Firebase crashの導入Tips（Android編）

実際にFirebase crashをAndroidアプリに組み込む際に知っておくと便利（だと思う）ことを記載します。
いままではCrashlyticsを使っていたので（これからも使うんですけど）、そちらと比べての説明になります。

Firebase crashの導入方法に関しては省略します。

## 注意：Google Play Serviceのない端末では動作しない

Firebase crashのクラッシュレポートは、`FirebaseCrashSenderService`クラスを通して行われるのですが、このクラス内で `com.google.android.gms` パッケージのクラスを利用するため、Google Play Serviceのない端末だとNameNotFoundExceptionを起こしてしまい、クラッシュレポートが送信されません。

ログ：https://gist.github.com/yamacraft/20a713a23ccd8a810d76f22406fc4ff7

このため、Kindleや中華タブレットといった端末での利用を対象としたアプリの導入は現状不可能です。

## try〜catchでもクラッシュレポートを送りたい（アプリクラッシュ以外でも送信したい）

Crashlyticsでは `Crashlytics.getInstance().core.logException(Throwable throwable)` を呼び出すことでクラッシュレポートを送信することができましたが、Firebase crashでも`FirebaseCrash.report(Throwable throwable)`で「非致命的エラー」として送信することができます。

![スクリーンショット_2016-07-05_17_40_58.png](https://qiita-image-store.s3.amazonaws.com/0/4560/45415848-0ded-1c01-3f1d-4904224c8be6.png "スクリーンショット_2016-07-05_17_40_58.png")

※ 赤枠で囲んだ部分


あわせて `FirebaseCrash.log(String message)` を使ってクラッシュレポート用にログを溜め、クラッシュレポート送信時にログを送ることも可能です。

![スクリーンショット 2016-07-05 17.43.22.png](https://qiita-image-store.s3.amazonaws.com/0/4560/2ce430af-06dc-ddc0-6e3d-2ebd903e6a26.png "スクリーンショット 2016-07-05 17.43.22.png")

※ ためこんで送信したログの内容


自分は以前からTimberを利用して「開発中はLogCat表示、リリース時は一定以上のログのみをCrashlyticsのログに溜め、`Timber.e()`時に送信」という形で実装したので、以下のようなTimber.Treeクラスを作って利用しています。


```java:TimberTree.java
private static class CrashReportingTree extends Timber.Tree {
    @Override
    protected void log(int priority, String tag, String message, Throwable t) {
        if (priority == Log.VERBOSE || priority == Log.DEBUG) {
            return;
        }
        if (priority != Log.ERROR) {
            Crashlytics.getInstance().core.log(message);
            FirebaseCrash.log(message);
            return;
        }
        Throwable throwable = t;
        if (throwable == null && !TextUtils.isEmpty(message)) {
            throwable = new Exception(message);
        }
        Crashlytics.getInstance().core.logException(throwable);
        FirebaseCrash.report(throwable);
    }
}
```

これで必要なcatch箇所で `Timber.e() `することで、アプリがクラッシュしないタイミングでも、レポートを送信することができます。

### 参考：Timberについて

- [JakeWharton/timber: A logger with a small, extensible API which provides utility on top of Android's normal Log class.](https://github.com/JakeWharton/timber)
- [Androidのログ出力をいい感じにする #potatotips 9 // Speaker Deck](https://speakerdeck.com/cutmail/androidfalseroguchu-li-woiigan-zinisuru-number-potatotips-9)



## proguard設定時に正しくエラー箇所を特定できるようにしたい

「try〜catchでもクラッシュレポートを送りたい」のコンソール画面にも少し出てきていますが、難読化（proguard）をかけてしまうとスタックトレースが正しく取得できません。そのため、設定ファイルに以下を記述する必要があります。

```pro:proguard-rules.pro
-keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable
-keep public class * extends java.lang.Exception
-printmapping mapping.txt
```

実際には上の３行、というより `-keepattributes SourceFile,LineNumberTable` だけで良いような気がしますが、全部入れておきましょう。[Crashlyticsも同様の設定を指定しています](https://docs.fabric.io/android/crashlytics/dex-and-proguard.html)。

一番下は、スタックトレース補助用のマッピングファイル生成の設定になります。`app/build/outputs/mapping/release/` 辺りに `mapping.txt`として生成されるので、Firebaseのコンソール画面にアップロードしましょう。

![スクリーンショット 2016-07-05 18.48.35.png](https://qiita-image-store.s3.amazonaws.com/0/4560/56809df7-1a97-fe26-5332-eb9eb03f209b.png "スクリーンショット 2016-07-05 18.48.35.png")

とはいえ、これを毎回やるのはめんどくさいことこの上ないので、APIがあればCIからアップロードさせたいですね……（未調査）

## ライブラリ導入によって増加するapk容量

サンプルプロジェクトに対して「何も追加しない」「gmsだけ追加」「firebase crash
まで追加」の3種類でrelase-apkを作ったみた比較です。
`minifyEnabled=true` しています。

|条件|容量(byte)|
|:---|---:|
|何も追加しない|887,244|
|gmsだけ追加|1,696,813|
|firebase crashまで追加|1,710,199|

firebase crash自体は15k程度ですが、gms自体は800kほど増えているのがわかりました。

以上です。