Migrate to AGP 9.2.1 + Gradle 9.4.1 (new DSL, built-in Kotlin)#61
Conversation
- buildSrc: Android Gradle Plugin 8.13.2 -> 9.2.1 (bundles KGP 2.3.10, matching the pinned Kotlin version). Gradle wrapper 8.14.5 -> 9.4.1. - app: drop the kotlin-android plugin; AGP 9 provides built-in Kotlin (android.builtInKotlin defaults to true), so applying it would clash. - Helpers.kt: adopt AGP 9's new DSL. Remove the legacy variant API (AbstractAppExtension / applicationVariants / BaseVariantOutputImpl) used for in-place APK output renaming, which no longer exists under android.newDsl=true. - Replace APK renaming with RenameApkTask, wired via androidComponents.onVariants + artifacts.use(...).toListenTo(APK). It copies each ABI split into build/outputs/renamed_apks/<variant>/ as NekoBox-<version>[-<abi>].apk and preserves output-metadata.json. Public APIs only (no AGP internals, no Gradle impldep). - CI workflows: point the arm64-v8a APK find/upload at renamed_apks. - Fix minor Gradle 9 deprecations (tasks.register, jniLibs.directories, rootProject.layout.buildDirectory). KSP stays at 2.3.9 (latest; the 2.3 line dropped the -kspRev suffix and is compatible with KGP 2.3.10). Verified locally: app:assembleOssDebug builds and renameApksForOssDebug runs as part of assemble.
- RenameApkTask.baseName: @internal -> @input so a version bump correctly invalidates the task and re-copies APKs with the new name (avoids stale output). Verified renameApksForOssDebug still runs automatically during a clean app:assembleOssDebug (it listens on SingleArtifact.APK). - CI workflows: fail loudly if no arm64-v8a APK is found under renamed_apks instead of silently proceeding with an empty path.
📝 WalkthroughWalkthroughThe PR upgrades the Android Gradle Plugin from 8.x to 9.2.1 and the Gradle wrapper from 8.14.5 to 9.4.1. It introduces a new ChangesAGP 9 Upgrade and APK Renaming Pipeline
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/release.yml:
- Around line 138-143: The find command on line 138 can return multiple APK
matches, and the unquoted dirname variable reference on line 143 will emit
multiple paths into GITHUB_ENV, corrupting the artifact path. Modify the APK
variable assignment to pipe the find result through head -1 to select only the
first match, ensuring a single APK path is captured. Then quote the variable in
the dirname call by changing dirname $APK to dirname "$APK" to properly handle
the path when storing in GITHUB_ENV.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: dfaec6dd-f5e5-43cb-b400-c42e6da6bb6b
📒 Files selected for processing (10)
.github/workflows/build.yml.github/workflows/ci.yml.github/workflows/preview.yml.github/workflows/release.ymlapp/build.gradle.ktsbuild.gradle.ktsbuildSrc/build.gradle.ktsbuildSrc/src/main/kotlin/Helpers.ktbuildSrc/src/main/kotlin/RenameApkTask.ktgradle/wrapper/gradle-wrapper.properties
- RenameApkTask: drop builtArtifacts.save(outputDir). The metadata it writes references the original un-renamed APK paths (outputs/apk/...), not the NekoBox-* copies, so it would mislead any BuiltArtifactsLoader consumer (Greptile P1). Nothing downstream consumes it, so omit it. - CI workflows (all four): pipe find through 'head -n 1' and quote dirname "$APK" to avoid multi-match / word-splitting corruption of GITHUB_ENV (CodeRabbit + Greptile P2). - Helpers.kt: add trailing newline (Greptile P2). Re-verified app:assembleOssDebug builds and renameApksForOssDebug emits the four NekoBox-<ver>-<abi>.apk files.
Summary
Migrates the build toolchain to the latest Android Gradle Plugin 9.x line, adopting AGP 9's new DSL and built-in Kotlin (no opt-out flags). Verified on Android with a local debug build.
Changes
buildSrc/build.gradle.kts). AGP 9.2.1 bundles KGP 2.3.10, matching the version already pinned.gradle/wrapper/gradle-wrapper.properties, pinneddistributionSha256Sum).kotlin-androidplugin fromapp/build.gradle.kts. AGP 9 enables built-in Kotlin by default, so applying the plugin would clash.Helpers.kt: removed the legacy variant API (AbstractAppExtension/applicationVariants/BaseVariantOutputImpl) that powered in-place APK output renaming - it no longer exists underandroid.newDsl=true.RenameApkTask(new): replaces APK renaming viaandroidComponents.onVariants+artifacts.use(...).toListenTo(SingleArtifact.APK). It copies each ABI split intobuild/outputs/renamed_apks/<variant>/asNekoBox-<version>[-<abi>].apkand preservesoutput-metadata.json. Public APIs only (no AGP internals, no Gradleimpldep).renamed_apks, with a guard that fails the job if no APK is found.tasks.register,jniLibs.directories,rootProject.layout.buildDirectory).KSP stays at 2.3.9 (latest; the 2.3 line dropped the
-kspRevsuffix and is compatible with KGP 2.3.10).Testing
./gradlew app:assembleOssDebugbuilds successfully on JDK 17 (matches CI).renameApksForOssDebugruns automatically duringassemble(clean rebuild after deleting outputs) and producesNekoBox-1.4.2-mod-12-arm64-v8a.apketc. +output-metadata.json.aapt2 dump badgingon the arm64 APK:package=com.nb4a.debug,versionName=1.4.2-mod-12,native-code=arm64-v8a.Greptile Summary
This PR migrates the Android build toolchain from AGP 8.13.2/Gradle 8.14.5 to AGP 9.2.1/Gradle 9.4.1, adopting AGP 9's new DSL and built-in Kotlin while replacing the removed
applicationVariants/BaseVariantOutputImplAPK-renaming API with a newRenameApkTaskthat uses the publicandroidComponents.onVariants+artifacts.use(...).toListenTo(SingleArtifact.APK)pipeline.kotlin-androidplugin dropped since AGP 9 enables built-in Kotlin by default to avoid an "extension already registered" clash.RenameApkTask(new): Copies each ABI-split APK fromoutputs/apk/<variant>/intooutputs/renamed_apks/<variant>/asNekoBox-<version>[-<abi>].apk; intentionally omitsbuiltArtifacts.save()to avoid emitting a misleadingoutput-metadata.jsonwith stale original paths (previously flagged and now explicitly documented in the code).find/upload atrenamed_apks, with a fail-fast guard if no arm64-v8a APK is present;$APKindirnameis now properly double-quoted.Confidence Score: 5/5
Clean build toolchain migration with no correctness issues found; safe to merge.
All three issues flagged in earlier review rounds (misleading output-metadata.json, unquoted shell variable, missing trailing newline) are explicitly addressed in this revision. The new RenameApkTask uses only public AGP APIs, correctly annotates inputs/outputs for Gradle's incremental build, and the CI guard ensures a missing APK fails fast rather than silently uploading nothing. No new defects were identified across any of the changed files.
No files require special attention.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A["`./gradlew assembleOssRelease`"] --> B[AGP compiles & links APKs] B --> C["`outputs/apk/ossRelease/ app-oss-arm64-v8a-release.apk app-oss-armeabi-v7a-release.apk app-oss-x86_64-release.apk app-oss-x86-release.apk`"] C -->|toListenTo SingleArtifact.APK| D["`renameApksForOssRelease (RenameApkTask)`"] D -->|BuiltArtifactsLoader enumerates splits| E{ABI detected in filename?} E -->|yes| F["`NekoBox-VERSION-arm64-v8a.apk NekoBox-VERSION-armeabi-v7a.apk NekoBox-VERSION-x86_64.apk NekoBox-VERSION-x86.apk`"] E -->|no — universal APK| G["`NekoBox-VERSION.apk`"] F --> H["`outputs/renamed_apks/ossRelease/`"] G --> H H --> I["`CI: find *arm64-v8a*.apk | head -n 1`"] I -->|APK found| J[Upload artifact directory] I -->|not found| K[exit 1 — fail job]%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD A["`./gradlew assembleOssRelease`"] --> B[AGP compiles & links APKs] B --> C["`outputs/apk/ossRelease/ app-oss-arm64-v8a-release.apk app-oss-armeabi-v7a-release.apk app-oss-x86_64-release.apk app-oss-x86-release.apk`"] C -->|toListenTo SingleArtifact.APK| D["`renameApksForOssRelease (RenameApkTask)`"] D -->|BuiltArtifactsLoader enumerates splits| E{ABI detected in filename?} E -->|yes| F["`NekoBox-VERSION-arm64-v8a.apk NekoBox-VERSION-armeabi-v7a.apk NekoBox-VERSION-x86_64.apk NekoBox-VERSION-x86.apk`"] E -->|no — universal APK| G["`NekoBox-VERSION.apk`"] F --> H["`outputs/renamed_apks/ossRelease/`"] G --> H H --> I["`CI: find *arm64-v8a*.apk | head -n 1`"] I -->|APK found| J[Upload artifact directory] I -->|not found| K[exit 1 — fail job]Reviews (2): Last reviewed commit: "Address review bots: metadata, shell quo..." | Re-trigger Greptile