Firebase CrashlyticsをXamarin.Formsアプリで使ってみたら色々と難ありだった

これは [Xamarin Advent Calendar 2018](https://qiita.com/advent-calendar/2018/xamarin) の4日目の記事です。

Firebaseの [Crashlytics](https://firebase.google.com/docs/crashlytics/) が使えるようになったとのことで、Xamarin.Formsなアプリに導入してみました。結構手こずったため試行錯誤が足りずイマイチ正解が見えていませんが、動いたので共有します。

## 対象
新規作成したXamarin.Formsプロジェクト。
（Formsは最新に更新）

## 環境
検証したのが11月末のため、記事公開時点でVisual Studioは1個前のバージョンです。

|コンポーネント|バージョン|
|-----------------:|:------------------|
|macOS|Mojave(10.14.1)|
|Visual Studio for Mac|7.6.11 (build 9)|
|Xcode|10.1|
|Xamarin.iOS|12.2.1.10|
|Android SDK Tools|26.1.1|
|Android SDK Platform-Tools|28.0.0|
|Android SDK Build Tools|28.0.2|
|Android SDK|8.1|
|Java SDK|1.8.0_192|
|Xamarin.Android|9.0.0.20|

## 準備
明日の @f-miyu さんがFirebaseを使うあたりのことを書かれるとのことで、ざくっと言うと
1. FirebaseのコンソールでiOS、Androidそれぞれのアプリプロジェクトを作成する
2. plistやjsonの定義ファイルをダウンロードし、プロジェクトに組み込む
3. iOS、AndroidそれぞれのプロジェクトにFirebase.CoreなNugetパッケージを組み込む
4. アプリを起動する
という感じです。アプリを起動したときFirebaseに（たぶんAnalyticsの）情報が届くと、Firebaseコンソールのほうで導入が成功した表示がされます。

ここまで来たら、FirebaseのコンソールでそれぞれのプロジェクトからCrashlyticsを有効にします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/96859/903b175b-c986-034f-d1b7-6e3cfe8018d1.png)


ここまできたら、いよいよ本番です。

## Xamarin.Formsの画面にボタンを追加して押したら例外をスローするようにする

動作確認用のクラッシュとして単に例外をスローしてみます。

```xml:MainPage.xaml
<Button Text="Crash!" Clicked="OnClickedCrash" />
```

```csharp:MainPage.xaml.cs
void OnClickedCrash(object sender, System.EventArgs e)
{
    throw new InvalidOperationException("Hello Crashlytics!");
}
```

「Crash!」ボタンを押すとクラッシュしますが、当然ながらまだCrashlyticsには何も届きません。

ちなみにCrasylyticsには動作確認用のCrashメソッドが用意されているためこれを使っても良かったのですが、これをFormsから呼ぶにはDependencyServiceを経由しないといけないし、ネイティブでのクラッシュになり話がややこしくなるため今回は手抜きです。

## Xamarin.FormsのiOSアプリにCrashyticsを導入する

公式ドキュメント[Get Started with Firebase Crashlytics for iOS](https://github.com/xamarin/GoogleApisForiOSComponents/blob/master/Firebase.Crashlytics/component/GettingStarted.md)を参考にしましたが、なぜか色々と違いました。

iOSプロジェクトは以下のようにしました。

1. Xamarin.Firebase.iOS.Crashlyticsを追加する
2. AppDelegate.csのFinishedLaunchingにCrashlyticsの初期化を追加する
3. Xamarin.Firebase.iOS.Analyticsの4.0.5を追加する
4. AppDelegate.csのFinishedLaunchingにFirebase.Coreの初期化を追加する

１と２のみで動く・・・と予想していたのですが、ハマったところはこのあたりです。

- Xamarin.Firebase.iOS.Analyticsを追加せずにXamarin.Firebase.iOS.Crashlyticsのみの場合
    - クラッシュさせてもCrashlyticsのコンソールに届きませんでした。
    - クラッシュ→アプリ再起動、で通常はクラッシュログが送信されます。
- Xamarin.Firebase.iOS.Analyticsを追加した（＝最新の5.1.4）場合
    - [ビルドに失敗しました](https://github.com/xamarin/GoogleApisForiOSComponents/issues/158)
    - ただ色々試しているときにビルドが通ったこともあり少し謎です...。
- 初期化コードがCrashlyticsのみの場合
    - クラッシュさせてもCrashlyticsのコンソールに届きませんでした。

Xamarin.Firebase.iOS.Crashlyticsの依存関係には改善の余地があるのかも、と思っています。

初期化コードはこうなりました。

```csharp:MainPage.xaml.cs
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    Firebase.Core.App.Configure();
    Firebase.Crashlytics.Crashlytics.Configure();

    // ：（以下、元のコード）
}
```

これでアプリを起動してしばらくすると、何か初期化が届くのかFirebaseのコンソール（虫網ボーイの表示）がこうなります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/96859/cc4533d3-1a08-a94d-da3b-ff2209a52984.png)



## Xamarin.FormsのiOSアプリから送信されたクラッシュログの例

このようなメールが届きます。
MainPage.xaml.csに書いた「Crash!」ボタンによるInvalidOperationExceptionということは全然想像が付きません。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/96859/839d3603-dd46-19d1-a60a-2bed49506099.png)

でも詳細を見るとスタックトレースには現れていました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/96859/817d98f4-8ef9-1aab-7079-e89f7c62ce9f.png)

