自作プラグインをAndroid Gradle Plugin 7.1.0に移行した記録
Photo by Call Me Fred on Unsplash
Wantedlyでは、Androidのマルチモジュールの設定を楽にするために、共通の設定を自作のプラグインで管理しています。
今回は、Android Gradle Plugin 7.1.0がリリースされたので、その自作のプラグインを移行した記録をツラツラと書いていきます。内容はAGPを割と知っている人向けです。
実のところ、AGPのバージョンを上げるだけでも大体は動作しますが、Deprecatedなどの警告が数多く表示されるので、それらを移行するというのがメインの話です。
やったこと
BaseExtensionからCommonExtensionへ
Androidでbuild.gradle.ktsにandroid {}と記述する際、DSLを表現するクラス(android {}ブロックのthisになるクラス)は、com.android.applicationをapplyした場合はAppExtension、com.android.libraryをapplyした場合はLibraryExtensionになります。
それらの基底クラスはBaseExtensionとなっています。このような関係ですね。
- BaseExtension
- AppExtension
- LibraryExtension
我々の自作プラグインはこのBaseExtensionに対して、applicationとlibrary共通の設定を行うようにしていました。
AGP 7.1.0にしたタイミングでいくつかDeprecated警告が出るようになったので対応しようとします。
例として、lintOptions.isAbortOnErrorはlint.abortOnErrorに変更されているとあります。しかしながら、BaseExtensionにはlintというDSLは存在しません。
じゃあどこにあるのかというと、CommonExtensionです。
CommonExtensionは(2019年辺りに追加されているので恐らくAGP 7.0あたりで追加された)インターフェースであり、各種Extensionに実装されています。クラスの継承ではなくインターフェースにすることでDSLをより柔軟にする変更が起きているようです。
BaseExtensionはDeprecatedなDSLが多くあり、新しいDSLはCommonExtensionに集約されているようです。移行期であるせいか、BaseExtensionでDeprecatedになっていても、移行先はCommonExtensionにしかないということが起きています。
lintOptionsはそのいい例であり、移行先のlintはCommonExtensionにしかありません。(しかもBaseExtension.lintOptionsはDeprecatedになっていない…)
なので、BaseExtensionではなく、CommonExtensionに対して汎用的な設定を行うように修正が必要になります。
CommonExtension
CommonExtensionは4つの型パラメーターを持ちます。
ApplicationExtensionはこんなインターフェースで、
LibraryExtensionも具象の型パラメーターを指定しています。
CommonExtensionは抽象のDSLとなるわけですが、抽象で記述できる項目は限られています。例えばtargetSdkはApplicationとLibraryどちらにも存在してますがCommonには存在しません。ApplicationとLibraryで共通項目はあるけど、Commonにはないものがあります。これはDynamicFeatureなど他のExtensionも存在しているためだと思われます。
なので、このようにApplication/Library/Commonで設定を分ける実装に変更しました。
lint {}
android.lintOptions {} はDeprecatedになり、 android.lint {} にDSLが変更されています。
愚直にbuild.gradle.ktsのlintOptionsをlintに書き換えたところ、IDE上ではエラーがないがコンパイルエラーになるという状態になりました。
IDE上ではエラー表示はないが、実際にコンパイルすると以下のようなエラーが出ました。
FAILURE: Build failed with an exception.
* Where:
Build file '/Users/masatoshi/StudioProjects/app-android/app/build.gradle.kts' line: 143
* What went wrong:
Script compilation errors:
Line 143: lint {
^ Expression 'lint' cannot be invoked as a function. The function 'invoke()' is not found
しかも、 buildSrc の自作プラグインの中では lint {} と記述しても問題なく動作します。なので、Lintの設定はすべて自作プラグインの方へ移動することにしました。
AGPバージョンの解決時に問題があるのかと思い、 ./gradlew --scan などで調べてみましたが、特に問題はなさそうで、Google Issue Trackerも軽く調べたのですが特に見つからず、原因はわかっていません。
うちの固有の問題かもしれません。
Safe Args Plugin
Known issuesにも書かれているが、Navigation 2.4.0のSafe Args Pluginが動作しない。
https://issuetracker.google.com/issues/213086135
我々は未だに2.3.xを使い続けているせいか、この影響は受けなかった。(それはそれでよくない)
Firebase Performance Plugin
Firebase Performance Gradle Plugin 1.3.5を使っていたが、リリースビルド時に次のようなエラーが発生する。
Execution failed for task ':app:transformClassesWithFirebasePerformancePluginForVisitQaRelease'.
> 'java.lang.String com.android.utils.FileUtils.relativePossiblyNonExistingPath(java.io.File, java.io.File)'
firebase/firebase-android-sdk#3155 (comment) でも報告されていて、1.3.2にダウングレードしたら改善する。
Firebase Performance Plugin 1.4.1でAGP 7.1.0に対応しているらしいが、今後はここで報告されている問題が起きる。
> Task :app:minifyVisitQaReleaseWithR8 FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:minifyVisitQaReleaseWithR8'.
> Could not resolve all files for configuration ':app:visitQaReleaseRuntimeClasspath'.
> Failed to transform moshi-1.13.0.jar (com.squareup.moshi:moshi:1.13.0) to match attributes {artifactType=android-asm-instrumented-jars, asm-transformed-variant=visitQaRelease, org.gradle.category=library, org.gradle.dependency.bundling=external, org.gradle.jvm.environment=standard-jvm, org.gradle.jvm.version=8, org.gradle.libraryelements=jar, org.gradle.status=release, org.gradle.usage=java-runtime, org.jetbrains.kotlin.platform.type=jvm}.
> Execution failed for AsmClassesTransform: /home/circleci/.gradle/caches/modules-2/files-2.1/com.squareup.moshi/moshi/1.13.0/da685586facab9eb5c4fb630ce248be14e7da21b/moshi-1.13.0.jar.
> Record requires ASM8
これはAGP 7.2.0のリリースを待つしかないので、AGP 7.1.0環境ではFirebase Performance Plugin 1.3.2にダウングレードしておくしかなさそう。
まとめ
頑張って移行しましょう 💪