Skip to content

feat: Add split APK support#408

Draft
Aunali321 wants to merge 1 commit intoReVanced:devfrom
Aunali321:feat/split-apk-support
Draft

feat: Add split APK support#408
Aunali321 wants to merge 1 commit intoReVanced:devfrom
Aunali321:feat/split-apk-support

Conversation

@Aunali321
Copy link

@Aunali321 Aunali321 commented Mar 12, 2026

Summary

Add support for patching apps distributed as split APKs (base.apk + config splits for ABI, density, language).

  • Introduce sealed class Apk (Single / Split) replacing raw File parameter
  • Merge dex classes from all splits into a unified class pool
  • Decode and compile resources per split
  • Backward-compatible patcher(File, ...) overload preserved
  • Update ABI dumps

Implementation details

Resource ID resolution: The base APK's resources.arsc does not contain entries for resources that reside in density/config splits. Without those entries, apktool decodes binary XML references as @null, corrupting the output. Solved by loading split resource tables as auxiliary packages in apktool-lib (see ReVanced/Apktool#3) before decoding the base. Split public.xml entries are also included in the base's generated public.xml so that patches resolving resources by name work correctly.

AAPT linking: The base resource table references drawables that physically reside in density splits. Without those files in the base res/ directory, AAPT fails to link. Solved by symlinking split res/ contents into the base decode directory (with copy fallback).

Package name sync: Android requires all split manifests to have the same package attribute as the base. Patches like GmsCore rename the base package, so syncSplitPackageNames() propagates the base package to all split manifests before compilation.

ABI split manifests: ABI splits have no resources.arsc but still need their manifest decoded (for package sync) and recompiled to binary XML. Handled by passing null for resPath to AAPT, which compiles only the manifest.

Other edge cases handled:

  • Config splits may contain no dex — catch EmptyMultiDexContainerException
  • New split(), splitDocument(), deleteSplit() public APIs for patches to access split resources

Test plan

  • compileKotlinJvm passes
  • jvmTest (43 tests) passes
  • checkLegacyAbi passes
  • End-to-end: full APK — 60/60 patches pass
  • End-to-end: split APK bundle (35 splits) — 60/60 patches pass
  • Device install via adb install-multiple — success
  • App launches and runs without crashes

Depends on: ReVanced/Apktool#3

Companion PRs:

@Aunali321 Aunali321 force-pushed the feat/split-apk-support branch from 89f8160 to 76637bd Compare March 12, 2026 05:20
@oSumAtrIX
Copy link
Member

oSumAtrIX commented Mar 12, 2026

Merge dex classes from all splits into a unified class pool
Decode and compile resources per split

I thought only base had classes.
Also I thought only the resources split has resources

Is that not the case?

@Aunali321
Copy link
Author

On dex in splits:
Feature module APKs can contain dex. From the Android docs, each module has its own dex/ directory, and feature APKs "contain code and resources for a feature of your app." Config splits (ABI, density, language) typically don't have dex. The code handles both cases by trying to read dex from each split and catching EmptyMultiDexContainerException for those that don't.

On resources in splits:
Multiple splits carry resources, not just one. The docs describe configuration APKs as including "native libraries and resources for a specific screen density, CPU architecture, or language." So density splits have drawables, language splits have strings, etc. For example, in YouTube's split APK bundle, 29 of 35 splits have their own resources.arsc. Only the 4 ABI splits (which contain just native .so libraries) have no resource table.

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