よかったよかった。

・・・だけど「ログ」が空です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/96859/145bc3db-17bf-ddfd-1e35-dbbdbd5f1cb3.png)

Analyticsによる画面遷移の記録が載るはず、と思っていたのですがFormsはPageだからキビしかったかな・・・？（自力でFirebase Analyticsで画面名を送信する対応が必要になります）


## Xamarin.FormsのAndroidアプリにCrashyticsを導入する

公式ドキュメントは[こちら](https://github.com/xamarin/XamarinComponents/blob/master/Android/Crashlytics/README.md)

Androidプロジェクトは以下のようにしました。
結構色々とワケ分からん感じでした。

1. Xamarin.Android.Crashlyticsを追加する
2. MainActivity.csのOnCreateにCrashlyticsの初期化を追加する
3. 足りないライブラリを追加する
    - Xamarin.Android.Crashlytics.Answers
    - Xamarin.Android.Crashlytics.Beta
    - Xamarin.Android.Crashlytics.Core
    - Xamarin.Firebase.Core
    - これらを入れないと何かが足りないからとアプリが起動しませんでした。そういうもの…？。
4. Xamarin.Build.Downloadを0.4.12-preview3に上げる
    - [同様のアプリを複数インストールするとProviderが被って起動しなくなる不具合](https://github.com/xamarin/XamarinComponents/issues/444)の回避です。
5. strings.xmlにcom.crashlytics.android.build_idを追加する
6. AndroidManifest.xmlにfirebase_crashlytics_collection_enabled(=false)を追加する
7. アプリを起動する
8. AndroidManifest.xmlのfirebase_crashlytics_collection_enabledをtrueに変更する
9. アプリを起動する

５をしないと、落ちます（例外忘れた）。

６（と７）を飛ばすと、このようなエラーで落ちます。

```
E AndroidRuntime: io.fabric.sdk.android.services.concurrency.UnmetDependencyException: This app relies on Crashlytics. Please sign up for access at https://fabric.io/sign_up,
E AndroidRuntime: install an Android build tool and ask a team member to invite you to this app's organization.
```

まさか今さら登録が必要なのか？と思ったのですが、特にFabricのサイトを使う必要はなかったです。


## Xamarin.FormsのAndroidアプリから送信されたクラッシュログの例

このようなメールが届きます。
そのファイル名はForms側なのでは、と思ってしまいます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/96859/18feb8bc-713c-f7ff-1e67-9b1d3daa2713.png)

詳細が思ったような感じではありませんが・・・
![image.png](https://qiita-image-store.s3.amazonaws.com/0/96859/ac0dbf7f-03c0-8764-8697-0e9a1698e960.png)

よく見ると、それっぽい事が書いてありました。
行番号がないので少し不安です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/96859/bce5f327-3abc-5dab-619b-ab89ec57abd1.png)

ログも１つ出ていました。
ただ結局PageではMainActivityのままなので、画面名は送信しないといけないでしょうね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/96859/b293535a-23ca-7169-6a7e-c35837364dca.png)

## 参考：普通のAndroidアプリでクラッシュさせたログ

Android Studioで普通に作ったアプリからCrashlyticsのテスト用API、crash()で落とした時のログです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/96859/cf340515-32f3-29b1-0e61-5002353f9c82.png)
↑これが、こう↓
![image.png](https://qiita-image-store.s3.amazonaws.com/0/96859/162f37d9-6e8d-c0c1-a8f8-87258e75e3da.png)

行番号も出ているし、さすが、良い感じです。

（ちなみに普通のiOSのほうはCocoaPodsがうまく使えなくて挫折中です）

## まとめ
Xamarin.FormsでFirebaseのCrashlyticsは使えます。
ただいくつか難があり本番環境ではケアが必要です。

- 画面名やイベント（ボタン押下など）を自力で送信するようにしておかないと「ログ」が寂しくなります
- スタックトレースが意味不明な場合もありそうです

iOSやAndroid側の目新しいものをXamarinで使おうとするのはイバラの道ですね。
（Xamarin.Android.CrashlyticsのNugetパッケージが出たのは9月です）

## 課題（残件）
Crashlytics自体の話ですが、ストアに届くクラッシュログとの関係が良く分かっていません。
こっちを有効にするとストアには届かなくなるのか？など。
またチームで開発している場合、Crashlyticsに届いた内容をどう周知すると良いのだろうとか。
まだまだ不明点が多いです。

---

明日は @f-miyu さんです。よろしくお願いします！