さまよえる、Android

Androidのプログラミングで便利なことや残しておきたいことを残しておく。もしオススメのライブラリがあったら教えてくださいね。

AndroidのTimber(ログ系)とFabric/Crashlytics(クラッシュレポート)を使ってみた。

Log.d使うのやめよう。

ログのコメントアウトが面倒くさい。

github.com

Androidでログを出力するにはLogクラスがある。

開発中は、デバッグ目的でよく利用すよねー

リリースのときに、コメントアウトを忘れるんです。

ログ系オープンソースを探してみた結果、Timberを使ってみた。

これでリリースと開発でログの出力を分けたりすることが簡単にできる。

リリース時は、クラッシュレポートのログとして利用する。

compile 'com.jakewharton.timber:timber:4.1.0'

DebugTree

アプリが起動したら、はじめにTimberの設定をしよう。出力するログのタイプを決める。

リリースとデバッグはこの設定で切り替える。DebugTreeは標準で用意されたライブラリで、リリース目的のログクラスは、独自で作って対応する。

Timber.plant(new Timber.DebugTree());

タグを付ける。

Timber.tag("マイタグ");

ログを出力する。

Timber.e(String.format("Hello, %s %s", "Tanaka", "Hanako"));
11-01 18:34:40.376    9027-9027/? E/マイタグ﹕ Hello, Tanaka Hanako

デバッグとリリースで分ける。

各Activityで初期化するのは面倒なので、Applicationクラスでアプリ起動時に1度だけ行うこと。

if (BuildConfig.DEBUG) {
    Timber.plant(new DebugTree()); //デバッグ
} else {
    Timber.plant(new MyCrashReportingTree()); //リリース
}

MyCrashReportingTree

   private static class MyCrashReportingTree extends Timber.Tree {
        @Override
        protected void log(int priority, String tag, String message, Throwable t) {
            Log.d("タグ", tag);
            Log.d("タグ", message);

            if (priority == Log.ERROR) {
                Log.d("タグ", "エラー");
            }

            if (priority == Log.DEBUG) {
                Log.d("タグ", "デバッグ");
            }

            if (priority == Log.WARN) {
                Log.d("タグ", "警告");
            }
        }
    }

リリース、アップデート後の不安、クラッシュレポートで解決しよう。

アプリのDL数はリアルタイムで更新されません。つまり問題があってもわかりません。クラッシュレポート機能をつけて、少しでも早くバグに気づこう。

Fabric/Crashlytics

リリース時のクラッシュレポートには、TwitterのFabricのCrashlyticsが有名みたい。Twitterアカウントを使ったログイン機能、広告、クラッシュレポート、この3つのサービスをまとめたもの。今回は、クラッシュレポートのみを使用する。

Android Studio用のFabricプラグインをダウンロード。

Safariだと、zipを自動で解凍してしまうので、Safariの設定をダウンロード後に ”開かない”という設定に変更すること。

https://get.fabric.io

インストール

Android studio => Preferences => Plugins => Install plugin from discを選択。

Crashlyticsをアプリに組み込む。

Android Studioにfabricのボタンが表示されるので、このボタンを押せば、アプリにCrashlyticsの機能を組み込むことができる。

f:id:araiyusukej:20151101184054p:plain

テストしてみる。

勝手にいろんなコードが追加されました。では、はたしてインストールできたのか。。。
強制終了させて、fabric経由でメールが来るのかテストしてみる。

強制終了させるテスト

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Fabric.with(this, new Crashlytics());
        setContentView(R.layout.activity_main);
        TextView nameTv = null;
        nameTv.setText("ダルビッシュ〜");
    }

登録したメールアドレスにNew Fatal Issue Discoveredメールが届いた。

f:id:araiyusukej:20151101184619p:plain

なぜか、Gmailのプロモーションの中に入っていたw

Android StudioのFabricプラグインからも確認できる。

f:id:araiyusukej:20151102104708p:plain

クラッシュした時のレポートから、ファイル名、行数、OS、画面の向き、メモリの状況などを取得できる。

開発者が独自に追加してレポートに追加することもできる。

レポートにユーザー情報を追加する。

f:id:araiyusukej:20151102115859p:plain

アカウントやメールアドレスをアプリで管理している場合は、crashlyticsに情報を設定しておけば、ダッシュボードから、強制終了が起きた時に、確認することができる。もし管理してない場合は、ユーザー固有の識別子を割り当てよう。レポートが溜まってきた時に、エラーの優先度を決める時に、役に立つ。

Fabric.with(this, crashlyticsKit);
setContentView(R.layout.activity_main);

//識別子で管理。
crashlyticsKit.setUserIdentifier("識別");

//ユーザー名やEmailで管理。
crashlyticsKit.setUserEmail("info.yusuke.arai@gmail.com");
crashlyticsKit.setUserName("マイケル");
EditText tv = null;

API

void setBool(String key, boolean value);

void setDouble(String key, double value);

void setFloat(String key, float value);

void setInt(String key, int value);
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Fabric.with(this, new Crashlytics());
        setContentView(R.layout.activity_main);
        Crashlytics.setString("タグ", "UIの操作");
        TextView nameTv = null;
        nameTv.setText("ダルビッシュ〜");
    }

f:id:araiyusukej:20151102105356p:plain

開発中は、クラッシュレポートの機能を無効にする

Crashlytics crashlyticsKit = new Crashlytics.Builder()
                .core(new CrashlyticsCore.Builder().disabled(!BuildConfig.DEBUG).build())
                .build();
Fabric.with(this, crashlyticsKit);

開発中はAndroid Studioにログを出力する。リリース時はログのタイプによって処理を分ける。下の記事を参考にしました。

blog.xmartlabs.com

Crashlyticsへログを送る

Crashlytics.logException(new Exception("強制終了でないけど、ログを送るよ"));


VERBOSE、DEBUG、INFO以外は、Fabric/Crashlyticsへログを渡してあげます。例えば、サーバーと連携するような処理で接続エラーの時や、Sqliteのデータベースエラー、例外処理に仕込んでおくといいかも。

BuildConfig.DEBUGのフラグを切り替えると、開発とリリースで切り替えることができる。

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.crashlytics.android.Crashlytics;
import io.fabric.sdk.android.Fabric;
import timber.log.Timber;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (BuildConfig.DEBUG) {
            Timber.plant(new Timber.DebugTree());
        } else {
            Fabric.with(this, new Crashlytics());
            Timber.plant(new CrashlyticsTree());
        }
        Timber.tag("タグ");
        Timber.e("メッセージ");    }

    public class CrashlyticsTree extends Timber.Tree {
        private static final String CRASHLYTICS_KEY_PRIORITY = "priority";
        private static final String CRASHLYTICS_KEY_TAG = "tag";
        private static final String CRASHLYTICS_KEY_MESSAGE = "message";

        @Override
        protected void log(int priority, @Nullable String tag, @Nullable String message, @Nullable Throwable t) {
            if (priority == Log.VERBOSE || priority == Log.DEBUG || priority == Log.INFO) {
                return;
            }

            Crashlytics.setInt(CRASHLYTICS_KEY_PRIORITY, priority);
            Crashlytics.setString(CRASHLYTICS_KEY_TAG, tag);
            Crashlytics.setString(CRASHLYTICS_KEY_MESSAGE, message);
            if (t == null) {
                Crashlytics.logException(new Exception(message));
            } else {
                Crashlytics.logException(t);
            }
        }
    }
}

f:id:araiyusukej:20151102202237p:plain