FlutterアプリでSentryとFirebase Crashlyticsにエラーレポートを送りアプリの品質改善に役立てる
Flutterアプリとしてエラーは大きく2種類あります。
- Flutter/Dart側で起きるエラー
- ネイティブ(Android/iOS)側で起きるエラー
今回は、1をSentryで、2をFirebase Crashlyticsで収集します。本当はどちらともFirebase Crashlyticsで収集したかったのですが、Crashlyticsのほうは、iOSで同じエラーでも以下のように別々のエラーとして扱われてしまったのでSentryとCrashlyticsを使っています。同じように扱える場合は、Crashlyticsで統一したいですね(ここ解決する方法しっていたら教えてください)。
Sentryの導入
まずあらかじめSentryでアカウントを作っておきます。Sentryには、Organization, Projectという概念があり、Organizationが複数のProjectをもっているという感じです。初めてアカウントを作ったときに、まずOrganizationを作り、その後に環境(production, developmentなど)に応じて複数Projectを作るといいと思います。
Organizationは、ページの左上のSwitch organization
=>Create a new organization
から作成でき、Projectは、OrganizationページのSettings
=>Project
から作成できます。
SentryはReport errors to a serviceで公式にエラーレポートの導入の仕方を説明しているので、この通りに導入すれば大丈夫です。今回は、2.2.0
のバージョンを入れました。
ドキュメントではrunZoned
を使って、runApp
をラップしています。Zoneは、runApp
実行中に起きたハンドリングできなかったエラーをハンドルして、Sentryなどにエラー情報を送ることができます。try-catch
とは違って、runApp
を終了せずにそのまま実行できます。
なにか適当なボタンのタップイベントなどにthrow FlutterError('err');
とかいてエラーを起こさせます。そうするとSentryで以下のようなIssueが生成されます。
ドキュメントのままでは、エラーログとしの情報が足りないので以下の情報をつけて送れるようにします。
- OSの種類とバージョン
- アプリのバージョン
- productionやdevelopmentなどの環境名
- ユーザの情報
SentryはSentryClient
を初期化するときにEvent
というイベントを送るときに付属させる情報を定義できるので以下のように上記の情報をつけます。
final version
final sentry = new SentryClient(
dsn: 'SentryのDNS',
environmentAttributes: Event(
release: version,
environment: 'production',
tags: {
'os': deviceInfo.os,
'osVersion': deviceInfo.osVersion,
'model': deviceInfo.model,
},
),
);
version
はpackage_infoのPackageInfoを'${packageInfo.version} (${packageInfo.buildNumber})';
ようにして取得しています。
deviceInfoは、device_infoから以下のように定義して_deviceName()
から取得しています。
class _DeviceInfo {
var os = '';
var osVersion = '';
var model = '';
_DeviceInfo({
this.os,
this.osVersion,
this.model,
});
}
Future<_DeviceInfo> _deviceName() async {
final deviceInfo = _DeviceInfo(
os: Platform.operatingSystem,
);
final deviceInfoPlugin = DeviceInfoPlugin();
if (Platform.isAndroid) {
final androidInfo = await deviceInfoPlugin.androidInfo;
deviceInfo.model = androidInfo.model;
// ignore: cascade_invocations
deviceInfo.osVersion = androidInfo.version.release;
} else if (Platform.isIOS) {
final iosInfo = await deviceInfoPlugin.iosInfo;
deviceInfo.model = iosInfo.name;
// ignore: cascade_invocations
deviceInfo.osVersion = iosInfo.systemVersion;
}
return deviceInfo;
}
ちなみに、device_info
はAndroid/iOS各以下のように端末の情報がとれます。
device_infoのAndroidの端末情報
device_infoのiOSの端末情報
ユーザの情報に関しては以下のようにSentryで定義されているUser
をuserContext
に代入します。
sentry.userContext = User(id: 123);
このように設定してからSentryにエラーを送ると、以下のように各種付属した情報がSentryにでます。これで端末情報などでしぼりこめるので、エラーの原因解明がはかどります。
(注意: 実際のアプリで実装したコードなので、ソースコードの値とは若干ことなります)
これでFlutter/Dart側で起きたエラーはSentryでエラーレポートがみれるようになりました。
Firebase Crashlyticsの導入
ネイティブ(Android/iOS)のコードがクラッシュしたときのエラーレポートはCrashlyticsで取得することにします。まずはFirebase Crashlyticsを設定します。FirebaseのコンソールのQualityにあるCrashlyticsを選んでから以下を選んでおきます。
Flutterのパッケージとして、flutter_crashlyticsを使用します。このパッケージはFirebase Crashlyticsの場合と、Fabricから移行したCrashlyticsの場合で、設定が若干ことなるのですが、今回はFirebase Crashlyticsを使った場合を説明します。
pubspec.yaml
のdependencies
に以下を追加します。今回、kiwi-bop/flutter_crashlyticsをforkして、このコミットだけを行ったものをパッケージとして使ってます。fatal error: 'Fabric.h' file not found
というエラーがでたので、Issueに記載されている修正をしました。
flutter_crashlytics:
git:
url: https://github.com/wapa5pow/flutter_crashlytics.git
ref: f0b5f56d1bcaae4e352991437a29ebc65ae6ef50
パッケージを導入したら、Crashlyticsにエラーレポートを送れるように以下のように設定します。
Android側
apply plugin: 'com.android.application'
apply plugin: 'io.fabric' // <= 追記
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
repositories {
...
maven { url 'https://maven.fabric.io/public' } // <= 追記
}
dependencies {
...
classpath 'io.fabric.tools:gradle:1.+' // <= 追記
...
}
iOS側
Run Scriptを追加する必要があるので以下のように左上の+
ボタンから追加します。READMEにはFabricのAPIキーを引数として設定してますが、Firebase Crashlyticsの場合はいりません。
Flutter側
main.dartに以下のように記載してCrashlyticsを初期化します。環境を設定している部分は必要なら記載してください。setInfo
でSentryのタグみたいに独自情報を付属できます。
await FlutterCrashlytics().initialize();
await FlutterCrashlytics().setInfo('environment', 'production';
終わったらネイティブ連携など適当な部分でクラッシュさせてログがでているか確かめます。
まとめ
SentryとFirebase Crashlyticsを使いFlutterアプリのクラッシュしたときやハンドルしていない例外がでたときにエラーレポートを送ることができるようになりました。アプリのバージョンやOSなど細かい情報も入れられるので、ユーザからお問い合わせがあったときも対応しやすくなりアプリの品質が高められますのでまだエラーレポートを入れていないFlutterアプリがある場合はぜひためしてみてください。