課題
Flutterアプリで、flutter_local_notificationsを使ってローカル通知を作成するとき、デバッグビルドでは問題ないが、リリースビルド時に失敗する。
確認したこと
まずはリリースビルドの実行
$ flutter run --release
リリースビルドだとデバッグログが表示されないので、別でターミナルを立ち上げログ監視
$ adb logcat | grep flutter
すると、下記のようなログが表示される。
01-09 14:24:07.177 3966 3966 E MethodChannel#dexterous.com/flutter/local_notifications: Failed to handle method call
01-09 14:24:07.177 3966 3966 E MethodChannel#dexterous.com/flutter/local_notifications: java.lang.RuntimeException: Missing type parameter.
01-09 14:24:07.177 3966 3966 E MethodChannel#dexterous.com/flutter/local_notifications: at R1.a.<init>(SourceFile:4)
01-09 14:24:07.177 3966 3966 E MethodChannel#dexterous.com/flutter/local_notifications: at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.loadScheduledNotifications(SourceFile:26)
(略)
デバッグビルド時には出なかったタイプエラーが出てる??なぜ??
原因
この問題は、ProGuard や R8(リリースビルドでコードの最適化、縮小、難読化を行うツール)の設定が原因らしい。
ProGuard や R8 は、Java/Kotlin コードを最適化する過程で使用されていないクラスやメソッド、フィールドを削除するが、特にジェネリクス(List や Map のような型パラメータ)に関する情報は、ランタイムには不要だと判断されて削除される可能性があるとのこと
https://developer.android.com/build/shrink-code?hl=ja
解決策
コードの最適化時に必要な部分が削除されることを防ぐため、proguardの設定を行う。
android/app配下にproguard-rules.proを作成し、下記をコピペする
## Gson rules
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
android/app/build.gradleのbuildTypesを下記のように編集する。
buildTypes {
release {
minifyEnabled true
shrinkResources true
signingConfig = signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
この設定を行うことで標記の問題は解決できた。
参考
https://stackoverflow.com/questions/68265930/java-lang-runtimeexception-missing-type-parameter-error-on-released-apk
https://github.com/MaikuB/flutter_local_notifications/blob/master/flutter_local_notifications/example/android/app/proguard-rules.pro