Skip to content

Add asset-based match index support for KSP library modules#391

Open
rossbacher wants to merge 7 commits into
masterfrom
rossbacher-useBinaryMatchIndexWithKsp
Open

Add asset-based match index support for KSP library modules#391
rossbacher wants to merge 7 commits into
masterfrom
rossbacher-useBinaryMatchIndexWithKsp

Conversation

@rossbacher
Copy link
Copy Markdown
Collaborator

@rossbacher rossbacher commented Jan 28, 2026

This change adds an optional asset-based approach for storing the match index binary data when using KSP with the manifest-generation plugin. Instead of encoding the binary data as strings in the generated registry class, the match index is written as an Android asset file and loaded at runtime via AssetManager.

Key changes:

  • Add shared constants in ManifestGeneration.kt for asset paths and KSP option
  • Generate AssetManager-based registry constructor when useAssetBasedMatchIndex=true
  • Add MergeDeepLinkAssetsTask and RelocateDeepLinkAssetsTask for Gradle plugin
  • Update ManifestGenerationPlugin to handle asset file relocation and merging
  • Add processor tests for asset-based and legacy string-based code generation
  • Update sample tests to use KspLibraryDeepLinkModuleRegistry with assets

The asset-based approach provides:

  • Faster build times (no string chunking/encoding)
  • Faster app startup (direct binary loading, no string decoding)
  • Better APK compression (binary assets compress better than dex strings)

Both modes (asset-based and string-based) are supported per-registry level.

I did run benchmarks on this and in the registry creation (the important benchmark) the asset based approach is bout 20-25% faster, less than I had hoped but this also simplifies this significantly especially once we drop kapt support.

Comment thread gradlew

#
# Copyright © 2015 the original authors.
# Copyright © 2015-2021 the original authors.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just updated gradlew to latest as of the used gradle version (9.2.1)

Andreas Rossbacher added 7 commits April 20, 2026 15:28
This change adds an optional asset-based approach for storing the match
index binary data when using KSP with the manifest-generation plugin.
Instead of encoding the binary data as strings in the generated registry
class, the match index is written as an Android asset file and loaded
at runtime via AssetManager.

Key changes:
- Add shared constants in ManifestGeneration.kt for asset paths and KSP option
- Generate AssetManager-based registry constructor when useAssetBasedMatchIndex=true
- Add MergeDeepLinkAssetsTask and RelocateDeepLinkAssetsTask for Gradle plugin
- Update ManifestGenerationPlugin to handle asset file relocation and merging
- Add processor tests for asset-based and legacy string-based code generation
- Update sample tests to use KspLibraryDeepLinkModuleRegistry with assets

The asset-based approach provides:
- Faster build times (no string chunking/encoding)
- Faster app startup (direct binary loading, no string decoding)
- Better APK compression (binary assets compress better than dex strings)

Both modes (asset-based and string-based) are supported per-registry level.
- Share loadMatchIndexFromAsset helper via new Utils.RegistryUtils object
  in the :deeplinkdispatch module so the processor no longer emits a
  per-registry copy of the helper method.
- Fail the build (throw DeepLinkProcessorException) when the binary
  match-index asset can't be written, instead of swallowing the
  IOException as a diagnostic error.
- Replace runtime reflection for setting the KSP `deepLink.useAssetBasedMatchIndex`
  arg with a typed call gated on pluginManager.withPlugin("com.google.devtools.ksp").
- Centralize KSP output paths in ManifestGeneration (kspResourcesDir,
  kspGeneratedManifestPath, kspGeneratedAssetsDir) so the gradle plugin
  and processor agree on one source of truth.
- Replace findByName-based task lookups in the plugin with
  `tasks.matching { it.name == ... }.configureEach`, which is lazy and
  tolerates KSP registering its variant-specific tasks after our
  plugin code runs.
- Sample: use `gradle.projectsEvaluated` to wire the cross-project
  copyLibraryAssetsForTest task (the producer is registered inside
  a sibling project's AGP onVariants callback, which fires during
  projectsEvaluated, not afterEvaluate), and use an exact consumer
  task-name set so we don't end up depending on unrelated
  lintVitalRelease tasks.
- Tests: add BaseDeepLinkProcessorTest stubs for RegistryUtils so KSP-
  generated registries compile under the processor test classpath, and
  add an end-to-end test that compiles the same deep links both ways
  (string-encoded and asset-based) and asserts that the bytes of the
  asset equal the bytes decoded from the generated string chunks.
@rossbacher rossbacher force-pushed the rossbacher-useBinaryMatchIndexWithKsp branch from ba52a88 to 864d4c8 Compare April 20, 2026 22:31
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.

1 participant