Python bindings for JADX — decompile Android APK/DEX to Java source.
Project description
pyjadx
Python bindings for JADX via JPype. Decompile Android APK and DEX files to Java source from Python.
from pyjadx import Jadx
with Jadx("app.apk") as jadx:
for cls in jadx.classes:
print(cls.full_name)
print(cls.code)
Why pyjadx?
JADX is the leading open-source Android decompiler — it produces clean Java/Kotlin source from Dalvik bytecode, preserving class hierarchies, generics, exception handling, and annotations. pyjadx brings this into Python without subprocess overhead: JADX runs in-process via JPype.
Install
pip install pyjadx
Requirements: JDK 11+ (JADX JARs are downloaded automatically on first use).
Quick start
from pyjadx import Jadx
with Jadx("app.apk") as jadx:
# All top-level classes (inner classes via cls.inner_classes)
for cls in jadx.classes:
print(cls.full_name, len(cls.methods), "methods")
# Search by fully qualified name
main = jadx.search_class("com.example.MainActivity")
if main:
print(main.code)
# Method-level decompilation
for method in main.methods:
print(f"{method.name}: {method.code}")
# Cross-references
for method in main.methods:
print(f"{method.name} called by: {[c.name for c in method.callers]}")
# Package navigation
for pkg in jadx.packages:
print(pkg.name, len(pkg.classes), "classes")
Supported inputs
| Format | Example |
|---|---|
| APK | Jadx("app.apk") |
| DEX | Jadx("classes.dex") |
| Multi-DEX APK | Handled transparently — all classes merged |
API reference
Jadx(path, *, threads=None, mode="auto", code_cache=False)
Main entry point. Use as a context manager or call load()/close() manually.
| Parameter | Description |
|---|---|
path |
Path to APK or DEX file |
threads |
JADX thread pool size (None = CPU count) |
mode |
"auto", "restructure", "simple", or "fallback" |
code_cache |
False = in-memory cache (default), True = disk-backed |
Properties:
| Property | Type | Description |
|---|---|---|
classes |
list[JavaClass] |
Top-level classes across all DEX files |
packages |
list[JavaPackage] |
Package-level navigation |
class_count |
int |
Number of top-level classes |
java |
JObject |
Escape hatch to underlying jadx.api.JadxDecompiler |
Methods:
| Method | Description |
|---|---|
load() |
Load and resolve classes (called by __enter__) |
close() |
Release resources (called by __exit__) |
decompile_all() |
Eagerly decompile all classes |
search_class(name) |
Find class by fully qualified name |
JavaClass
| Property | Type | Description |
|---|---|---|
name |
str |
Short name ("MainActivity") |
full_name |
str |
Fully qualified ("com.example.MainActivity") |
package |
str |
Package name |
code |
str |
Decompiled Java source (lazy, cached) |
smali |
str |
Smali disassembly (lazy, cached) |
methods |
list[JavaMethod] |
Methods in this class |
fields |
list[JavaField] |
Fields in this class |
inner_classes |
list[JavaClass] |
Inner/anonymous classes |
declaring_class |
JavaClass | None |
Parent class (if inner) |
top_class |
JavaClass |
Outermost enclosing class |
dependencies |
list[JavaClass] |
Classes this class depends on |
is_inner |
bool |
Whether this is an inner class |
java |
JObject |
Escape hatch to jadx.api.JavaClass |
JavaMethod
| Property | Type | Description |
|---|---|---|
name |
str |
Method name |
full_name |
str |
Fully qualified with class |
code |
str |
Decompiled source (lazy, cached) |
callers |
list[JavaMethod] |
Methods that call this one (lazy, cached) |
callees |
list[JavaMethod] |
Methods this one calls (lazy, cached) |
override_related |
list[JavaMethod] |
Bidirectional override chain |
declaring_class |
JavaClass |
Class this method belongs to |
java |
JObject |
Escape hatch to jadx.api.JavaMethod |
JavaField
| Property | Type | Description |
|---|---|---|
name |
str |
Field name |
full_name |
str |
Fully qualified with class |
type |
str |
Field type as string |
callers |
list[JavaMethod] |
Methods referencing this field (lazy, cached) |
declaring_class |
JavaClass |
Class this field belongs to |
java |
JObject |
Escape hatch to jadx.api.JavaField |
JavaPackage
| Property | Type | Description |
|---|---|---|
name |
str |
Full package name |
classes |
list[JavaClass] |
Classes in this package |
sub_packages |
list[JavaPackage] |
Sub-packages |
java |
JObject |
Escape hatch to jadx.api.JavaPackage |
Escape hatch
Every wrapper exposes its underlying JADX Java object via .java. This lets you call any JADX API we haven't wrapped yet:
with Jadx("app.apk") as jadx:
cls = jadx.search_class("com.example.Foo")
# Call JADX Java API directly
code_info = cls.java.getCodeInfo()
JVM coexistence
pyjadx coexists with other JPype consumers (e.g., PyGhidra) in the same process. If a JVM is already running, pyjadx.start() adds JADX JARs to the existing classpath. If not, it starts one.
import pyghidra
pyghidra.start() # starts JVM for Ghidra
import pyjadx
pyjadx.start() # adds JADX JARs to existing JVM — no conflict
Configuration
Custom JADX installation:
# Via environment variable
# export JADX_HOME=/opt/jadx
# Or at runtime
import pyjadx
pyjadx.start(jadx_home="/opt/jadx")
JAR caching: JADX JARs are auto-downloaded from Maven Central on first use and cached at ~/.pyjadx/jars/<version>/.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyjadx-0.1.0.tar.gz.
File metadata
- Download URL: pyjadx-0.1.0.tar.gz
- Upload date:
- Size: 17.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45e99a22de72f7b1ebd18afcbd09e60bf6b144fd2d3193e72ab0c41741f3eeba
|
|
| MD5 |
97914c43f9debf1a2354b2b1dae7468c
|
|
| BLAKE2b-256 |
cf0b43a9d5c0f4b5f8df8a77f665b2554a75fc2ceb92e4db2a370c41dc345278
|
File details
Details for the file pyjadx-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pyjadx-0.1.0-py3-none-any.whl
- Upload date:
- Size: 10.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
01203e6d5b3358915515c8ebe43359eab01e22389abee568656a460256e57941
|
|
| MD5 |
39f953361af3ff245a2ed79787b79258
|
|
| BLAKE2b-256 |
b1b893a957fcd44f401593ff7d504ccdecf11c1df5e87f4b46c45846c4c79c16
|