Repository navigation
Support apktool 2.12+/3.x builds while keeping aapt2 on older apktool - #24
Merged
Merged
Conversation
`apkutil build` / `network` / `debuggable` / `all` failed with the current apktool (3.0.3) because `--use-aapt2` was removed in apktool 2.12.0. Detect the apktool version at build time and pass the flag only to versions that still accept it (< 2.12.0), so apktool <= 2.8 (aapt1 by default) keeps building with aapt2. Also decode subprocess output as UTF-8 with replacement instead of ASCII, which raised UnicodeDecodeError on apktool's usage text and hid the real error, and recognize the `I: Built apk into: <path>` success message used since apktool 2.7.0 so stderr warnings on a successful build are not treated as failures. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
apktool 2.12.x does not accept `--version` and prints its banner
("Apktool 2.12.0 - a tool for ...", "with smali 3.0.9 ...") instead of a
bare version. Anchor the version regex to the start of a line with an
optional "Apktool " prefix so the bundled smali version is never mistaken
for apktool's.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
apkutil build/network/debuggable/allfail on the current apktool (Homebrew 3.0.3) with'ascii' codec can't decode byte 0xc5 in position 128. This PR fixes the three underlying issues inapkutil/util.pywithout changing any other subcommand, the~/apkutil.jsonschema, or the supported Python versions (verified on 3.8.5 and 3.14.7).Bug A:
--use-aapt2is rejected by apktool >= 2.12.0apktool removed
--use-aapt2in 2.12.0 (aapt2 has been its default since 2.9.0). Passing it to 2.12+/3.x fails withUnrecognized option: --use-aapt2and nothing is built.Chosen approach: option 1 (runtime detection).
build()now runsapktool --version, parses the version from the start of a line with an optionalApktool/vprefix (tolerating suffixes like2.12.0-dirty/2.11.1-SNAPSHOT), and appends--use-aapt2only when the version is< 2.12.0.Note on 2.12.x: it is the one series that rejects
apktool --version(Unrecognized command) and prints its banner (Apktool 2.12.0 - a tool for .../with smali 3.0.9 ...) instead. The parser is anchored to line start so it reads2.12.0from the banner and never the bundled smali version.Why option 1 over option 2 (drop the flag + document apktool >= 2.9.0):
apktool --versioncall per build. If the version can't be parsed the flag is omitted, which is the safe choice for every apktool >= 2.9.apktoolmissing still hits the existingFileNotFoundError-> "apktool not found." path.Bug B:
_run_subprocess()decoded as ASCIIapktool's usage text contains
Wiśniewski, so the real error was swallowed byUnicodeDecodeError. Output is now decoded as UTF-8 witherrors='replace', which also covers non-ASCII APK paths and localized aapt2/apksigner messages.Bug C: success detection matched only
I: Built apk...apktool >= 2.7.0 prints
I: Built apk into: <path>, sois_builtwas never true and any stderr noise on a successful build raised. The check is now"I: Built apk" in outs, matching both forms.Version
Bumped
setup.pyto0.1.11:0.1.10is already onmain(installed viagit+ssh), and this changes user-visible build behavior, so a new version helpspipx/uv tool upgradeusers see the update.Tests
tests/test_cli.py(same mock-driven style, no apktool/SDK/keystore/APK needed) now also locks in:--use-aapt2is passed for apktool 2.4.1 / 2.8.1 / 2.9.3 / 2.11.0 / 2.11.1-SNAPSHOT and not for 2.12.0 / 2.12.0-dirty / 2.12.1 / 3.0.3 / 3.1.0-SNAPSHOT, the 2.12.x banner output, or an unparseable version_parse_apktool_version()edge cases, including the 2.12.x / 2.8.x banner formats and not matchingwith smali 3.0.9 ...build()returns True for bothI: Built apk...andI: Built apk into: /path/x.apk, including when apktool also writes a warning to stderr; a real failure still raises with the stderr text_run_subprocess()returns str for UTF-8 and for invalid byte sequences instead of raisingAgainst the unpatched
util.pythe new tests fail (7 failures, 10 errors).Manual verification
Sample APK: a minimal manifest +
resources.arscAPK built withaapt2 link;ANDROID_HOME=~/Library/Android/sdk, build-tools 36.0.0, OpenJDK 25.0.4. Non-Homebrew versions were run viajava -jar apktool_<ver>.jarwrappers onPATHfrom GitHub Releases.util.build()on a directory decoded by apktool 3.0.3:apktool b <dir> -o <apk> --use-aapt2I: Built apk into:OKapktool b <dir> -o <apk> --use-aapt2apktool b <dir> -o <apk> --use-aapt2--use-aapt2, no--version)apktool b <dir> -o <apk>apktool b <dir> -o <apk>Full CLI flows:
decodebuildnetworkdebuggableallAll outputs pass
apksigner verify(v1/v2/v3). (2.8.1 could notdecodethe aapt2-36-built sample itself and needed its own framework dir; both are apktool-version issues in the lab setup, not apkutil.)Not addressed here (pre-existing, out of scope)
On JDK 25,
apksignerprintsWARNING: A restricted method in java.lang.System has been called ...to stderr. The APK is signed correctly (Signed, verify passes), but the existingsign()treats any stderr as failure, so the run ends withFailedinstead ofOutput: .... This reproduces identically onmainand is unrelated to apktool 3. Possible follow-up: pass-J-enable-native-access=ALL-UNNAMEDto apksigner (verified to silence the warning with build-tools 36.0.0), or ignoreWARNING:lines insign().🤖 Generated with Claude Code