Hyperion-AndroidでAndroidアプリをデバッグしよう

[shibuya.apk #24](https://shibuya-apk.connpass.com/event/83014/)でLTする内容になります。(ネタバレになるので来る方はその時に見てください :pray:)

[Hyperion-Android](https://github.com/willowtreeapps/Hyperion-Android)

Hyperion-AndroidはStethoやLeakCanary、[DebugAlter](https://github.com/takahirom/debug-alter)(宣伝)などと同じデバッグ時のみ有効にさせるライブラリです

* デバッグメニューをアプリに追加できる
* 一つ一つのメニューが便利
* [Google AutoService](https://github.com/google/auto/tree/master/service)により、dependencyに追加するだけで、コードを編集せずに機能を追加できる

端末を振るか通知をタップするとこんな感じでデバッグメニューが出てきます。

<img src="https://qiita-image-store.s3.amazonaws.com/0/27388/74f3f1ec-ae4f-8da3-a00f-b2fab5f52d8a.png" width="150" />


# Hyperion-Androidの機能紹介

## hyperion-attr
おすすめ度　★
* ViewのAttributeを見れる
* Enableなどを切り替えたりも出来る

<img src="https://qiita-image-store.s3.amazonaws.com/0/27388/fe4e380e-17a5-a1d1-e8e7-5c889fe6d737.png" width="150" />

## hyperion-measurement
おすすめ度　★★★★★
ZeplinのようにViewとViewの間や Viewの大きさをdp単位で見ることが 出来る
これのために入れるといっても 良い機能
一度使うとこれなしで正確なレイアウトを組めなくなります

<img src="https://qiita-image-store.s3.amazonaws.com/0/27388/1983328f-89ad-09f4-9f9f-9c19e5117249.png" width="150" />

## hyperion-shared-preferences
おすすめ度　★★★
Preferenceの値を動的に変更できる 機能
<img src="https://qiita-image-store.s3.amazonaws.com/0/27388/1b4c5238-0fe1-f218-48d6-6c84c191ad77.png" width="150" />

## hyperion-recorder
おすすめ度　★
アプリの動きを動画として保存できる 機能
<img src="https://qiita-image-store.s3.amazonaws.com/0/27388/151f6177-527b-2976-5cf4-67a84146b821.png" width="150" />

## hyperion-disk
おすすめ度　★
アプリのデータディレクトリに保存 されいているファイルを見られる機能
<img src="https://qiita-image-store.s3.amazonaws.com/0/27388/067efc0e-6a62-5d25-58f0-190f892c12ae.png" width="150" />

## hyperion-phoenix
おすすめ度　★
アプリを再起動しながらデータや キャッシュを削除できる機能
<img src="https://qiita-image-store.s3.amazonaws.com/0/27388/1bf9e6fc-ea1a-4aee-fecc-f69aed62f16a.png" width="150" />

## hyperion-crash
おすすめ度　★★★★
アプリが強制終了した時に、クラッシュ ログを表示してくれる機能
地味に便利
<img src="https://qiita-image-store.s3.amazonaws.com/0/27388/ef64c7f4-401b-35d5-1f72-a1b6cfa5b66b.png" width="150" />

## サードパーティのプラグイン Hyperion-Chuck
おすすめ度　★★★
jgilfelt/chuckを呼び出せる機能
アプリ内でHttpのログを確認できる
<img src="https://qiita-image-store.s3.amazonaws.com/0/27388/8f48b32f-6fc6-70d1-43bf-08e71e0f9978.png" width="150" />
https://github.com/Commit451/Hyperion-Chuck

## hyperion-geiger-counter
おすすめ度　？
まだ未リリースのようなのですが、フレーム落ちを検知できるようです。(サンプルアプリで使って見ましたがフレーム落ちが起きなかったので試せていません。)

## ガンガンメニュー追加しちゃいましょう
プラグインのコントリビューター募集しているっぽい雰囲気なので、コントリビュートしてあげるといいかもです。
https://github.com/willowtreeapps/Hyperion-Android/issues


# Hyperion-Androidを導入する上でハマった所とその解決策
自分が若干Hyperion-Androidを入れる上で手間取った所を紹介します。

## DataBindingのBinding生成のエラーになる

```groovy
debugImplementation 'com.willowtreeapps.hyperion:hyperion-core:0.9.21'
debugImplementation 'com.willowtreeapps.hyperion:hyperion-attr:0.9.21'
...
```

READMEに書いてあるとおりにdependencyにHyperion-Androidを入れてビルドしようとすると自分の環境ではDataBindingのBindingが生成されない系のエラーになりました。

Hyperionが最新のSupport Libraryなどを使っているのが原因でした。

```
+--- com.willowtreeapps.hyperion:hyperion-core:0.9.21
|    +--- com.willowtreeapps.hyperion:hyperion-plugin:0.9.21
|    +--- com.android.support:appcompat-v7:27.1.0 (*)
|    +--- com.android.support:recyclerview-v7:27.1.0 (*)
|    \--- com.google.dagger:dagger:2.15
|         \--- javax.inject:javax.inject:1
```


以下のように除外して対応できました (逆にHyperionがうまく動かなくなる部分があるかもしれません。)

```groovy
  ["hyperion-core", "hyperion-attr", "hyperion-measurement", "hyperion-disk", "hyperion-recorder","hyperion-phoenix","hyperion-crash"].forEach {
    debugImplementation ("com.willowtreeapps.hyperion:$it:0.9.20"){
      exclude group: 'com.android.support'
      exclude group: 'com.google.dagger'
    }
  }
```

## 既存のデバッグメニューは どうするか？

すでにアプリにデバッグメニューが実装されている場合、どのように対応しますか？
* ~~既存のデバッグメニューは消す？~~
* 自分でPluginを作る？
* ???


### 既存のデバッグメニューを開くために自分でPluginを作る

![image.png](https://qiita-image-store.s3.amazonaws.com/0/27388/a51d500e-7c06-b044-7488-515b32d78111.png)
GoogleのAutoServiceをkaptで依存する(Kotlinなどの対応状況による。)

以下をモジュールで作って、そのモジュールをdebugImplementationで参照します。

```groovy
  implementation 'com.willowtreeapps.hyperion:hyperion-plugin:0.9.21'  
  kapt "com.google.auto.service:auto-service:1.0-rc4"
```

以下のようにプラグインを作る。
ポイントは以下

* AutoServiceアノテーションを使う(ライブラリとして使う場合)
* Pluginクラスを作りそこでPluginModuleを作成
* PluginModuleクラスでViewを作って返す
* PluginModuleクラスには 色々便利なメソッドが生えているので利用してみると良さそう

```java
@AutoService(Plugin.class)
class HelloWorldPlugin extends Plugin {
    @Override
    public PluginModule createPluginModule() {
        return new HelloWorldPluginModule();
    }
}

class HelloWorldPluginModule extends PluginModule {
    @Override
    public View createPluginView(@NonNull LayoutInflater layoutInflater, @NonNull ViewGroup parent) {
        final TextView textView = new TextView(parent.getContext());
        textView.setText("Hello Hyperion Plugin");
        textView.setTextSize(50);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("Hyperion", "goto debugmenu");
            }
        });
        return textView;
    }
}
```

### プラグインをHyperionに追加する
アプリのモジュール内で実装する場合、 debug/以下ではダメで、main/以下に置かないと なぜかGoogleのAutoServiceは拾ってくれないので メニューに追加されないので、プロダクション環境にコードを追加しないとHyperionに既存のデバッグメニューへの導線を追加できません。
別モジュールにすればいいですが、そうするとアプリ内のコードをそのモジュールから参照できません。

プルリク出してAutoServiceを使わずにアプリ内で自分で追加できるようにしました！
このように自分でプラグインを追加して、メニューを追加することができます。

```java
        PluginSource source = Hyperion.getPluginSource();
        class MyPluginSource implements PluginSource {
            private PluginSource originalPluginSource;

            MyPluginSource(PluginSource originalPluginSource) {
                this.originalPluginSource = originalPluginSource;
            }

            @Override
            public Set<Plugin> getPlugins() {
                final HashSet<Plugin> plugins = new HashSet<>();
                plugins.addAll(originalPluginSource.getPlugins());
                // ここで追加したいプラグインを指定する
                plugins.add(new HelloWorldPlugin()); 
                return plugins;
            }
        }
        Hyperion.setPlugins(new MyPluginSource(source));
```

### プラグイン作るの面倒？
わざわざ自分でプラグインを作らなくても、これを使うと簡単にHyperionにアイテムを追加することができます。(宣伝)
https://github.com/takahirom/Hyperion-Simple-Item

```java
public class DebugApp extends App {
  @Override public void onCreate() {
    super.onCreate();

    final SimpleItem item = new SimpleItem.Builder("all: this is the title")
            .text("this is the text")
            .image(R.drawable.ic_list_black_24dp)
            .clickListener(new View.OnClickListener() {
              @Override public void onClick(View v) {
                Toast.makeText(App.this, "click",Toast.LENGTH_SHORT).show();
              }
            })
            .build();
    SimpleItemHyperionPlugin.addItem(item);
```

# 導入Pull Request
DroidKaigi 2018公式アプリでの導入PRです。
https://github.com/DroidKaigi/conference-app-2018/pull/672

# まとめ
Hyperion-Android、いい感じなので、入れてみましょう。
DataBindingでエラーが出たら依存関係を疑ってみましょう。
既存のデバッグメニューに飛ばすときはHyperion-Simple-Itemを 入れてみましょう。