Stethoをreleaseビルドに含まない方法メモ

Facebookのライブラリ、Stetho便利ですよね。

セキュリティ的にバックドアになるものなのでreleaseビルドでは関連コードは確実に除きたいものです。
ただ、releaseビルドに含まないためのからのlibraryがないのでちょっと面倒です。
すでにqiitaにも幾つか方法が投稿されていたのでまとめてみました。

まず、共通する部分として、debugビルドにしかstetho関連ライブラリを含まない、としたいのでbuild.gradleを次のようにします。

```groovy:app/build.gradle
dependencies {
    ....
    debugCompile 'com.facebook.stetho:stetho:1.3.1'
    debugCompile 'com.facebook.stetho:stetho-okhttp3:1.3.1'
}
```

# buildTypeによって参照するクラスを書き換える方法
[Create stetho-stub for convenient removal from release builds #16](https://github.com/facebook/stetho/issues/16)

公式githubのissueの中で議論されていた方法です。
この方法を見てこの記事を書こうと思いました。

build.gradleの中でBuildConfigに追加するクラスをbuildTypeに応じて変える、という方法です。
賢いなぁ、と思いました。

```groovy:build.gradle
debug {
    ...
    // ここでBuildConfig.STETHOとして追加するクラスを変える。
    buildConfigField 'mypackage.util.StethoHelper', 'STETHO', 'new flipboard.util.RealStethoHelper()'
}

release {
    ...
    // releaseビルドではfakeクラスを追加する
    buildConfigField 'mypackage.util.StethoHelper', 'STETHO', 'new flipboard.util.FakeStethoHelper()'
}
```

そしてまず、mainの中にどちらでも使うInterfaceと空クラスを定義します。

```java:app/src/main/java/mypackage/util/StethoHelper.java
// StethoHelper interface, AKA "NetworkEventReporterImpl"
public interface StethoHelper {
   void init(Context context);

   void configureInterceptor(OkHttpClient httpClient);
}
```
```java:app/src/main/java/mypackage/util/FakeStethoHelper.java
public class FakeStethoHelper implements StethoHelper {
    @Override
    public void init(Context context) {
        // Noop
    }

    @Override
    public void configureInterceptor(OkHttpClient httpClient) {
        // Noop
    }
}
```
次にdebugの中に本当にstethoを使うクラスを作成します。
この中でだけstethoを参照することでdebugCompileでもビルドできるようにしていますね。

```java:app/src/debug/java/mypackage/util/RealStethoHelper.java
public class RealStethoHelper implements StethoHelper {

    @Override
    public void init(Context context) {
        Stetho.initializeWithDefaults(context);
    }

    @Override
    public void configureInterceptor(OkHttpClient httpClient) {
        httpClient.networkInterceptors().add(new StethoInterceptor());
    }

}
```
実際にstethoを使うクラスは分ける必要がありません。
該当箇所でStethoHelperクラスにinitやinterceptの設定をすればいいだけです。

```java:app/src/main/java/mypackage/MyApplication.java
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        // In your application class's onCreate()
        BuildConfig.STETHO.init(this);
    }
}
```
```java:app/src/main/java/mypackage/network/AbsNetwork.java
// In your network stack
BuildConfig.STETHO.configureInterceptor(this.httpClient);
```

この方法は初回こそ若干build.gradleに書いたり、helperクラスに書いたりする必要がありますが、使う箇所が増えてもhelperを拡張していけばいいだけですし、メンテナンスの時に便利そうです。

+ + 参照場所やbuildTypeが増えてもメンテナンスしやすそう
+ + ちょっと賢そう。
+ - はじめに追加する部分が多い。

# debugビルドでのみinitする方法

[デバッグ時のみStetho, LeakCanary, StrictModeを入れる](http://qiita.com/takahirom/items/2cbf307c49048016f5b7)

Applicationクラスを共通用のものを継承したDebugApplicationクラスを作って、debugビルドではそちらに上書きする、という方法ですね。
これが一番簡単な方法かと思います。

他のライブラリについても書かれているので、Stetho部分だけ抜き出すと、

```java:app/src/debug/java/mypackage/DebugApplication.java
public class DebugApplication extends MyApplication {
    @Override
    public void onCreate() {
        super.onCreate();
        Stetho.initializeWithDefaults(context);
    }
}
```
```xml:app/src/debug/AndroidManifest.xml>
    <application
        android:name=".DebugApplication"
        tools:replace="android:name" />
```

ですね。

でもこれだと一つ問題があってbuild.gradleでstetho-okhttpを参照していますが、okhttpにinterceptorを入れる箇所でもstethoを参照してしまっているため、このままだとbuildできませんでした。

helperを別に作るなど、他の方法を組み合わせるのがいいと思います。

+ + コード量が少なくて楽
+ - stethoの初期化時にしか使えない。(他の部分は増やしていく必要がある)

### 元ネタ
[Stetho for Android debug builds only](http://www.littlerobots.nl/blog/stetho-for-android-debug-builds-only/)


# releaseビルドでは同名クラスを作成する方法。

[Stethoをrelease時に使用しないようにする方法](http://qiita.com/kubode/items/a5afd116a432331a4fc6)

もう一つはreleaseビルドように同名のダミークラスを用意する方法です。
例がkotlinで書かれているので、同じようにjavaでもあげてみます。

```java:app/src/release/java/com/facebook/stetho/Stetho.java
public class Stetho {
    public static void initializeWithDefaults(Context context) {
        // 空実装
    }
}
```
```java:app/src/release/java/com/facebook/stetho/okhttp3/StethoInterceptor.java
public class StethoInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        return null; // 空実装
    }
}
```

これなら、okhttpのinterceptor等もreleaseビルドで参照できて、いいと思います。
ただ、使っている関連クラスが増えたり、methodの形式が変わったりすると同じ構成を実現できるように維持する必要があるため、メンテナンスが煩雑になりそうです。

+ + 追記するコード量は少なめ
+ + どちらのコードも特殊なことをしなくて良い
+ - 参照クラスを増やすたびにダミークラスやメソッドを追記する必要がある

# ちなみに
本文と関係ありませんが、stethoをupdate？追加した際、releaseビルドができない問題に遭遇しました。

[気をつけたいGradleの推移的依存関係とその解決](http://qiita.com/tomoima525/items/6dd59830aa122e39520b)

上の記事の内容の通りで、明示的にjsr305をdependenciesに含めたら解決しました。

```
dependencies {
    compile 'com.google.code.findbugs:jsr305:2.0.1'
}
```

ご参考までに。