0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Type Safe Navigationの導入でやらかした話

Posted at

初めに

公開中のアプリに、型安全のNavigationを導入しリリースしたところ、更新した全ユーザーにクラッシュが発生してアプリが起動できなくなってしまいました。

調査

エラーの内容

D7.g: Serializer for class 'k' is not found.
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.

"Serializer対象のクラスが見つかりません。@Serializableを付け、serialization pluginを適用していることを確認してください。"とのことですが、どちらも適用されています。
ただし、クラスが見つからないのと、実装時の動作確認では問題無かったので、Proguard絡みだと予想されます。

build.gradle.kts
buildTypes {
    release {
        isMinifyEnabled = false
        isShrinkResources = true
        proguardFiles(
            getDefaultProguardFile("proguard-android-optimize.txt"),
            "proguard-rules.pro"
        )
    }
+    debug {
+        isMinifyEnabled = true
+        isShrinkResources = true
+        proguardFiles(
+            getDefaultProguardFile("proguard-android-optimize.txt"),
+            "proguard-rules.pro"
+        )
+    }
}

設定を追加して、ローカルのデバッグビルドでも発生するのか確認します。

kotlinx.serialization.SerializationException: Serializer for class 'SearchGraph' is not found.
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.

デバッグ情報が付与されているため、見つからないというクラス名も出力されていますが、同じエラーが発生したので、こちらが発生しないよう調査、修正を行います。

導入手順の再確認

Kotlin DSL と Navigation Compose における型安全性  |  Android Developers
こちらの手順を確認しましたが、こちらも問題ありませんでした。また、Proguardに関する記述はありませんでした。

Proguardに関する情報を探すと、Kotlin Serialization側で見つかりましたが、プラグインを導入すると自動的に適用されるようです。実装方法によっては追加の設定が必要なようですが、そちらにも該当しませんでした。
Kotlin/kotlinx.serialization: Kotlin multiplatform / multi-format serialization

他のアプリで確認

CodelabやGoogleが公開しているサンプルアプリを探してみましたが、Type Safe Navigationを使用している物はみつかりませんでしたが、先日投稿した記事で参考にしたサンプルがType Safe Navigationを使用していたので、そちらのProguardを有効にして実行してみたところ、エラーは発生せずに起動できました。

原因箇所の特定

Type Safe Navigation+sealed interface(?)Hilt(?)Proguardで、正常に動いているアプリと動かないアプリの設定や実装の違いを比較し、何処が原因なのか調査しました。

結論としては、現在の実装方法では、NavHost内で、ネストしたナビゲーションnavigation<T>()を使用せずに、通常のナビゲーションcomposable<T>()を使用すると、デスティネーションのクラスが見つからなくなるようです。現在の実装方法ではと書いたのは、通常のナビゲーションを使用していても問題無く動作しているアプリもあるのですが、それらのアプリでは、デスティネーションの指定にsealed interfaceを使用しなかったり、Hiltを使用していなかったりするため、そのあたりも影響があるようです。

Destination.kt
sealed interface Destination {
    // ...
+    @Serializable
+    data object DemoScreen: Destination
}
MainActiviy.kt
    NavHost(
        navController = navController,
        startDestination = navigator.startDestination,
        modifier = Modifier.padding(innerPadding)
    ) {
+        composable<Destination.DemoScreen>() {
+            // TODO
+        }
        navigation<Destination.AuthGraph>(
            startDestination = Destination.LoginScreen
        ) {
            composable<Destination.LoginScreen> {
                val viewModel = hiltViewModel<LoginViewModel>()
kotlinx.serialization.SerializationException: Serializer for class 'DemoScreen' is not found.
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.

修正方法

その1

デスティネーションを定義しているクラスを最適化の対象から除外する。

proguard-rules.pro
+-keep class jp.hamachi.android.img.core.navigation.** {*;}

その2

デスティネーションを定義しているsealed interfaceにも@Serializableを付ける。

Destination.kt
+@Serializable
sealed interface Destination {

終わりに

今回の場合は上記のどちらの対応でもエラーは発生しなくなりましたが、ネストしたナビゲーションでは元々発生せず、通常のナビゲーションの場合のみ発生する理由がはっきりしないままです。ネストしたナビゲーションを使用することが推奨されていたりするのでしょうか?ご存じの方がいらっしゃいましたらお教えください。

戒め

リリース前には、リリースビルドで動作確認を行いましょう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?