※ChatGPTを使用して記事を作成しています。
はじめに
Android開発において、依存ライブラリはもはや欠かせない存在です。Retrofit、OkHttp、Glide、Hilt、Room、Compose関連など、公式・非公式を問わず、多くのライブラリが私たちの開発スピードを劇的に向上させてくれます。
しかし、その恩恵の裏には大きなリスクがあります。そう、「ライブラリの更新」です。最新バージョンにアップデートした途端、ビルドが通らなくなったり、実行時にクラッシュしたり、最悪の場合はリリース後にユーザー環境で大規模な不具合が発生することさえあります。
今回の記事では、私が実際に「依存ライブラリ更新で大爆死」した体験談を交えながら、なぜそんなことが起こるのか、どうすれば回避できるのかを掘り下げていきます。
ケース1: Retrofitの大規模更新
ある日、Retrofitを2.x系の最新バージョンに更新しました。Release Noteには「Bug Fix」「パフォーマンス改善」など良いことばかり書いてあり、何も考えずに libs.versions.toml
の retrofit
の行を書き換えてビルド。
最初はビルドが通ったので安心していました。しかし、いざ実行するとAPI通信部分で大量のクラッシュが発生。調べてみると、内部的に依存しているOkHttpのバージョンも引き上げられており、TLSまわりの挙動が変わっていたのです。
失敗コード例
// 旧バージョンでは問題なかったコード
val client = OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
新しいバージョンでは、このコードで一部の古いAndroid端末からの接続が失敗するようになりました。TLS1.2対応が必須になったためです。
修正版
val spec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) .tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_3) .allEnabledCipherSuites(true) .build() val client = OkHttpClient.Builder() .connectionSpecs(listOf(spec, ConnectionSpec.CLEARTEXT)) .retryOnConnectionFailure(true) .build()
教訓: Retrofitの更新は単なるメソッド仕様の変更にとどまらず、内部の依存ライブラリ(OkHttp)の影響も受けるため、必ずRelease Noteをチェックし、古い端末での動作確認も忘れないこと。
ケース2: Jetpack ComposeのCompose BOM地獄
Composeを使っている方ならご存知の通り、ライブラリ群はBOM(Bill of Materials)で一括管理します。これ自体は便利なのですが、Compose CompilerやKotlinのバージョンと密接に関係しているため、相性問題が頻発します。
ある日、Kotlinを2.0に更新したタイミングでCompose BOMも最新に引き上げたところ、全画面で真っ白になる現象に遭遇しました。
失敗コード例
implementation(platform("androidx.compose:compose-bom:2025.01.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.material3:material3")
Kotlin 2.0では新しいCompose Compilerが必須だったにもかかわらず、古いCompose Compilerが使われていたため、実行時にクラッシュせず「描画されない」だけという最悪の症状になりました。
修正版
plugins { id("org.jetbrains.kotlin.android") version "2.0.0" id("org.jetbrains.kotlin.plugin.compose") version "2.0.0" } dependencies { implementation(platform("androidx.compose:compose-bom:2025.02.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.material3:material3") }
教訓: Compose関連は「Kotlin」「Compose Compiler」「BOM」の3点セットで必ずバージョン整合性を確認すること。1つでもズレると、描画すらされなくなる。
ケース3: ProGuard/R8との地獄絵図
ライブラリ更新の地雷原の一つがProGuard(R8)です。
あるライブラリを更新した途端、リリースビルドでのみクラッシュ。原因は内部クラスが難読化され、リフレクションで呼び出される箇所が全滅していたことでした。
失敗例
# 旧バージョンではこれで動いていた -keep class com.example.mylib.** { *; }
新バージョンでは内部構造が大きく変わり、-keep
の指定だけでは足りなくなりました。
修正版
# Retrofit + Gson の例 -keepattributes Signature -keepattributes *Annotation* -keep class com.google.gson.stream.** { *; } -keep class sun.misc.Unsafe { *; } -dontwarn okhttp3.**
教訓: ライブラリ更新時はProGuard設定の再確認が必須。特にリフレクションを使うライブラリは要注意。
なぜ爆死するのか?
- 依存関係が芋づる式に更新される
→ Retrofit更新 → OkHttp更新 → TLS仕様変更 → 古い端末で通信不能 - 非互換性が突然出る
→ ComposeとKotlinのバージョン整合性 - ドキュメント不足
→ ProGuardの必要設定が明示されていない - CI/CDでの自動更新の罠
→ RenovateやDependabotで一括更新して壊れる
防止策
- Release Noteを必ず読む
- 段階的に更新する(一気に複数ライブラリを更新しない)
- テストを拡充する(古い端末・リリースビルドを含む)
- CIにスモークテストを組み込む
- バージョン固定 (
libs.versions.toml
で安定版を管理) - 本番リリース前のステージング環境で必ず確認
まとめ
ライブラリ更新は「最新が最強」と思い込みがちですが、実際は爆弾が仕込まれていることが多いです。安易に更新して「動かない!戻そう!」となると依存関係の巻き戻しでさらに時間を浪費します。
一番大切なのは 「ライブラリ更新はプロジェクトの一大イベント」 という認識を持つことです。計画的に、慎重に、そしてテストを厚くして臨みましょう。