Skip to content

Repository files navigation

Bytecode Surgery — sample project

Companion code for Bytecode Surgery: Modifying Third-Party Libraries in Android with ASM.

It's a runnable, minimal reproduction of the article's example: an ASM-based AGP Instrumentation plugin that rewrites calls to isSystemInDarkTheme() at build time, forcing them to return false, without touching the source of the library that calls it.

Modules

  • build-logic — the actual plugin from the article: LightThemeVisitor, LightThemeVisitorFactory, and LightThemePlugin, registered as the Gradle plugin io.github.lucf15.bytecodesurgery.light-theme.
  • onboarding-lib — stands in for a third-party UI library you depend on but can't edit. Its one screen calls isSystemInDarkTheme() and renders a different background depending on the result. Nothing else in this project calls that function.
  • app — a minimal app that only depends on onboarding-lib and applies the plugin. It never references isSystemInDarkTheme() itself.

Only app/build.gradle.kts applies the plugin, with InstrumentationScope.ALL. That's enough to rewrite onboarding-lib's compiled bytecode during the app's build, since from Gradle's point of view a project dependency is instrumented the same way an external library would be.

Running it

./gradlew :app:installDebug

Or open the project in Android Studio and run the app configuration.

Toggle your device's system Dark Theme setting on or off, reinstall, and the screen will always read:

isSystemInDarkTheme() reports: false

Verifying the bytecode

To see the effect directly instead of trusting the screen text, decompile the built APK and look at OnboardingScreenKt:

./gradlew :app:assembleDebug
jadx -d /tmp/jadx-out app/build/outputs/apk/debug/app-debug.apk
cat /tmp/jadx-out/sources/io/github/lucf15/bytecodesurgery/onboarding/OnboardingScreenKt.java

There's no call to isSystemInDarkTheme() in the decompiled output, only a hardcoded 0 constant where the call used to be, which is exactly what LightThemeVisitor does: pop the call's arguments and push ICONST_0 instead of invoking it.

License note

This targets androidx.compose.foundation.DarkThemeKt.isSystemInDarkTheme, part of an Apache 2.0-licensed library, for interoperability with the app that depends on it. See the "A Word of Caution" section of the article before pointing this technique at code you don't own under a different license.

License

Apache License 2.0.

About

Runnable sample for the Medium article on patching a dependency's bytecode at build time with ASM and the AGP Instrumentation API

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages