Claude Media
Claude CodeでR8の難読化をretraceで戻してから渡す手順

Claude CodeでR8の難読化をretraceで戻してから渡す手順

Play Consoleやlogcatの難読化されたスタックトレースを、mapping.txtとretraceで戻してからClaude Codeに渡す順序。keepルールを足したあとの検証まで、AndroidのR8を例にまとめます。

R8で難読化したAndroidアプリのクラッシュログは、そのままClaude Codeに貼ると調査の質が落ちます。a.b.a.c(Unknown Source) のような名前では、Claudeもリポジトリ内のどのクラスか特定できないからです。先に mapping.txt と retrace で元の名前に戻し、戻したトレースを渡す。この順序なら、Claudeは元のクラス名を手がかりにリポジトリを調べられます。

keepルールを足したあとの検証まで含めて、Claude Codeに任せる範囲と人が握る範囲を分けて書きます。

なぜ貼る前に戻すのか

R8は、コードの縮小に加えて名前の短縮もします。com.example.MyActivity が a.b.a になるのが典型例で、DEXファイルが小さくなる代わりに、スタックトレースはソースと対応しなくなります。行番号やクラス名、メソッド名が変わるため、トレースだけではコードを引けません。

Claude Codeにバグ修正を頼むときは、再現コマンドとスタックトレースを渡すと進みやすくなります。これはClaude Codeの一般的なワークフロー解説にも書かれている基本です。難読化されたままのトレースは、この「手がかり」として働きません。リポジトリを検索しても a.b.a に当たる箇所が見つからず、推測で別のクラスを疑い始める恐れがあります。

戻してから渡せば、Claudeは元のクラス名で検索し、該当ファイルを開いて原因を読めます。

戻す手段は3つある

どの経路でもmappingファイル(mapping.txt)が材料になります。使う場面が違うだけです。

経路

スタックトレースを戻す3つの経路

  • Logcat(Android Studio)

    Android Studio Otter 3 Feature DropとAGP 9.0以降は、Logcatが自動でデオブフスケートします。手元の端末や実機デバッグの出力はこれで足ります。

  • retraceコマンド

    古いAndroid Studioを使っている場合や、ログファイルを手元に持っている場合の手動手段です。コマンドラインツールに同梱されています。

  • Play Console

    mappingをアップロードしておくと、以降のクラッシュとANRがデオブフスケートされた状態で、Android vitalsの画面に出ます。

Claude Codeに渡す素材として使いやすいのは、手元のファイルに落とせる retrace の出力です。Play Consoleの画面からトレースをコピーする場合も、すでに戻っているかどうかを先に見ておくと無駄がありません。

retraceの実行手順

retraceは、mappingファイルとスタックトレースのファイルを引数に取ります。Android開発者向けドキュメントに載っているコマンドは次の形です。

$ANDROID_HOME/cmdline-tools/latest/bin/retrace \
  app/build/outputs/mapping/$releaseVariant/mapping.txt \
  trace.txt

$releaseVariant はビルドバリアントの名前(たとえば release)に置き換えます。trace.txt には、Play Consoleやクラッシュ収集サービスからコピーした難読化済みのトレースを貼ります。

手順

トレースをClaude Codeに渡すまでの流れ

  1. 1

    クラッシュしたバージョンのmapping.txtを探す

    クラッシュが出たリリースと同じビルドのmappingを使います。別のビルドのmappingでは名前が合いません。

  2. 2

    トレースをtrace.txtに保存する

    Play ConsoleやCrashlyticsの画面から、難読化されたままのスタックトレースをコピーして保存します。

  3. 3

    retraceで元の名前に戻す

    上のコマンドを実行します。出力の先頭付近で、自分のパッケージ名のクラスが読めることを確かめます。

  4. 4

    戻したトレースをClaude Codeに渡す

    再現手順と、戻したトレースを一緒に渡します。

ターミナルから非対話で渡すなら、出力をファイルに保存してパイプで流す形が使えます。Claude Codeは標準入力を受け取れるので、git log を渡す例と同じ要領です。

cat retraced.txt | claude -p \
  "このスタックトレースの原因を、リポジトリのコードを読んで特定して"

対話セッションで頼むなら、ファイルのパスを書くだけで足ります。

retraced.txt は release 1.4.2 で出たクラッシュを retrace で戻したものです。
該当クラスを開き、nullになる経路を調べてください。

mappingは毎回保存しないと戻せない

この作業で一番つまずきやすいのは、mappingが残っていないことです。Android Studioは build/outputs/mapping/ にmappingファイルを保存しますが、ビルドのたびに上書きされます。リリースのたびにコピーを残しておかないと、過去のバージョンのクラッシュは戻せなくなります。

Play Consoleの側にも似た条件があります。

  • mappingはバージョンごとに必要で、新しいバージョンのたびにアップロードします
  • Android App BundleをAGP 4.1以降でビルドしている場合、アップロードは不要で、Play側がバンドルからmappingを取り出します
  • APKで配布している場合は、手動でアップロードします
  • アップロード前に起きたクラッシュは、あとからmappingを上げてもデオブフスケートされません
  • 対応するのはReTrace互換のmappingで、ProGuardとR8が出す形式です

