ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-05-04中級

AntigravityでFirebase Crashlyticsのクラッシュ解析を自動化する

Firebase Crashlyticsのクラッシュレポートをビッグクエリ経由で自動取得し、Antigravityで根本原因を特定する実践ワークフローを解説します。GitHub Actions連携で毎朝自動解析が可能です。

firebase11crashlytics5ios35android27mobile-devcrash-analysisgithub-actions9

プレミアム記事

Crashlyticsのダッシュボードを開くたびに「また増えてる…」と感じていませんか。

個人でiOS/Androidアプリを運営していると、クラッシュレポートへの対応はどうしても後回しになりがちです。新機能の開発で手が埋まっているのに、毎日積み上がるレポートを一件一件読んで、再現して、修正する——この繰り返しは本当に消耗します。

私自身、2014年から個人でアプリを作り続ける中で、累計5,000万ダウンロードを超えるまでには「クラッシュ対応が怖い宿題」になっていた時期がありました。Antigravityを使い始めてから、このワークフローが根本的に変わりました。CrashlyticsのNSExceptionスタックトレースをそのままコンテキストとして渡すと、Antigravityがコードベースをスキャンしてどのファイルのどのメソッドが問題かを即座に指摘してくれます。

Firebase CrashlyticsとBigQueryの連携を準備する

まず前提として、Firebase CrashlyticsのBigQueryエクスポートを有効にしておく必要があります。Firebaseコンソールの「Crashlytics」→「BigQueryへのエクスポート」から設定できます。エクスポートが開始されると、firebase_crashlyticsデータセットにクラッシュイベントが自動で蓄積されていきます。

エクスポートの開始から最初のデータが揃うまで24〜48時間かかるため、まだ設定していない場合は先に有効化しておいてください。

設定後、以下のPythonスクリプトで直近7日間の致命的クラッシュ上位10件を取得できます。

# crash_fetcher.py
from google.cloud import bigquery
from datetime import datetime, timedelta
 
def get_top_crashes(project_id: str, app_id: str, days: int = 7) -> list[dict]:
    """
    Crashlyticsの直近N日間の致命的クラッシュ上位10件を取得する。
    app_idはFirebaseコンソールの「プロジェクト設定」>「全般」から確認できる。
    例: "1:123456789012:ios:abcdef1234567890"
    """
    client = bigquery.Client(project=project_id)
 
    # BigQueryのテーブル名はapp_idの":"を"_"に置換した形式
    table_id = app_id.replace(":", "_")
    dataset = f"{project_id}.firebase_crashlytics"
    table = f"{dataset}.{table_id}"
 
    query = f"""
    SELECT
        issue_id,
        issue_title,
        issue_subtitle,
        COUNT(*) AS crash_count,
        ARRAY_AGG(
            STRUCT(
                application.display_version AS version,
                device.manufacturer AS manufacturer,
                device.model AS model,
                os.display_version AS os_version,
                ARRAY(
                    SELECT CONCAT(frame.file, ':', CAST(frame.line AS STRING))
                    FROM UNNEST(exceptions[OFFSET(0)].frames) AS frame
                    WHERE frame.file IS NOT NULL
                    LIMIT 10
                ) AS stack_frames
            )
            ORDER BY event_timestamp DESC
            LIMIT 3
        ) AS recent_examples
    FROM `{table}*`
    WHERE
        _TABLE_SUFFIX BETWEEN
            FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL {days} DAY))
            AND FORMAT_DATE('%Y%m%d', CURRENT_DATE())
        AND is_fatal = TRUE
    GROUP BY issue_id, issue_title, issue_subtitle
    ORDER BY crash_count DESC
    LIMIT 10
    """
 
    results = client.query(query).result()
    return [dict(row) for row in results]
 
if __name__ == "__main__":
    crashes = get_top_crashes(
        project_id="your-firebase-project-id",
        app_id="1:000000000000:ios:aaaaaaaaaaaaaaaa"  # 実際のapp_idに変更
    )
    for crash in crashes:
        print(f"[{crash['crash_count']}件] {crash['issue_title']}")
    # 出力例:
    # [247件] Fatal Exception: NSInvalidArgumentException
    # [89件] Fatal Exception: EXC_BAD_ACCESS SIGSEGV

