Skip to content

Judge tool success by exit code and warn on outdated apktool - #25

Merged
tkmru merged 1 commit into
mainfrom
fix/returncode-and-version-check
Sep 20, 2026
Merged

tkmru merged 1 commit into
mainfrom
fix/returncode-and-version-check

Conversation

@tkmru

@tkmru tkmru commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #24. The root cause shared by the apktool 3 breakage, the earlier adb stdout/stderr fix (#21) and the sign() failure on JDK 25 is that apkutil never looked at the exit code of the tools it wraps: success was "stderr is empty" (adb/apksigner/zipalign/aapt2) or "stdout contains a magic string" (apktool build). Both are unreliable, since adb prints progress to stderr, apktool prints W: warnings, and apksigner on JDK 25 prints native-access WARNING: lines, all on successful runs.

1. Exit code decides

  • _run_subprocess() now returns (stdout, stderr, returncode).
  • Every caller (decode, build, align, sign, get_packagename, get_screenshot, _get_package_name, _get_apk_paths, _pull_apk_files) raises/returns False only when returncode != 0. The I: Built apk string match from Support apktool 2.12+/3.x builds while keeping aapt2 on older apktool #24 is gone.
  • stderr on a successful run is printed in yellow instead of being treated as an error.
  • Error message: stderr, else stdout (apktool's usage text goes to stdout), else <tool> exited with code N (e.g. pm path on an unknown package prints nothing).
  • _pull_apk_files and the adb pull in get_screenshot previously ignored failures entirely; they now raise.
  • Not touched: the decode -f switch workaround, the ~/apkutil.json schema, subcommand behavior otherwise.

Net effect for users: apkutil build/all/... on JDK 25 now finishes with Output: ... instead of Failed after a correctly signed APK.

2. Outdated apktool warning

util.warn_if_apktool_outdated() runs once at the start of decode, build, debuggable, network and all. It prints a yellow warning (never fails) when apktool is older than APKTOOL_MIN_VERSION = (2, 9, 0), or when the version can't be parsed. Missing apktool stays silent here because decode()/build() already report it. README lists 2.9.0 as the recommended minimum.

Why 2.9.0: it is the first release where aapt2 is the default, and older releases can't even decode APKs built by recent aapt2 (2.8.1 failed on the test fixture). The --use-aapt2 runtime detection from #24 still keeps < 2.12 on aapt2, so older versions keep working; they just get told.

Version

0.1.11 -> 0.1.12 (user-visible change in build/sign outcome).

Tests

31 tests (was 19), Python 3.8.5 and 3.14.7, no apktool/SDK/keystore needed. New coverage: exit-code-driven success/failure for build/decode/align/sign/get_packagename, message fallback to stdout and to the exit code, sign() succeeding with JVM warnings on stderr, and the version warning (recent = silent, 2.8.1 = warns, unparseable = warns, missing = silent).

Manual verification (apktool 3.0.3 unless noted, build-tools 36.0.0, OpenJDK 25, emulator attached)

  • build / all: Signed + yellow JDK warnings + Output: ... (was Failed)
  • decode onto an existing dir: Destination directory (sample) already exists. ... + Failed (error path intact)
  • build with apktool 2.8.1: prints apktool 2.8.1 is outdated. Please upgrade to apktool 2.9.0 or later., then builds with --use-aapt2 and its W: Could not find sources shows as a warning instead of failing
  • build with apktool 2.9.3: no warning
  • apktool missing: apktool not found. unchanged
  • info on a valid / nonexistent APK: package name / aapt2 error + Failed
  • screenshot: pulled and removed from the device, Output: screenshot-....png
  • pull internals against com.android.settings: list, path and pull succeed; unknown package now raises adb exited with code 1 instead of an empty message

🤖 Generated with Claude Code

Every external tool (apktool, adb, zipalign, apksigner, aapt2) was judged
successful only when its stderr was empty, or by matching a stdout string.
adb prints progress to stderr, apktool prints warnings, and apksigner on
JDK 25 prints native-access WARNINGs, all on successful runs, so these
checks produced false failures (e.g. `build` ending in "Failed" after a
correctly signed APK). `_run_subprocess` now also returns the exit code
and every caller decides by it; stderr on a successful run is shown as a
yellow warning, and an error message falls back to stdout or the exit
code when stderr is empty.

`decode`, `build`, `debuggable`, `network` and `all` now print a warning
when apktool is older than 2.9.0 (APKTOOL_MIN_VERSION) or its version
can't be determined. The build itself is unaffected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@tkmru
tkmru merged commit a4263ad into main Sep 20, 2026
3 checks passed
@tkmru
tkmru deleted the fix/returncode-and-version-check branch September 20, 2026 21:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant