Zygote
APKs & installationbeginner

Anatomy of an APK

An APK is a ZIP file with a strict internal contract: binary manifest, compiled resources, DEX code, native libraries, and a signature that covers the whole archive. Learn the parts and install failures stop being mysterious.

11 minAPI 1–37 · 17interactivequizverified 2026-10-27

Strip away the tooling and an APK is a ZIP archive. What makes it an APK is the contract about what is inside: a compiled manifest, a compiled resource table, DEX files, native libraries in ABI-named folders, and a signature that covers the archive rather than individual files.

TL;DR#

  • An APK is a ZIP with a fixed set of parts: AndroidManifest.xml, classes*.dex, resources.arsc, res/, lib/\<abi\>/, assets/, META-INF/, and the signing block.
  • The manifest and resources are binary XML and a binary table, not text. The platform parses them without a general XML parser.
  • classes*.dex exist because a single DEX can reference at most 65,536 methods; beyond that you need multidex or, better, code shrinking.
  • Native libraries are stored uncompressed and page-aligned (zipalign) so they can be mapped rather than copied.
  • The APK Signing Block sits between the last entry and the central directory; v2 and later sign the archive, which is why tampering is detectable without unzipping.

Mental model#

Think of a shipping container.

The container itself is standard (ZIP). Inside, every item has a declared place: the manifest is the customs declaration, the DEX files are the machinery, the resources are the consumables, the native libraries are the specialist tools, and the signature is the seal on the door.

A container with a broken seal is not inspected item by item at the destination — it is refused. That is roughly what PackageManager does.

Where the analogy breaks#

A container is opened and its contents used. An APK is often memory-mapped rather than extracted: the platform reads the central directory, maps the pieces it needs, and never unpacks the whole thing. That is why alignment and compression choices matter for performance.

The big picture#

Loading diagram…
Text description of this diagram

An interactive treemap of a real APK measured from the Zygote template app in this repository. The largest area is DEX code — classes.dex and its siblings — which in a debug build is over 28 MB across five files. The resource table resources.arsc follows, then res/ with compiled layouts and drawables, lib/ with native libraries, META-INF/ with signature metadata, and AndroidManifest.xml, which is tiny but decisive. With R8 enabled for release the same app is roughly seventeen times smaller: one DEX file of about 1.1 MB instead of five totalling 28 MB. Clicking a group explains what it holds and gives both the debug and release sizes.

Those proportions are measured, not invented. Debug APK 28.9 MB uncompressed; the same app with R8 enabled for release is 1.7 MB — 16.8× smaller. The debug DEX is 28.2 MB across 5 files; release shrinks it to 1.1 MB in 1 file. Sizes are uncompressed sizes of the entries inside each APK.

Two cautions. The template is a Compose hello-world, so its shape is the shape of framework code, not of a real product: a game can be 90% assets, a small utility can be almost entirely dex, and an app shipping four ABIs can double its size in native libraries alone. And the figures are uncompressed entry sizes inside the APK, which differ from the download size because the archive itself is deflated.

Deep dive#

AndroidManifest.xml#

The manifest is the app's declaration to the platform: package name, components, permissions, required hardware features, the minimum and target SDK, and metadata. It is compiled to binary XML, a compact format that the platform can parse without a general-purpose XML parser.

Two consequences follow. First, you cannot meaningfully edit it after building — it is compiled. Second, its size is tiny compared with everything else, but it is the file that decides whether the app can install at all.1

classes.dex and the 64K limit#

DEX is Android's bytecode format. A single DEX file can reference at most 65,536 methods, because method references are indexed with 16 bits. An app that exceeds that must either shrink its code or split it into additional DEX files.2

On modern Android, multidex is largely handled by the platform: a debug build can use legacy multidex, and release builds with a minSdk at or above 21 do not need the support library at all.

resources.arsc and res/#

This pair is the most misunderstood part of the APK.

  • res/ holds the actual resource files, organised into configuration-specific folders: res/values-fr/, res/drawable-xxhdpi/, res/layout-land/.
  • resources.arsc is the table that maps every resource ID to its value for each configuration.

The split exists so that a lookup at runtime is a table read, not a directory search. When getString(R.string.title) runs, it has an integer ID; the table tells it which values-* entry to use for the current configuration.4

The next page takes this apart properly, including why IDs start with 0x7f.

lib/<abi>/#

Native libraries live under a folder named after the ABI: arm64-v8a, armeabi-v7a, x86, x86_64. An app that ships all four can be several times larger than one that ships only the ABI a device needs — which is exactly the problem App Bundles solve.

Native libraries are stored uncompressed and aligned to a page boundary. The reason is mmap: the loader can map the library directly from the APK instead of extracting it to disk, which saves space and install time. That is what zipalign guarantees, and why an aligned APK is a requirement for modern installs.5

assets/#

Files shipped verbatim. Unlike res/, they are not compiled, not given resource IDs and not configuration-aware. You read them with AssetManager by path. Game data, ML models and fonts typically live here.

The distinction from res/raw/ is subtle but real: res/raw/ files get resource IDs and are configuration-aware; assets/ files do not.

META-INF/ and the signing block#

This is where the APK's integrity story lives, and it has two eras.

The v1 scheme (JAR signing) puts a digest of every file into META-INF/MANIFEST.MF, signs that manifest, and stores the signature. It verifies per file.

The v2 scheme introduced the APK Signing Block, a region between the last ZIP entry and the central directory, holding digests of the whole archive. v3 adds key rotation, and v4 adds a separate signature file for incremental installation.678

The reason for moving beyond v1 is that per-file verification is slow and has known weaknesses: an attacker can add files that v1 does not cover, or exploit ambiguities in the ZIP structure. Signing the whole archive closes those gaps.

What makes an APK large, and what to do#

The four usual culprits, in order:

  1. Native libraries for several ABIs. Ship one, or use an App Bundle.
  2. Density-specific images. Ship vector drawables, or use an App Bundle's density splits.
  3. DEX from unused dependencies. Enable R8 shrinking.
  4. Assets. Compress them, download them, or move them to an asset pack.

Android Studio's APK Analyzer shows the same breakdown as the treemap above, with real numbers.

How it evolved#

Storage changes10 releases
APIVersionWhat changed
31.5 Cupcake
  • android.widget video and media improvements
123.1 Honeycomb
  • ParcelFileDescriptor improvements
154.0.3 Ice Cream Sandwich
  • New calendar and media provider APIs
194.4 KitKat
  • Storage Access Framework
247.0 Nougat
  • FileProvider and StrictMode for file URLs
2910
  • Scoped storage with requestLegacyExternalStorage opt-out
3011
  • Scoped storage enforced for targeting apps
3313 Tiramisu
  • READ_MEDIA_IMAGES/VIDEO/AUDIO replace storage reads
3414 Upside Down Cake
  • READ_MEDIA_VISUAL_USER_SELECTED
3717 Cinnamon Bun
  • ACTION_PICK_CONTACTS gives session-scoped contact field access
2008–2016JAR signingv1: per-file digests in META-INF.API 1
2016 →Whole-archive signingv2 signs the archive; verification gets faster and stronger.API 24
2018 →Key rotationv3 allows changing the signing key without breaking updates.API 28
2021 →Split deliveryPlay requires App Bundles for new apps, so APKs are per-device.API 30

Under the hood#

Curiosity corner#

  • An APK is a valid ZIP, but a ZIP is not a valid APK. You can unzip one; you cannot install a plain ZIP.
  • unzip -l does not show the signing block. It is not a file entry, which is why people are surprised to find it with apksigner verify --print-certs.
  • A 1-byte change invalidates the signature. The whole-archive scheme means there is no such thing as a harmless post-signing edit.

Try it#

Take an APK apart

unzip -l app-release.apk | head -30 apksigner verify --print-certs app-release.apk aapt2 dump badging app-release.apk

Example output
AndroidManifest.xml
classes.dex
classes2.dex
resources.arsc
res/drawable-xxhdpi/ic_launcher.png
lib/arm64-v8a/libexample.so
assets/model.tflite
META-INF/CERT.RSA

unzip -l shows the entries; apksigner verify shows the signature scheme and the signer; aapt2 dump badging shows what the platform will actually read from the manifest.

Build it#

Build a tiny app, unzip it, and match each folder to the diagram above. Then enable R8 and compare the DEX sizes — the difference is usually larger than people expect.

Check yourself#

Check yourself

1 / 12

An APK is fundamentally which kind of file?

0 answered · 0 correct

Sources#

Sources

Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.

  1. docsApp manifest overviewdeveloper.android.comaccessed 2026-10-27↩
  2. docsEnable multidexdeveloper.android.comaccessed 2026-10-27↩
  3. docsShrink, obfuscate, and optimize your appdeveloper.android.comaccessed 2026-10-27↩
  4. docsApp resources overviewdeveloper.android.comaccessed 2026-10-27↩
  5. docsapksignerdeveloper.android.comaccessed 2026-10-27↩
  6. docsAPK Signature Scheme v2source.android.comaccessed 2026-10-27↩
  7. docsAPK Signature Scheme v3source.android.comaccessed 2026-10-27↩
  8. docsAPK Signature Scheme v4source.android.comaccessed 2026-10-27↩
  9. docsAPK signature schemesource.android.comaccessed 2026-10-27↩
  10. docsAbout Android App Bundlesdeveloper.android.comaccessed 2026-10-27↩