Claude Codeに「mappingを探して」と頼む前に、保管場所を決めておくと運用が楽です。CIでリリースビルドを作っているなら、成果物としてバージョン名付きで保存する設定が現実的です。

落とし穴

手元のmapping.txtが古いビルドのもの

直近のローカルビルドで mapping.txt が上書きされ、クラッシュが出たリリースの名前と合わなくなります。名前が合わないmappingでは正しく戻せません。リリースごとに保存したコピーを使ってください。

CLAUDE.mdに書いておくと毎回の説明が減る

戻す手順を毎回口頭で伝えるのは手間です。難読化に関する約束事は、CLAUDE.mdに短く書いておけます。

## 難読化されたクラッシュの扱い
- スタックトレースの名前が a.b.a のように短いときは、調査を始めず先に伝えること
- mapping は releases/<バージョン>/mapping.txt にある
- 戻すときは $ANDROID_HOME/cmdline-tools/latest/bin/retrace を使う
- 戻したトレースは retraced.txt に保存してから読む

この断片はあくまで一例で、ディレクトリ名はプロジェクトに合わせて変えてください。要点は、Claudeが難読化済みのトレースを見て推測に走らないよう、止まる条件を書いておくことです。

keepルールを足すときの順序

戻したトレースが ClassNotFoundException や NoSuchMethodException で終わっていたら、リフレクションが壊れている可能性があります。R8の公式ドキュメントでは、次のような例外が目印とされています。

  • ClassNotFoundException
  • NoSuchMethodException
  • NoSuchFieldException
  • NoClassDefFoundError
  • NoSuchMethodError
  • NoSuchFieldError

コード側に Class.forName(...) や java.lang.reflect.* の利用があれば、疑いは濃くなります。対処はkeepルールの追加で、自分のコードのリフレクションならJetpack Keepのアノテーションで済ませる手もあります。

Claude Codeにkeepルールを書かせるときは、広く保持するルールを最初に書かせないことが肝心です。-keep class com.example.** { *; } のように広くすれば直りますが、R8の最適化の効果が薄れます。対象を絞った形の例は、次のようになります。

-keep class com.example.model.UserData {
    public java.lang.String getUserId();
}

これはドキュメントにあるメソッド指定の例です。コンストラクターは <init> で指定します。

ルールの効き方を確かめる

ルールを足したら、効いているかを検証します。ここはClaudeの推測に任せず、R8自身の出力を根拠にします。

手順

keepルール追加後の切り分け

  1. 1

    リリースビルドを作り直して再現する

    同じ例外が出なければ直っています。出るなら次へ進みます。

  2. 2

    ルールが取り込まれているかを見る

    app/build/outputs/mapping/configuration.txt には、ライブラリとモジュールの全ルールが統合されて載ります。足したルールがここにあるかを確かめます。ライブラリ側が持ち込んだ範囲の広いkeepルールも同じ場所で見つかるので、必要以上に多くのコードが残る原因を探すときの手がかりになります。

  3. 3

    保持理由を調べる

    対象のクラスやメソッドが残っている理由を、-whyareyoukeeping でローカルに調べます。

-whyareyoukeeping はR8に「なぜこれを残したのか」を出力させるルールです。出力には、キープしているルールの場所や、保持されたコードからの参照が載ります。

-whyareyoukeeping class com.example.foo.MainActivity {
  private void setLabel(...);
}

このルールはローカルでのデバッグ専用で、ビルドが遅くなるためコミットには含めません。Claudeに頼むときも、「一時的に足して、確認後に消す」と指示しておくと混ざりません。

手を動かす前に決めておく役割分担

自動化できるのは調査までで、リリース判断は人が持つのが安全です。

作業Claude Codeに任せる人が握る
retrace実行と結果の読解Claude Codeに任せる向く人が握るmappingの正しさの確認
原因クラスの特定Claude Codeに任せる向く人が握る再現手順の提供
keepルール案の作成Claude Codeに任せる向く人が握る範囲の広さの判断
-whyareyoukeeping の実行と解釈Claude Codeに任せる向く人が握るルールをコミットに残さない確認
Play ConsoleへのアップロードClaude Codeに任せる向かない人が握るmappingの管理

Android端末の操作そのものを任せたい場合は、Android-MCPの手順や、ビルドと画面操作までつなぐReplicant MCPの記事が参考になります。クラッシュ調査全般の渡し方は、Claude Codeデバッグの精度を決める情報の質に整理されています。

まとめ

順序は「mappingを保管する、retraceで戻す、戻したトレースを渡す、keepルールは狭く足して検証する」です。難読化済みのトレースを貼っても、Claudeは調査を始められません。Play Consoleが自動で戻してくれる範囲も、アップロード後のクラッシュに限られます。まずは次のリリースから、mappingをバージョン名付きで残す運用に切り替えるところが出発点になります。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. developer.android.com/topic/performance/app-optimization/troubleshoot-the-optimi…
  2. developer.android.com/topic/performance/app-optimization/add-keep-rules
  3. developer.android.com/topic/performance/app-optimization/troubleshooting-rules
  4. support.google.com/googleplay/android-developer/answer/9848633
  5. developer.android.com/build/shrink-code
  6. code.claude.com/docs/en/common-workflows
この記事を共有:XはてブLinkedIn