apkpatch is a small command-line workflow wrapper for APK security review and
smali patch testing.
It hides the repetitive details around:
- decoding APKs with
apktool - initializing a clean git baseline for decoded smali
- rebuilding with
apktool b - aligning with
zipalign - signing with
apksigner - generating a non-interactive debug keystore
- verifying signatures
- installing with
adb install -r
The tool does not modify smali for you. It manages the workflow around your manual smali/resource edits.
From the repository root:
python3 -m pip install -e .Then run:
apkpatch doctorYou can also run without installing:
PYTHONPATH=src python3 -m apkpatch doctorapkpatch expects these tools to exist:
apktooljavakeytoolzipalignapksigneradbfor install onlygitfor baseline/diff only
zipalign and apksigner are searched in this order:
$PATH--build-tools-dir$ANDROID_HOME/build-tools/*$ANDROID_SDK_ROOT/build-tools/*~/Library/Android/sdk/build-tools/*on macOS
Decode an APK:
apkpatch decode app.apk -o app_workdirBy default this also creates a git repository inside app_workdir and commits
the decoded APK as:
baseline: decoded apk
Make your smali/resource changes manually, then inspect them:
cd app_workdir
apkpatch diffBuild, align, sign, and verify:
apkpatch build \
--generate-ks ~/.apkpatch/debug.keystore \
--out dist/app-patched-signed.apkInstall:
apkpatch installOr build and install in one step:
apkpatch build --install
apkpatch build --install -s DEVICE_SERIALCheck tool discovery:
apkpatch doctorDecode an APK with apktool d:
apkpatch decode input.apk -o workdirUseful options:
apkpatch decode input.apk -o workdir --force
apkpatch decode input.apk -o workdir --no-gitBuild a decoded workdir:
apkpatch buildbuild defaults to the current directory. You can still pass a workdir
explicitly:
apkpatch build workdirDefault output uses the decoded package name when available:
workdir/dist/com.example.app-signed.apk
Unsigned and aligned intermediate APKs are removed after a successful build by default.
If the package name cannot be inferred, apkpatch falls back to the workdir
name.
Useful options:
apkpatch build --clean
apkpatch build --name review-false
apkpatch build --suffix review-false
apkpatch build --keep-intermediates
apkpatch build --out /tmp/review-false-signed.apk
apkpatch build --installBuild again using metadata saved from the previous build:
apkpatch rebuildSign an existing APK:
apkpatch sign unsigned.apk -o signed.apk --ks ~/.apkpatch/debug.keystoreRun only zipalign:
apkpatch align unsigned.apk -o aligned.apkInstall an APK:
apkpatch install signed.apk
apkpatch install signed.apk -s DEVICE_SERIALIf no APK is provided, install defaults to last_signed_apk in the current
workdir's .apkpatch.json:
apkpatch install
apkpatch install -s DEVICE_SERIALIf --workdir is provided, install failures can include package-name hints:
apkpatch install signed.apk --workdir app_workdirShow changed files and smali/resource diffs:
apkpatch diff
apkpatch diff --statInitialize git tracking for an existing decoded workdir:
apkpatch git-initIf no keystore is provided, apkpatch build uses:
~/.apkpatch/debug.keystore
If it does not exist, it is generated non-interactively with:
alias: apkpatchdebug
password: android
You can override:
apkpatch build \
--ks ./debug-review.keystore \
--alias debugreview \
--ks-pass android \
--key-pass androidExisting keystores are not overwritten unless:
--force-generate-ksBy default apkpatch disables APK Signature Scheme v4, so apksigner does not
create a .idsig sidecar file.
Enable it explicitly:
apkpatch build --v4apkpatch is intended for local APK security review, reverse engineering, and
patch validation on apps you are authorized to inspect.
It does not bypass platform security checks by itself. It only wraps common APK tooling and makes the workflow reproducible.