command reference

xenolith-apk-editor

The terminal form of APK Editor. Mac, Windows and Linux, no Java. Smali stays packed until you ask for it. A build always starts from the original APK.

Download

One static binary per system — no installer, no Java, nothing else to set up. The Android framework table ships inside the archive and installs itself on the first run.

macOS

  1. tar -xzf xenolith-apk-editor-*.tar.gz

    Unpack the archive.

  2. cd xenolith-apk-editor
    ./xenolith-apk-editor d app.apk -o app

    Decode your APK. The framework table beside the binary installs itself on the first run.

Linux

  1. tar -xzf xenolith-apk-editor-*.tar.gz

    Unpack the archive.

  2. cd xenolith-apk-editor
    ./xenolith-apk-editor d app.apk -o app

    Decode your APK. The framework table beside the binary installs itself on the first run.

Windows

  1. Expand-Archive xenolith-apk-editor-*.zip

    Unpack the archive.

  2. cd xenolith-apk-editor
    .\xenolith-apk-editor.exe d app.apk -o app

    Decode your APK. The framework table beside the binary installs itself on the first run.

The usual path

Four commands, from a file to a signed APK.

  1. xenolith-apk-editor d app.apk -o app --src

    Unpack the APK into a directory. --src writes smali. Without it the dex files are copied through.

  2. xenolith-apk-editor b app --base app.apk -o unsigned.apk

    Pack the directory back into an APK. --base is the original file: everything you did not edit comes from there.

  3. xenolith-apk-editor keygen --key key.pem --cert cert.pem

    A new ECDSA P-256 key and certificate. The key is the app’s identity. Keep a copy.

  4. xenolith-apk-editor sign unsigned.apk -o signed.apk --key key.pem --cert cert.pem

    Sign the package. The default is signature schemes v2 and v3.

Commands

Decode

d, decode

xenolith-apk-editor d <app.apk> [-o dir]

One APK becomes a directory. The manifest is text, resources are files. Dex stays dex until --src or --java. If the directory already exists, the command stops unless you pass -f. Exit 0 is success, 1 is a bad invocation, 3 is a failure while running.

  • -o, --outputOutput directory. The default is the apk name with .apk removed.
  • -f, --forceDelete an existing output directory and decode again.
  • --srcDisassemble classes*.dex into smali/. This is off unless you ask.
  • --javaAlso write java/ so you can read the app. That tree is a view. The source you assemble is smali. You can pass --src and --java together.
  • --only-manifestDecode the manifest and leave the rest untouched.
  • --no-assetsSkip assets/. lib/ is still copied.
  • --frame-pathDirectory of installed framework tables. The same flag is accepted by build.
  • --res-resolve-modedefault, greedy or lazy. lazy does not invent dummy attributes for references it cannot resolve.

Build

b, build

xenolith-apk-editor b <dir> --base <app.apk> -o <out.apk>

One decoded directory in, one APK out. --base and -o are both required. Smali in the tree is assembled into dex. A .9.png you replaced is refused.

  • --baseThe original APK. The build copies it through and applies your edits.
  • -o, --outputWhere to write the APK. - sends the bytes to stdout.
  • --frame-pathFramework tables, when the project needs them.
  • --res-resolve-modeThe same default, greedy or lazy choice as decode.
  • --edit-fileRepeatable. A file in the tree whose bytes are written into the APK as they stand. res/, original/, the manifest and apktool.yml are refused. Smali does not need this flag.

Sign

keygen

xenolith-apk-editor keygen --key <key.pem> --cert <cert.pem>

Writes an unencrypted PKCS#8 key and a self-signed X.509 certificate. Both paths are required. The backup line is not a slogan: a different key will not update an app signed with this one.

  • --keyWhere to write the private key.
  • --certWhere to write the certificate.
  • --cnName on the certificate. The default is xenolith-dev-key.

sign

xenolith-apk-editor sign <unsigned.apk> -o <signed.apk> --key <key.pem> --cert <cert.pem>

