Skip to content

External toolchain

Morphe Builder is Python, but the actual patching, merging, and signing is done by four Java tools. morphe-builder tools resolves them to exact releases, downloads them into a user cache, hashes them, and records provenance. None of these binaries is committed to the repository.

Tools

ToolUpstreamDefault versionLicenseRole
Morphe Desktop CLIMorpheApp/morphe-desktoplatest stable releaseGPL-3.0Applies patches to merged stock APK
Morphe patchesMorpheApp/morphe-patcheslatest stable releaseGPL-3.0Patch bundle consumed by the CLI
APKEditorREAndroid/APKEditorV1.4.9Apache-2.0Merges verified splits into one APK
uber-apk-signerpatrickfav/uber-apk-signerv1.3.0Apache-2.0Signs merged stock and patched APKs
Google apksignerbundled inside uber-apk-signerbuild-tools 33.0.2Apache-2.0Verifies APK signatures and returns every certificate in a v3.1 signing lineage

The bundled apksigner JAR is extracted atomically into the same verified tool cache. No Android SDK installation or extra download is required.

The Morphe CLI and patch sources are configurable per app; see configuration.md. APKEditor and signer defaults change only through a reviewed source update, because a merge or signing change affects every app at once.

Java requirement

Java 21 or newer must be on PATH. The resolved java path, reported version, and executable SHA-256 are recorded in toolchain provenance, so a build can be traced to the exact runtime that produced it. A missing or too-old Java fails with exit code 4.

Version resolution

bash
morphe-builder tools
morphe-builder tools --morphe-version v1.12.0 --patches-version v1.37.0

latest resolves through the GitHub release API and records the resolved tag, so latest is never left ambiguous after the fact. Use explicit release tags when you need a build to be repeatable months later, since latest will have moved.

A release must expose exactly one expected non-signature asset. Ambiguous releases (several plausible assets) and malformed releases (none) both fail rather than guessing.

Authentication

GitHub metadata requests use GITHUB_TOKEN when it is set and stay anonymous otherwise, which mainly matters for API rate limits on busy CI runners.

The token is sent only to api.github.com. Asset downloads use public github.com release URLs and never receive it. Cached metadata and provenance never contain it.

Integrity

Every download is verified before it is trusted:

  • An upstream SHA-256 file is verified when the release publishes one.
  • Otherwise the GitHub-reported asset size is enforced and the SHA-256 is computed locally and recorded.
  • The pinned release asset URL is recorded alongside the hash.
  • A cached file is reused only while the file and its sidecar metadata still match.
  • Downloads are bounded by the reported asset size and retried at most three times.

JAR tools and the patch bundle are recorded by resolved release and SHA-256 before first use, so a later cache tamper is detected rather than silently patched into an APK.

Cache layout and concurrency

--cache defaults to %LOCALAPPDATA%/morphe-builder on Windows, $XDG_CACHE_HOME/morphe-builder when set, otherwise ~/.cache/morphe-builder.

Toolchain assets live under <cache>/tools, keyed by owner/repo@resolved-tag. Two apps using different patch sources therefore never collide, and switching a pin does not invalidate the other app's cache.

Writers serialize through exclusive lock files, and publication into the cache is atomic, so two concurrent builds cannot produce a half-written JAR. A crashed process can leave a stale lock behind; remove it only after confirming no Morphe Builder process is still using that cache.

morphe-builder clean never touches <cache>/tools. It removes only <cache>/work.

Provenance

tools writes toolchain-provenance.json and prints its path. It records, for every tool:

  • resolved release tag
  • pinned release asset URL
  • reported size and computed SHA-256
  • Java path, version, and executable SHA-256

Build provenance references these hashes, so a published APK can be traced back to the exact CLI, patch bundle, merger, and signer that produced it. See build.md.

Update policy

Changing a default pin is a reviewed source change, not a configuration tweak. Before updating one, review the upstream repository, release asset naming, license, release notes, and checksum policy. Third-party binaries stay external cache artifacts and must never be committed. License inventory: THIRD_PARTY.md.

Released under the MIT License.