google-cloud-bigquery はpipで導入できます。Google Cloud SDKの認証は gcloud auth application-default login で通しておいてください。

クラッシュデータをAntigravityに渡すプロンプトを整形する

取得したデータをAntigravityに渡す際のポイントは「ただ貼り付けるだけ」ではなく、AIが判断しやすい構造で渡すことです。スタックトレースの前後に文脈(件数・デバイス傾向・質問形式)を添えることで、解析精度が大きく変わります。

# crash_analyzer.py
from crash_fetcher import get_top_crashes
 
def format_crash_for_ai(crash: dict) -> str:
    """
    Antigravityへのプロンプトとして、Crashlyticsレポートを構造化する。
    スタックトレースに件数・デバイス情報・具体的な質問を添えることが精度向上のカギ。
    """
    examples = crash.get("recent_examples", [])
 
    # 上位デバイス・OS情報をまとめる
    devices = list({
        f"{ex['manufacturer']} {ex['model']} (OS {ex['os_version']})"
        for ex in examples
        if ex.get("manufacturer")
    })[:3]
 
    # 最新クラッシュのスタックトレース(先頭10フレーム)
    stack_frames = []
    if examples and examples[0].get("stack_frames"):
        stack_frames = examples[0]["stack_frames"]
 
    prompt = f"""
## Crashlyticsクラッシュ解析依頼
 
**発生件数(直近7日):** {crash['crash_count']}
**エラータイプ:** {crash['issue_title']}
**サブタイトル:** {crash.get('issue_subtitle', 'N/A')}
**主な発生環境:** {', '.join(devices) if devices else '不明'}
 
**スタックトレース(最新クラッシュ・先頭10フレーム):**
{chr(10).join(f'  {i+1}. {frame}' for i, frame in enumerate(stack_frames))}
 
**依頼事項:**
1. このクラッシュの根本原因として最も可能性の高い箇所を特定してください
2. コードベース内で修正すべきファイル・メソッドを示してください
3. 修正アプローチを3つ提案してください(優先度順)
4. 最小再現手順を推測してください
"""
    return prompt
 
if __name__ == "__main__":
    crashes = get_top_crashes("your-firebase-project-id", "1:000000000000:ios:aaaaaaaaaaaaaaaa")
 
    # 上位3件をAntigravityに渡すプロンプトとして出力
    for i, crash in enumerate(crashes[:3], 1):
        print(f"\n{'=' * 60}\n### クラッシュ #{i}")
        print(format_crash_for_ai(crash))

このスクリプトの出力をAntigravityのチャット欄に貼り付けて送信すると、Antigravityがコードベースを自動検索して原因箇所と修正案を返してくれます。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
件数ではなくユーザー影響度(installation_uuidの重複排除)でクラッシュをトリアージする実装
iOSとAndroid双方のスタックトレースをAntigravityに渡す前に整形する具体的なコード
導入前後のクラッシュフリー率と対応時間の実測値、そしてAIクラッシュ解析で陥る3つの落とし穴
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

Agents & Manager2026-05-18
Crashlyticsの毎朝トリアージを5つのAntigravityサブエージェントに分担させた話
個人で6本のアプリを運営している中で毎朝のクラッシュトリアージが負担になり、Antigravityのサブエージェント5つに責務を分割しました。Fetcher/Classifier/Repro/Patch/PRの各段で人間レビューの境界線をどこに置いたかを、二週間の実運用データと合わせて記録します。
アプリ開発2026-07-03
ダウンロードサイズの逆行に提出直前で気づかないために — AAB/IPA のサイズ予算をエージェントの週次ゲートで守る
メディエーションSDKやアセットの追加で静かに膨らむダウンロードサイズに、bundletool と App Thinning レポートを使ったサイズ台帳・予算ゲート・増分の内訳特定で歯止めをかける設計をまとめます。
アプリ開発2026-06-22
壁紙ビューアのスライドショーとページ送りスクラバーを iOS から Android へ逆移植する — SnapHelper との双方向同期でつまずいた点
iOS 版の全画面壁紙ビューアにあったスライドショーと下部スクラバーを Android へ逆移植した実装記録。RecyclerView と SnapHelper で現在ページを確定させ、スクラバーと双方向同期し、自動送りとユーザー操作の競合を状態機械で解いた手順を Kotlin の動くコードで共有します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →