[Xamarin.Forms] Firebase Crashlytics を導入してみた (Android & iOS)

以前、Xamarin.FormsアプリにFirebase Analyticsを導入してみましたが、せっかくなので、Firebase Crashlyticsも追加導入してみました。

  • Q:なぜXamarin?
  • A:趣味です!

目次

環境

  • Windows
    • Windows 10 Pro
    • Visual Studio Community 2019 (16.1.5)
  • macOS
    • macOS Mojave (10.14.5)
    • Visutal Studio Community 2019 for Mac (8.1.3)
    • Xcode (10.2.1)
  • Android
    • Pixel 3a (Android 9)
  • iOS
    • iPhone 7 (12.2)
    • iPhone Xs Simulator (12.2)
  • Xamarin
    • Xamarin 16.1.0.545
    • Xamarin.Android SDK 9.3.0.23
    • Xamarin.iOS and Xamarin.Mac SDK 12.10.0.157
  • Library
    • 共通
      • Xamarin.Forms: 4.0.0.425677
    • Android
      • Xamarin.Android.Crashlytics: 2.9.4.1
      • Xamarin.Android.Crashlytics.Answers: 1.4.2
      • Xamarin.Android.Crashlytics.Beta: 1.2.9
      • Xamarin.Android.Crashlytics.Core: 2.6.3
      • Xamarin.Android.Fabric: 1.4.3
      • Xamarin.Firebase.Analytics: 60.1142.1
      • Xamarin.Firebase.Analytics.Impl: 60.1142.1
      • Xamarin.Firebase.Common: 60.1142.1
      • Xamarin.Firebase.Core: 60.1142.1
      • Xamarin.Firebase.Iid: 60.1142.1
      • Xamarin.GooglePlayServices.Basement: 60.1142.1
      • Xamarin.GooglePlayServices.Tasks: 60.1142.1
    • iOS
      • Xamarin.Firebase.iOS.Analytics: 5.5.0
      • Xamarin.Firebase.iOS.Crashlytics: 3.10.9

Xamarin.Formsアプリの作成とFirebaseプロジェクトの作成

下記で作成したXamarin.FormsアプリとFirebaseプロジェクトを流用します。

Xamarin.FormsアプリにFirebase Analyticsを導入してみたので、手順をまとめた! (Android & iOS)

Androidの準備

Firebase Crashlyticsの導入(Android)

NuGetで下記のライブラリをAndroidプロジェクトに追加します。

  • Xamarin.Android.Crashlytics

strings.xmlにユニークIDを追加

Resources/values/strings.xmlを新規作成し、下記を追加します。

アプリとバージョンを特定するためのユニークなIDのため、BundleIDとバージョンにしています。

<resources>
  <string name="com.crashlytics.android.build_id">com.companyname.FASample.v1.0.0</string>
</resources>

Firebase Crashlyticsの初期化(Android)

MainActivity.csOnCreate()に初期化コードを追記します。

protected override void OnCreate(Bundle savedInstanceState)
{
    TabLayoutResource = Resource.Layout.Tabbar;
    ToolbarResource = Resource.Layout.Toolbar;

    AnalyticsSingleton.GetInstance.Analytics = FirebaseAnalytics.GetInstance(this);
    AnalyticsSingleton.GetInstance.Activity = this;

    Fabric.Fabric.With(this, new Crashlytics.Crashlytics());
    Crashlytics.Crashlytics.HandleManagedExceptions();

    base.OnCreate(savedInstanceState);

    Xamarin.Essentials.Platform.Init(this, savedInstanceState);
    global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
    LoadApplication(new App());
}

Firebaseプロジェクト設定(Android)

Firebase Consoleにアクセスし、アプリが追加されているプロジェクトを選択したのち、「Crashlytics」を選択します。

FirebaseでCrashlyticsを選択する

続いて、Androidアプリを選択します。

Androidアプリを選択する

「いいえ」を選択して「次へ」を選択します。

「いいえ」を選択して次に進む

「ドキュメントに移動」を選択します。(そうしないと進めない)

ドキュメントに移動を選択する

待機画面でいったん放置します。

待機画面で放置する

アプリの実行と接続確認(Android)

ビルドエラー対応

下記のビルドエラーが発生したので、NuGetでライブラリを追加導入します。(私のWindows環境だと、ビルドエラーが文字化けしてました……)

error: package io.fabric.sdk.android.services.events does not exist
		io.fabric.sdk.android.services.events.EventsStorageListener
  • Xamarin.Android.Crashlytics
  • Xamarin.Android.Crashlytics.Answers
  • Xamarin.Android.Fabric
  • Xamarin.Android.Crashlytics.Beta
  • Xamarin.Firebase.Analytics
  • Xamarin.Firebase.Analytics.Impl
  • Xamarin.Firebase.Common
  • Xamarin.Firebase.Core
  • Xamarin.Firebase.Iid
  • Xamarin.GooglePlayServices.Basement
  • Xamarin.GooglePlayServices.Tasks

参考: Xamarin.Android.Crashlytics error: package io.fabric.sdk.android.services.events #460 | GitHub Issues

例外発生してアプリが落ちる

Androidアプリを実行すると、例外発生しました……。

Androidアプリを実行すると、例外発生した

Unhandled Exception:
Java.Lang.NoClassDefFoundError: <Timeout exceeded getting exception details>
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/crashlytics/android/core/CrashlyticsCore;

