FlipperでNetworkプラグインを使う際のリリースビルド

## はじめに
Flipperを導入した際に、Networkプラグイン(OkHttpプラグイン)を入れた際にリリースビルドで失敗したので、その時の対応を書いていきます。

## Flipperとは
Facebook製のデバッグツールで、iOS、Android両方に対応しています。
この記事はAndroidで使う際の話です。
[公式](https://fbflipper.com/)

## fliper-noop
flipper-noopはFlipper Interfaceの空実装が用意されているパッケージです。
no-op(no-operation)を利用することで、コンパイルを通しながらリリースビルドからFlipper本体のコードを除去することができます。
[公式のドキュメントの例では](https://fbflipper.com/docs/getting-started.html)に沿ってセットアップします。  
ドキュメントでは次のように、releaseImplementationでリリースビルド時にはno-opを使うようにしています。  

```
dependencies {
  debugImplementation 'com.facebook.flipper:flipper:0.26.0'
  debugImplementation 'com.facebook.soloader:soloader:0.5.1'

  releaseImplementation 'com.facebook.flipper:flipper-noop:0.26.0'
}
```

## Networkプラグインの導入
Networkプラグインを入れていきます。  
こちらも[公式のドキュメント](https://fbflipper.com/docs/setup/network-plugin.html)に沿ってやっていきます。
gradleでは `debugImplementation` でプラグインを追加します。  

```
dependencies {
  debugImplementation 'com.facebook.flipper:flipper-network-plugin:0.26.0'
}
```

次にアプリケーションの実装でプラグインを使うようにします。

Application

```
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;

NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
client.addPlugin(networkFlipperPlugin);
```

そしてOkHttpのInterceptorを追加します。

```
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;

new OkHttpClient.Builder()
    .addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin))
    .build();
```
これでdebugビルドでは問題なく動作します。  


## プラグインはno-opが無い
リリースビルドでは `Unresolved Reference` となり、プラグインの参照を解決できずビルドに失敗します。これはプラグインについてはno-opパッケージに空実装が用意されていないためです。
これについては[Issue](https://github.com/facebook/flipper/issues/561)で説明されています。メンテコストの観点からプラグインについてはno-opを提供しない方針のようです。  
代替として、アプリ側の実装でdebugとreleaseのソースを分けてFlipper関連のコードをそこに集約する方法が推奨されています。 

## debugとreleaseでFliper関連コードを分ける
ビルドタイプに対応したディレクトリを切り、そこにFlipper関連のコードを集約していきます。  
サンプルコードを[こちら](https://github.com/k-tomoyasu/flipper-handson/tree/installed/sample/android/app)に置いています。  
サンプルでは `src/debug` , `src/release` にそれぞれデバッグ、リリースビルド用のFlipper関連コード(FlipperInitializer.kt)を分けています。

src/debug/FlipperInitializer.kt

```
interface InitializationResult {
    val okHttpClient: OkHttpClient
}

object FlipperInitializer {
    fun initFlipper(context: Context): InitializationResult {
        SoLoader.init(context, false)

        val networkFlipperPlugin = NetworkFlipperPlugin()
        if (BuildConfig.DEBUG && FlipperUtils.shouldEnableFlipper(context)) {
            val flipperClient = AndroidFlipperClient.getInstance(context)
            flipperClient.addPlugin(networkFlipperPlugin)
            flipperClient.start()
        }

        return object : InitializationResult {
            override val okHttpClient: OkHttpClient
                get() = OkHttpClient.Builder()
                        .addInterceptor(FlipperOkhttpInterceptor(networkFlipperPlugin))
                        .build()
        }
    }
}
```

リリースビルド用の方には空実装を用意します。
src/release/FlipperInitializer.kt

```
interface InitializationResult {
    val okHttpClient: OkHttpClient
}

object FlipperInitializer {
    fun initFlipper(context: Context): InitializationResult {
        return object : InitializationResult {
            override val okHttpClient: OkHttpClient
                get() = OkHttpClient.Builder().build()
        }
    }
}
```

Flipperの初期化はFlipperInitializerを呼ぶように置き換えます。 
src/main/TutorialApplication.kt

```
class TutorialApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        val initResult = FlipperInitializer.initFlipper(context = this)
        Network.client = initResult.okHttpClient
    }
}
```

これでリリースビルドも成功するようになりました。

## 最後に  
FlipperはStethoに比べるとまだ情報が見つからりにくいですが、とても便利なので積極的に使っていきたいです。
[Flipper導入のハンズオン資料を作ってみました](https://k-tomoyasu.github.io/flipper-handson/index.html)