Signs one APK. -o, --key and --cert are required. The key is PKCS#8, the certificate is X.509, PEM or DER. v3 uses the minSdk window from the manifest. There is no key rotation.

  • -o, --outputSigned APK. - sends the bytes to stdout.
  • --keyPrivate key, PEM or DER.
  • --certCertificate, PEM or DER.
  • --no-v3Write the v2 block only.

Edit in place

patch

xenolith-apk-editor patch <app.apk> -o <out.apk> [edits]

Changes an APK and writes a new one. You name what changes. At least one edit is required. The launcher icon is resampled for each density.

  • -o, --outputOutput APK. - sends the bytes to stdout.
  • -l, --labelApplication label.
  • -p, --packagePackage name.
  • -n, --version-nameversionName.
  • --version-codeversionCode, a non-negative integer that fits in 32 bits.
  • --debuggabletrue or false. Sets android:debuggable on the application.
  • --add-permissionAdd a uses-permission. Repeat the flag. Adding one that is already there changes nothing.
  • --remove-permissionRemove a uses-permission. Missing names are left alone.
  • --add-metaname=value. Adds an application meta-data entry. The same name is replaced.
  • --remove-metaRemove an application meta-data entry by name.
  • --iconReplace the launcher icon from an image file.
  • --soReplace lib/arm64-v8a/libxenolith.so. The entry stays stored and 16 KB aligned. This is that slot, not an arbitrary library.

patch-manifest

xenolith-apk-editor patch-manifest <AndroidManifest.xml> -o <out.xml>

The same manifest edits, on a binary AndroidManifest.xml rather than a whole APK. The icon and the native library are not part of this command.

  • -o, --outputOutput manifest.
  • -l, --labelApplication label.
  • -p, --packagePackage name.
  • -n, --version-nameversionName.
  • --version-codeversionCode.
  • --add-permissionAdd a uses-permission. Repeatable.
  • --remove-permissionRemove a uses-permission.
  • --add-metaname=value for an application meta-data entry.
  • --remove-metaRemove an application meta-data entry by name.

Look

list-res

xenolith-apk-editor list-res <app.apk>

Prints the resource table. Filters are exact names, not substrings.

  • --typeOnly this resource type.
  • --nameOnly this entry name.
  • --configOnly this configuration qualifier.
  • --jsonJSON instead of the text listing.

signatures

xenolith-apk-editor signatures <app.apk>

Prints which of v1, v2, v3 and v3.1 are present, and the certificate facts the tool can read.

  • --jsonJSON instead of the text listing.

Images and dex

replace-entry

xenolith-apk-editor replace-entry <app.apk> <zip-path> --from <image> -o <out.apk>

Swaps one image inside the APK. The zip path stays the same, because resources.arsc points at it. A nine-patch .9.png is refused. --to accepts png, webp or jpeg.

  • --fromThe image file to put in.
  • -o, --outputOutput APK. - sends the bytes to stdout.
  • --topng, webp or jpeg. The default is the extension already on the entry.
  • --webp-lossyLossy WebP. The default is lossless.

assemble

xenolith-apk-editor assemble <smali-dir> -o <out.dex>

Reads every .smali file under the directory and writes one dex.

  • -o, --outputOutput dex. Required.

optimize

xenolith-apk-editor optimize <app.apk> -o <out.apk>

Recompresses entries that were stored. resources.arsc and memory-mapped .so files stay stored.

  • -o, --outputOutput APK. Required. A dash is not accepted.

Framework

if, install-framework

xenolith-apk-editor if <framework.apk>

Installs a framework resource table so later decodes can resolve its references. The default tag is 1.

  • -t, --frame-tagTag for this framework. The default is 1.

list-frameworks

xenolith-apk-editor list-frameworks

Prints the frameworks that are installed: tag, package name, number of types.

clean-frameworks

xenolith-apk-editor clean-frameworks

Removes installed framework tables.

  • --frame-pathFramework directory to clear. Without it, the usual location is cleared.