Migrate Hunter from Transform API to AGP 8.7 Instrumentation API#68
Conversation
Issues addressed: - #67 / #63 / #34: Transform API removed in AGP 8.0 → migrated each Hunter plugin to AndroidComponentsExtension.onVariants + AsmClassVisitorFactory. HunterTransform / ClassLoaderHelper / ExtendClassWriter / Schedulers / Worker are deleted; the new HunterPlugin / HunterAsmClassVisitorFactory base classes hide the AGP boilerplate so existing weaver authors keep writing ClassVisitor-based weavers. - #66 / #60: bumped every ASM ClassVisitor / MethodVisitor adapter from Opcodes.ASM7 to Opcodes.ASM9 so Java 17 records and sealed classes load. ASM dependency bumped to 9.7. - #48: TimingMethodAdapter no longer injects the start probe at visitCode in constructors — it tracks NEW depth and waits for the outermost INVOKESPECIAL <init> before priming startVarIndex, producing legal bytecode. - DebugWeaver's two-pass pre-go / instrumentation pipeline now runs against a buffered ClassNode, since AGP only hands us a single ClassVisitor chain. - DebugPreGoMethodAdapter.visitLocalVariable guards against an empty labelList instead of throwing IndexOutOfBoundsException on exotic methods. Build / publish: - AGP 8.7, Gradle 8.10.2, JDK 17 toolchain, compileSdk 34, minSdk 21. - vanniktech maven-publish 0.30 + Sonatype Central Portal (OSSRH was shut down 2025-06-30). Signing only enabled when a GPG key is configured, so publishToMavenLocal still works on a dev box. - New .github/workflows/gradle-publish.yml uses repository secrets only — MAVEN_CENTRAL_USERNAME / MAVEN_CENTRAL_PASSWORD / SIGNING_IN_MEMORY_KEY / SIGNING_IN_MEMORY_KEY_ID / SIGNING_IN_MEMORY_KEY_PASSWORD — and triggers on `v*` tags or manual dispatch (with a dry-run option). - New .github/workflows/build.yml runs assemble + check on PRs and pushes. Examples are excluded from settings.gradle: they reference plugins by their published Maven coordinates, so they only build after a publish.
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (72)
📝 WalkthroughWalkthroughMigrates Hunter from the legacy Gradle Transform API to the modern AGP AsmClassVisitorFactory and AndroidComponentsExtension. Updates all four plugins (debug, linelog, okhttp, timing) to the new architecture, upgrades build toolchain to Gradle 8.10.2 with AGP 8.7.0 and ASM 9.7, removes Transform infrastructure, and modernizes all Android examples to API 34 with Java 17. Changes
Sequence DiagramsequenceDiagram
participant User as User/Gradle
participant HPlugin as HunterPlugin
participant AGP as AndroidComponentsExtension
participant Variant as Variant
participant HFactory as HunterAsmClassVisitorFactory
participant Weaver as IWeaver (e.g. DebugWeaver)
participant ClassVisitor as AGP ClassVisitor Chain
User->>HPlugin: apply(Project)
HPlugin->>HPlugin: registerExtension(Project)
HPlugin->>AGP: locate & obtain reference
alt AGP Available
HPlugin->>AGP: onVariants { ... }
loop For Each Variant
AGP->>Variant: call listener
Variant->>HPlugin: skipVariant check
alt Not Skipped
HPlugin->>HFactory: transformClassesWith(getFactoryClass(), ...)
HFactory->>HFactory: createClassVisitor(ClassContext, nextClassVisitor)
HFactory->>Weaver: createWeaver(ClassContext)
Weaver->>HFactory: return IWeaver instance
HFactory->>Weaver: wrap(nextClassVisitor)
Weaver->>ClassVisitor: return wrapped ClassVisitor
ClassVisitor->>ClassVisitor: instrument bytecode
end
end
else AGP Not Applied
HPlugin-->>User: throw IllegalStateException
end
Old Flow (Removed): User/Gradle → Plugin.apply() → register Transform via AppExtension → Transform.transform(Context, ...) → custom ClassLoader setup → iterate JARs/files → ClassReader/ClassWriter/ExtendClassWriter → async work queue → await completion New Flow: User/Gradle → HunterPlugin.apply() → register extension → AndroidComponentsExtension.onVariants → for each variant check skipVariant → register ASM transformation with factory → factory creates weaver on-demand (cached) → weaver wraps ClassVisitor for bytecode instrumentation Estimated code review effort🎯 4 (Complex) | ⏱️ ~65 minutes Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This PR modernizes Hunter to use the Android Gradle Plugin 8.7+ Instrumentation API instead of the deprecated Transform API, while maintaining backward compatibility with the existing plugin architecture.
Summary
Hunter has been refactored to leverage AGP's modern
AsmClassVisitorFactoryinstrumentation pipeline. The legacyTransformAPI implementation has been replaced with a new base plugin framework that abstracts away AGP instrumentation boilerplate, allowing plugin authors to continue writingClassVisitor-based weavers.Key Changes
Core Framework
HunterTransformclass and all Transform API-specific codeExtendClassWriter,ClassLoaderHelper,Worker, andSchedulers(no longer needed with AGP's built-in instrumentation)HunterPlugin<P, F>- base plugin class that handles AGP instrumentation registrationHunterAsmClassVisitorFactory<P>- bridges AGP's factory contract to Hunter'sIWeaverabstractionHunterParameters- common interface for variant-specific configurationPlugin Updates
All four plugins (debug, timing, okhttp, linelog) have been refactored:
*HunterTransformclasses*HunterPluginto extendHunterPluginbase class*ClassVisitorFactoryimplementations*HunterParametersinterfaces for configuration*Weaverclasses to focus onClassVisitorwrappingASM & Bytecode
BaseWeaverto provide simplifiedwrap(ClassVisitor)contractIWeaverinterface to focus on visitor wrappingTimingMethodAdapterto defer probe injection until after super/this callsBuild & Dependencies
Examples
Updated all example projects to apply plugins via buildscript classpath and use modern Android DSL (compileSdk instead of compileSdkVersion).
Implementation Details
HunterPluginbase class handles variant filtering viaRunVariant.shouldSkip()HunterAsmClassVisitorFactorylazily caches weaver instances to avoid re-reading parameterscreateWeaver(ClassContext)and optionally overrideregisterExtension()https://claude.ai/code/session_011eDE2NVFKX5Fyk8ggYaV89
Summary by CodeRabbit
Release Notes
New Features
Breaking Changes
Improvements