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
Metadata
Release files for pyjadx 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pyjadx-0.1.1.tar.gz | 17.9 kB | Without provenance | Details for pyjadx-0.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pyjadx-0.1.1-py3-none-any.whl | Python 3 | none | any | Details for pyjadx-0.1.1-py3-none-any.whl |
Total release size: 28.4 kB
Release files / pyjadx-0.1.1.tar.gz
| Download URL | pyjadx-0.1.1.tar.gz |
|---|---|
| Size | 17.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e4ac12eb620805c4cb005b015aef2a33fd77f3024648169455d08d852ddaea83
|
|
BLAKE2b-256 checksum How to use checksums |
f6a23dc8fb4d2baba247a5e9934f3fc9306b387471fdce185ea4b2a6fa41dcdc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / pyjadx-0.1.1-py3-none-any.whl
| Download URL | pyjadx-0.1.1-py3-none-any.whl |
|---|---|
| Size | 10.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3fcf906e0455d7e059e37423101846badf24188a4f1de5b19c8ea773257a647f
|
|
BLAKE2b-256 checksum How to use checksums |
4838e98c20d5c2bd964f2d4437bbf1dd148c30d49baf1c40dd75f97836b9e46b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for pyjadx 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.