Caused by: java.lang.ClassNotFoundException: Didn't find class "com.crashlytics.android.core.CrashlyticsCore" on path: DexPathList[[zip file "/data/app/com.companyname.FASample-Jn4wnhxxnT4aX8IyEn33SQ==/base.apk"],nativeLibraryDirectories=[/data/app/com.companyname.FASample-Jn4wnhxxnT4aX8IyEn33SQ==/lib/arm64, /data/app/com.companyname.FASample-Jn4wnhxxnT4aX8IyEn33SQ==/base.apk!/lib/arm64-v8a, /system/lib64, /system/product/lib64]]

これに対処するため、NuGetから下記のライブラリを追加します。

  • Xamarin.Android.Crashlytics.Core

参考: Xamarin.Android.Crashlytics 2.9.4.1 - NoClassDefFoundError on CrashlyticsCore #455 | GitHub Issues

改めてアプリを実行する

接続成功しました!!!!

怪しい場合は、リビルド・Visual Studioを再起動・アプリの再インストールを試してみてください。

Firebase Crashlyticsに接続成功

iOSの準備

Firebase Crashlyticsの導入(iOS)

NuGetで下記のライブラリをiOSプロジェクトに追加します。

  • Xamarin.Firebase.iOS.Crashlytics

Firebase Crashlyticsの初期化(iOS)

AppDelegate.csFinishedLaunching()に初期化コードを追記します。

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    // https://github.com/xamarin/GoogleApisForiOSComponents/issues/158#issuecomment-483194061
    var foo = Firebase.Core.Configuration.SharedInstance;

    Firebase.Core.App.Configure();
    Firebase.Crashlytics.Crashlytics.Configure();

    global::Xamarin.Forms.Forms.Init();
    LoadApplication(new App());

    return base.FinishedLaunching(app, options);
}

Firebaseプロジェクト設定(iOS)

アプリの種類をiOSに変更します。

アプリの種類をiOSに変更する

Androidと同じ手順でポチポチし、待機画面を表示しておきます。

アプリの実行と接続確認(iOS)

iOSは素直にビルド&実行できました!!

Firebase Crashlyticsに接続成功

Crashのテスト

Xamarin.Formsコードの追加

Xamarin.Formsの画面にボタンを追加し、それを押すと強制的にCrashさせてみます。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="FASample.MainPage">

    <StackLayout VerticalOptions="Center">
        <Label Text="Welcome to Xamarin.Forms!" 
               HorizontalOptions="Center"
               VerticalOptions="Center"/>
        <Button Text="send event"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                Clicked="Button_OnClicked" />
        <Button Text="crash!!"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                Clicked="Button_Crash_Clicked"/>
    </StackLayout>

</ContentPage>
private void Button_Crash_Clicked(object sender, EventArgs e)
{
    throw new NotImplementedException("this is crash test!!!");
}

Crashのテスト(Android)

アプリを通常実行し(デバッグ実行だと通知来ないっぽい?)、画面の「crash!!」ボタンを押します。

アプリが強制終了したら、アプリを再び起動します。(次に起動した際にクラッシュレポートが送信されるため)

数分待つと、画面にクラッシュ情報が表示されました!

AndroidのCrashレポート

詳細はこんな感じになってます!

Androidのクラッシュレポート詳細

Crashのテスト(iOS)

iOSも、Androidと同じように通常実行し、「crash!!」ボタンを押します。 (アプリが終了するまで時間が掛かりました……)

すると、「dSYMをアップロードしてね」と言われました。

「dSYMをアップロードしてね」が表示された

dSYMファイルの取得(エミュレータビルド)

下記を参考に取得しようと頑張りました。

私の場合は、「dSYMファイル」は存在していなかったので、下記のように「IPAをビルドする」設定を有効にし、「FASample.iOSのリビルド」を実行しました。

iOSでIPAファイルを作成する

すると今度は「そんなprovisioningないよ」と怒られました。

error : Could not find any available provisioning profiles for iOS.

「なんちゃってBundleIDで実機リリースビルド」は流石に無理でした……。

dSYMファイルの取得(実機ビルド)

というわけで、BundleIDをちゃんと登録し、やり直しました。 (ここから先は有料会員パワー発動です)

  • FirebaseプロジェクトにiOSアプリ追加
  • GoogleService-Info.plistの更新
  • Crashlyticsの登録
  • アプリ起動し、Crashさせる

すると、、、なんということでしょう、、、「dSYMファイル」が無くても表示されました!!!

「dSYMファイル」が無くても表示された

エラー行もいい感じです。

「dSYMファイル」が無くても表示された(詳細)

ついでに、「dSYMファイル」ぽいものはできてました。

dSYMっぽいのもは出来ていた

おまけ

簡単に試したところ、「iPhone実機」の場合に「dSYMファイル」は必要ありませんでした。

種類 対象 dSYMファイルは必要?
Debug iOSシミュレータ Yes
Debug iPhone実機 No
Release iOSシミュレータ Yes
Release iPhone実機 No

なお、iOSシミュレータの場合に「dSYMファイル」は生成されませんでした。

やはりiOSは実機が安心ですね……! (個人の感想です)

他の機能

今回は試しませんが、Firebase Crashlyticsには下記などの機能もあります。

  • 任意のカスタムキーを追加(Key-Value)
  • ユーザIDを設定
  • カスタムログメッセージを追加
  • 致命的でない例外をログに記録

これらをうまく使えば、

  • ユーザ毎の傾向は?
  • 設定値の状態は?

といった情報も把握できそうです。

さいごに

簡単だと思ってましたが、一筋縄では行きませんでした……。

ビルドエラー等と戦いながら試したので、その記録も残しています。 どなたかの参考になれば幸いです。

参考