Skip to content

feat: Add auxiliary resource table loading for split APK support#3

Draft
Aunali321 wants to merge 1 commit intoReVanced:masterfrom
Aunali321:feat/auxiliary-resource-loading
Draft

feat: Add auxiliary resource table loading for split APK support#3
Aunali321 wants to merge 1 commit intoReVanced:masterfrom
Aunali321:feat/auxiliary-resource-loading

Conversation

@Aunali321
Copy link
Copy Markdown

Summary

Add lookup-only auxiliary resource table loading so that resource IDs defined only in split APK resources.arsc files can be resolved during base APK decode.

Motivation

When decoding a split APK bundle, the base APK's binary XML may reference resource IDs (drawables, strings, etc.) whose definitions exist only in density/config split resources.arsc files. Since ResourcesDecoder builds a ResTable from only the base APK, these IDs are unresolvable during XML decode. ResReferenceValue.encodeAsResXml() emits @null for any ID where getReferent() fails, corrupting the decoded XML. When AAPT recompiles, @null is compiled as resource ID 0, causing runtime crashes (Resources$NotFoundException).

A full (non-split) APK does not have this problem because all resource entries are in a single resources.arsc.

Changes

  • ResTable: Add mAuxiliaryResSpecs and mAuxiliaryResSpecsByName maps for lookup-only split resource entries
  • ResTable.getResSpec(): Fall back to auxiliary specs when the main package lookup fails
  • ResTable.getValue(): Fall back to auxiliary specs for name-based lookups
  • ResTable.loadAuxiliaryPkg()/loadAuxiliaryPkgs(): Public API to load split resource tables
  • ResTable.listResSpecs(): Optionally include auxiliary specs (for public.xml generation)
  • ResourcesDecoder: Expose loadAuxiliaryPkgs() and setIncludeAuxiliaryPublicXml()
  • Refactor: Extract selectPkg(), add idempotency guard to loadMainPkg()

Auxiliary specs are never added to the main package, so the decoder does not treat split-owned resources as base-owned. This avoids the decoder trying to read split files from base.apk.

Test plan

  • compileJava passes
  • Verified with YouTube 20.31.42 split APK bundle (base + 35 config splits) — @null references resolved correctly, app installs and runs without crashes

Companion PRs: revanced-patcher, revanced-library, revanced-cli

@oSumAtrIX
Copy link
Copy Markdown
Member

Any reason this is not PRed upstream?

@oSumAtrIX
Copy link
Copy Markdown
Member

Also, whats the reason you cant just load the resource table from the res apks split APK file and then compile the resources with aapt using that loaded table?

@Aunali321
Copy link
Copy Markdown
Author

  1. No strong reason. I put it in the ReVanced fork first for faster iteration and testing alongside the companion patcher/library/CLI PRs. It could be PRed upstream to iBotPeaches/Apktool once it's validated.

  2. The problem is at decode time, not compile time. When apktool decodes the base APK's binary XML, it resolves resource references (like @drawable/foo) by looking up IDs in the ResTable. But the ResTable is built only from base.apk's resources.arsc. If a resource ID is defined only in a density split's resources.arsc (e.g., a drawable that only exists in split_config.hdpi.apk), the lookup fails and apktool writes @null into the decoded XML. Once @null is baked into the text XML, no amount of AAPT configuration at compile time can recover the original reference, the information is already lost. The auxiliary loading fixes this by making split resource IDs available during decode so the correct @drawable/foo reference is emitted instead of @null.

@oSumAtrIX
Copy link
Copy Markdown
Member

oSumAtrIX commented Mar 12, 2026

When apktool decodes the base APK's binary XML, it resolves resource references (like @drawable/foo) by looking up IDs in the ResTable. But the ResTable is built only from base.apk's resources.arsc.

But i recall Apktool has an API to instantiate a res table from a given apk file. Once instantiated, you can use this table to decode the xml files, this is all public api that doesnt need any PR changes. Have you tried this

@Aunali321
Copy link
Copy Markdown
Author

When apktool decodes the base APK's binary XML, it resolves resource references (like @drawable/foo) by looking up IDs in the ResTable. But the ResTable is built only from base.apk's resources.arsc.

But i recall Apktool has an API to instantiate a res table from a given apk file. Once instantiated, you can use this table to decode the xml files, this is all public api that doesnt need any PR changes. Have you tried this

Unfortunately no, apktool-lib's existing APIs don't support this. The hard blocker is ResTable.addPackage() which throws if a package with the same ID or name already exists:

if (mPackagesById.containsKey(id)) {
throw new AndrolibException("Multiple packages: id=" + id);
}

Split APKs share the same package ID (0x7f) and package name as the base APK, so you can't add a split's ResPackage to the base's ResTable.
Additionally, ResourcesDecoder creates its own private final ResTable with no setter, and getResSpec(ResID) has no fallback mechanism. It only looks in registered packages.
The PR adds a separate auxiliary lookup path that bypasses the package system entirely, so split resource IDs are resolvable during decode without conflicting with the base package.

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.

2 participants