AndroidアプリにCrashlyticsを導入してクラッシュフリーユーザー率99.9%を目指す話


みなさん、こんにちは。空中清高です。
この記事は  [JustSystems Advent Calendar 2017](https://qiita.com/advent-calendar/2017/justsystems) の 3日目の記事です。

# はじめに

今日書くのは、スマイルゼミ中学生コースのクライアントアプリ(Android App)にCrashlyticsを導入して**30日間でのクラッシュフリー率99.9%**を目指す話です。

# Crashlyticsって？

Androidアプリに導入することでクラッシュを自動検出し、バグレポートしてくれるサービスです。
これを利用することで、今日は何件、どんなクラッシュが発生したか、を把握することが可能になります。
Google Developersの記事に詳しく載ってます。
https://developers-jp.googleblog.com/2017/10/7-tips-for-getting-most-out-of.html

# クラッシュフリーユーザー率って？

アプリを利用したユーザーがクラッシュに遭遇しなかった率です。
これは計測期間が長くなると低下する傾向にあります。
同一ユーザーのアプリ利用日数が増加するのでクラッシュに遭遇する率も増加するためです。

# なぜクラッシュフリーユーザー率を高くするの？

ユーザーが増加するほどクラッシュフリーユーザー率は重要な数値になります。
たとえばクラッシュフリーユーザー率が95%だとすると、アプリ利用者の5%はなんらかのクラッシュに遭遇することになります。
利用ユーザーが100人ならその5%は5人ですが、1000人の5%は50人、1万人の5%は500人といった具合にユーザーが増えるにつれ割合で人数が増えてしまいます。
ユーザーの増加に耐えるためにはユーザーの増加率に合わせてクラッシュフリーユーザー率も増加させる必要があります。

# クラッシュフリーセッション率っていうのもあるよ？

たとえばユーザーが100人いるとして、全ユーザーが毎日1回利用するとします。
このときの総ユーザー数は100人、総セッション数は700になります。
毎日5%のセッションでクラッシュしたとするとクラッシュフリーセッション率は95%です。
しかしクラッシュフリーユーザー率は最低で65%、最大でも95%になります。(いつも違う人がクラッシュした場合が最低、全部同じ人だった場合が最大)
なので、クラッシュフリーセッション率よりクラッシュフリーユーザー率のほうが高い数値を出すのが難しいです。

また、アプリを利用していて100回に1回クラッシュする、というより、アプリを利用中のユーザーの100人に1人でクラッシュした、というほうが何人に影響するの？っていう感覚から深刻度がわかりやすいと思ったため、クラッシュフリーユーザー率を見ることにしました。

# なぜ30日間なの？

ホットフィックス等を除けば、アプリのリリース間隔がだいたい30日間隔なことと、7日間では短すぎる(達成が容易)なため、30日で見ることにしました。
今月のクラッシュ遭遇者は何人、といった数値のほうがわかりやすいと思ったのもあります。

# なぜ99.9%なの？

計測開始から数日時点でのどんぶり勘定予想が90%台前半でした。
99%なら頑張ればなんとかなるかも？といった感覚だったので、より高みを目指すなら99.9%だろうと思って決めました。

# 99.9%はどの程度難しいの？

一般的なアプリのクラッシュフリーユーザー率は知らないのですが、Crashlyticsを紹介したGoogle Developersの記事では7日間で93%という数値がチラ見えできたり、99%にした話は記事にされたり（[クラッシュ率が1%未満に！バグ解析からデプロイまで、Fabricでアプリ開発・運営を効率化](https://seleck.cc/503)）、Droid Kaigiで公演されたり([テスト0から目指すクラッシュフリー率99%](https://academy.realm.io/jp/posts/droidkaigi17-crash-free-application/))しているので、相当すごそうです。
個人的にも一般的なアプリでの99%は相当難しく、さらに一つ桁が下がる99.9%はかなりの好条件が揃わないと厳しいのでは？という印象があります。

# そもそも99.9%って数値は現実的ではない？

世の中の一般的なアプリでは多種多様な端末＆OSバージョンに対応する必要があり、古い端末やメーカー独自カスタマイズの入ったOSに起因するクラッシュなど、さまざまな環境で戦っています。
しかしスマイルゼミ中学生コースは専用端末を利用している性質上、端末種類やAndroid OSのバージョンが限定されるためとても有利です。
こんな有利な状況でなら、もしかしたらやれるのでは？、といった感覚です。

# それで、いつ本題が始まるの？

はい、始めます。
まずは現在までの結果から。
9月のクラッシュフリーユーザー率は95.57%
10月のクラッシュフリーユーザー率は96.53%
11月のクラッシュフリーユーザー率は97.89%

# それぞれで何をしたの?

9月の数値はこれまでの努力の結果であり、Crashlytics導入前の初期値です。
10月と11月で何をしたのか、それぞれ見ていきます。

## 10月

Android OSのLowMemoryKillerにアプリをkillされてしまったあと、正常に復帰できていないことがわかり、急いで対応しました。
また、onSaveInstanceState()後のFragment操作で発生するIllegalStateExceptionにも対応しました。
Fragment操作のだいたいのところは対応していたのですが、ViewのonClickイベントが端末スリープ後にもやってくるなど、未考慮の部分でクラッシュしていたのが発覚して対応しました。
端末スリープ後のUI操作は禁止するのにクリックイベントだけ飛んでくるの、どうにかならないですか？Google先生・・・

# 11月

10月の一部の対応が甘く、クラッシュする個所を通り抜けたけど、その先でさらにクラッシュするといったことに対応しました。
Crashlyticsでクラッシュ個所とかはわかるのですが、タイミングの問題で再現が困難だったり、そもそも再現手順が不明なクラッシュ(スリープ後にonClickがやってくる等)だったりするので、こういうこともありますね。
また10月にリリースした新機能に起因するクラッシュも発見し、その対応もしました。

# で？99%にも届いてないけど？

当初の目論見では、11月までの対応でいけると思っていたのですが甘かった・・・

# 敗因は？

実は一つ、これを潰せばいけそうってやつがあったのですが、どこで何が起きているのかわからないクラッシュで困っていました。
これのクラッシュ数が予想以上に多かった・・・・
Crashlyticsでスタックトレースが見えるのですが、そこに私たちが実装しているクラス名がどこにも出現せず、Android OS内部でクラッシュしている現象だったんです。
しかも特定の端末＆OS限定のクラッシュでした。

# 原因不明クラッシュの調査

アプリのどこで起こっているのかわからないことには手の打ちようがないため、Crashlyticsとは別の独自ログ解析システムを使って調査しました。
これはCrashlytics導入前から運用していたシステムで、より詳細なログを取得することができますが、先にユーザーを特定する必要があり、主に個別サポート用途のログ解析システムです。
このシステムとCrashlyticsの合わせ技で詳細なログを取得して調査しました。
その結果、そのクラッシュは特定のViewを表示中に発生することがわかりました。

# 発生個所がわかったら解決？

いえ、発生した場所がわかっただけで、再現手順がわからないことには・・・
ここから先はそのViewをひたすら触って再現させる地道な作業です。
考えうるあらゆる操作を試すこと数時間、ようやく同じクラッシュを再現。
さらに調査を続け、最終的に特定のViewを二本指で同時に連打することで発生することがわかりました・・・
まあ、二本指の同時連打で発生しやすいってだけで、もしかしたら普通に操作しようとしてもタイミングによっては発生する系のクラッシュなのかもしれません。

# と思ったら、やっぱり違った

そうですよね、二本指で連続タップしないと起きないクラッシュの数がこんなに多いわけ無いですよね・・
違う方法で再現できることがわかりました。
こちらはもう少し普通の操作で、詳しく書くとめっちゃ長くなるので省きますが、ScrollViewとEditTextとrequestForcusとソフトウェアキーボードが複雑に絡み合った問題でした。

これにも対応したので、12月末の計測では99%に届くはずです、たぶん・・

# 今後は？

30日間でのクラッシュフリー率99.9%を目指すことは続けます。
また、これはどこかの月で達成したら終わり、という類の目標ではなく、達成した後の維持が本番です。
俺たちの戦いはまだ始まったばかりだ・・・

# まとめ

* Crashlyticsを利用してクラッシュフリーユーザー率の計測を開始した
* クラッシュフリーユーザー率は12月時点ではまだ99%にも届いていない
* 端末スリープ後にonClickイベントが飛んでくるの勘弁して
* 特定端末向けサービスなら端末＆OS依存クラッシュもなんとかなるはず
* クラッシュフリーユーザー率の目標は達成後の維持が大事
* 俺たちの戦いはまだ始まったばかりだ・・・