
Claude CodeでAndroidのメモリリーク改善を自動化する ── LeakCanaryの検知からAI修正までのアプローチ
はじめに こんにちは。and factory Androidエンジニアの鬼倉です。 今回は、私が携わるAndroidプロジェクトでClaude Codeを活用し、ANR改善に取り組んだアプローチを紹介します。ANRの原因はさまざまですが、本記事ではメモリリークを原因とするANRに焦点を当てます。 Android開発者にとって、メモリリーク対応のためにLeakCanaryを導入したはいいものの、結局修正できず通知が出続けているという方も多いのではないでしょうか? そこで今回私のプロジェクトでは、LeakCanaryによる検知に加えてClaude CodeのSkillsを活用した自動修正の仕組みを構築しましたので紹介します。 ANRとは? ANR(Application Not Responding)とは、アプリが指定時間内に操作を応答できなかった場合に発生するシステムエラーです。代表的には、UIスレッドが入力イベントに対して5秒以内に応答できない場合などでトリガーされます(BroadcastReceiverやServiceでも発生)。デッドロック、I/O処理のブロック、高負荷処理などさまざまな原因で発生します。Crashと同様にユーザー体験を大きく損なう問題ですが、Crashほど原因が明確でなく再現も難しいため軽視されがちです。ANR率はFirebase CrashlyticsやGoogle Play Consoleで確認できます。 本記事の環境 技術 バージョン Kotlin 2.3.20 AGP(Android Gradle Plugin) 8.9.3 LeakCanary 2.14 ANR改善が進まなかった背景 まずはそもそもメモリリークによるANRの修正改善がなぜ進んでいなかったのかを整理します。 FirebaseのANRレポートだけでは原因を深掘りしにくい Crashの場合、Firebase Crashlyticsに発生元のExceptionが記録されるため、その箇所が直接的な修正対象になります。一方、メモリリーク由来のANRは事情が異なります。複数箇所のメモリリークが徐々に蓄積し、最終的にANRとして発生します。そのため、Firebase上のレポートから直接的な原因箇所を特定することが困難です。 さらに、メモリリークの蓄積は端末のメモリ状況やユーザーの操作パターンに依存するため、開発環境での再現も難しいという問題があります。 ANR改善のためのLeakCanary導入と修正対応の難しさ ANRの発生件数を改善するため、メモリリーク検知の定番ライブラリであるLeakCanaryを導入しました。LeakCanaryを導入すると、開発中の手元の端末上でメモリリークの発生をリアルタイムに把握できます。 しかし、検知できることと修正できることは別の問題です。LeakCanaryはメモリリークの発生タイミングやある程度の情報を提供しますが、明確なコード上の原因までは教えてくれません。開発者自身が情報をもとに原因となるコードを探し出し、修正する必要があります。 さらに厄介なのは、メモリリークの原因となるコードは一見すると問題がないように見える点です。修正にはAndroid開発やKotlinに関する深い知識が求められ、1件あたりの対応に時間を要します。結果として、他の機能開発やCrash対応に比べて優先度が下がり、改善が後回しになりがちな状況が続いていました。 Claude Codeを活用したメモリリーク改善アプローチ 以上の理由により、LeakCanaryやFirebaseのANRログだけでは自力での修正は困難でした。それに対してどのようにAIを活用して修正をしていくのでしょうか? 最もシンプルなアプローチとしては、LeakCanaryが通知を出したら内容をClaude Codeにコピーペーストして修正を依頼することです。この方法でももちろん対応できます。 しかし、Logcatを含めた前後情報があればより精度が高まりますし、コピーペーストという作業をなるべく減らし即座に修正を依頼する環境を構築しなければ、再び後回しになりかねません。 今回私たちが構築したのは、LeakCanaryが通知を出した瞬間にClaude Codeへ/investigate-leakと依頼するだけで完結する方法です。AIが自ら端末のLogcatを確認し、ログ情報からメモリリークの修正を提案します。 LeakCanaryのリークトレースをClaude Codeから取得可能にする なお、本記事のアプローチではLogcatの内容をAIに読み取らせるため、ユーザーの個人情報やAPIキーといった機密情報がLogに出力されていないことが前提となります。 LeakCanaryはメモリリークを検知すると端末上に通知を表示します。しかし、デフォルトではヒープダンプの解析結果がlogcatに出力されません。Claude Codeがリークトレースを自律的に取得できるよう、解析結果をlogcatに出力する仕組みを追加しました。 具体的には、LeakCanaryのonHeapAnalyzedListenerをカスタマイズしています。 1 2 3 4 5 6 7 8 9 10 11 12 13 import leakcanary.LeakCanary import leakcanary.OnHeapAnalyzedListener import timber.log.Timber val defaultListener = LeakCanary.config.onHeapAnalyzedListener LeakCanary.config = LeakCanary.config.copy( onHeapAnalyzedListener = OnHeapAnalyzedListener { heapAnalysis -> defaultListener.onHeapAnalyzed(heapAnalysis) // ここでLogに出力(ここではTimberを利用しています) Timber.tag("LeakCanary").d(heapAnalysis.toString()) } ) この設定により、Claude Codeは以下のadbコマンドでリークトレース全文を取得できます。 ...