【2019年9月版】Android版Metamaskアプリの中の自前dAppsをデバッグする

# 自前dAppsのデバッグをAndroid版のMetamaskアプリ上でしてみたい。

Ethereum のウォレットアプリ？として有名な[Metamask](https://metamask.io) のスマホ版である **[Metamask Mobile](https://mobile.metamask.io/)** は [React Native](https://facebook.github.io/react-native/) で実装されています。

- [Github.com: MetaMask/metamask-mobile](https://github.com/MetaMask/metamask-mobile)

この Metamask Mobile 上で自前 dApps の動作確認を行ってみましたが、デバッグ環境の構築が若干、ややこしかったのでメモを残しておきます。

## 1.対象環境

OS: Ubuntu 18.04 LTS
テストネット: ローカルの Ganache
Android SDK: 9.0 (API 28)
機種: エミュレーター

今回の自前 dApps は React で作っている想定です。ただし、構築の手順は他のフレームワーク(Nuxt, Angular)などでも同じです。

また、リモートでのAndorid 上の Webアプリのデバッグでは **Chromeブラウザが必須**です。

Chromeブラウザをダウンロード＆インストールしておきましょう。

## 2.ポイント

用意するものがそこそこ多いので以下にハマるポイントだけを上げておきますと・・・

- Ganache は 0.0.0.0 で待ち受けること！→ エミュレーターからは 10.0.2.2 でホストにアクセスする！
- Ganache(7545)、開発サーバーのポート(3000,4200など)はそれぞれ `adb reverse` する → reverse しないと応答しなかった！

上記の箇所さえ抑えておけば後はすんなり動くようになります。

それではさっそく、以下の手順で構築していきます。

## 3. Ganache のインストール

ローカルで Ethereum のテストネットを動かすために今回は手っ取り早く Ganache を使用します。

- [Ganache | Truffle Suite](https://www.trufflesuite.com/ganache)

Linux 版をダウンロードし、インストールしたらダブルクリックで起動後、"Qucik Start"をクリックしてEthereumのテストネットを起動します。

これは非常に簡単ですね！

また、歯車アイコンクリックしてネットワークの設定を、"0.0.0.0" に変更しておきます。

IPアドレスを変更してテストネットの再起動後は以下のようなトップ画面になっていると思います。

<img width="50%" alt="1.Ganacheの設定.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/b0c32b19-85e5-a93e-ee6f-ce0e01c4132a.png">
(ETHの額が減っているのはごにょごにょした後だからです・・・)


## 4.React Nativeの環境構築

続いて React Native の環境設定です。

- [Getting Started . React Native](https://facebook.github.io/react-native/docs/getting-started)

基本的には本家サイトの環境構築手順の通りでOKです。

### 4-1.React Native Client は・・・

`react-native`コマンドを使用するため、React Native Clientをインストールが必要です。

が、**宗教上の理由**により `npm install -g` ができないのでこの手順は後ほど行います。

`npm install -g` を実行して問題ない方はどうぞ `react-native-cli` をインストールしてしまってください。

### 4-2.Android SDK (Android Studio)

今回は Ubuntu がターゲットのため iOS版ではなく Android 版だけの動作環境構築となります。

- [Android Studio インストール手順 Linux版](https://developer.android.com/studio/install#linux)

こちらは手順に従ってインストールします。すいませんが、具体的な手順は省略します。

SDKのインストール完了後、仮想デバイスマネージャーから仮想デバイスを追加しておいてください。

## 5.Metamask Mobile

以下のコマンドでリポジトリからcloneをしてきます。

```
$ git clone git@github.com:MetaMask/metamask-mobile.git -b v0.2.4
```
Metamask Mobileは"最新版"を使用しても実際にストアでリリースされているアプリとは挙動が異なる可能性大です。
できるだけストアで配布されているバージョンに合わせたタグのソースを取得しましょう

### 5-1.React Native CLI のインストール

Metamask Mobile リポジトリ内でReact Native Clientをインストールしたいと思います。

```
$ npm i react-native-cli
```

また、次のビルド手順の前に仮想デバイスを立ち上げておきましょう。

### 5-2.Metamask Mobileのビルド

Metamask Mobile の Android 版のビルドとデバッグは以下のコマンドでOKです。

```
$ npm run start:android
```

ビルド処理が実行され、仮想デバイス上で Metamask アプリが起動します。簡単ですね！

### 5-3.Ganache のポートを通す

以下のコマンドで Ganache と通信する 7545 ポートを通過させるようにします。

```
$ adb reverse tcp:7545 tcp:7545
```

このポートのマッピングはホスト側→端末側の順で指定します。

### 5-4.Metamask Mobileの実行と設定

以下が Metamask アプリの起動画面です。まずはアカウントの設定を行います。

下側の "Sync or Import Your Wallet" をクリックします。

<img width="50%" alt="2.Welcome To Metamask.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/a759e8b0-11b4-2834-f5a9-7f29934a112b.png">

次の画面では "Import using seed phrase" をクリックします。

<img width="50%" alt="3.AlreadyMetamaskUser.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/3671a6bc-453b-a61f-4167-fdcbe00139f6.png">

ニーモニックの入力ですが、コピペが出来ませんので Ganache の画面とにらめっこしながら 12単語を"目で"コピーします。

<img width="50%" alt="4.Import From Seed.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/f931b6a8-5c45-627d-43bb-d6f077014a01.png">

無事にニーモニックとパスワードの設定ができると、アカウントのインポートが完了です。

<img width="50%" alt="5.Import Success.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/d90272ba-8eb9-fe8a-f51c-3c9d93c898e2.png">

ただし、ここではまだメインネットやその他、グローバルなテストだけが接続できるだけなので、ローカルのGanacheネットワークの接続を追加しましょう。

画面左上のバーガーメニューをクリックして詳細メニューを開きます。

<img width="50%" alt="6.SideMenu.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/77f51255-6407-07a3-4a20-8a3b1da9b752.png">

詳細メニュー右上の歯車アイコンをクリックします。

<img width="50%" alt="7.Settings.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/4d88f30d-d2e2-47ad-9655-3b5f7ab45a0c.png">

システム設定？メニューが表示されます。ここから"Networks"を選択しましょう。

<img width="50%" alt="8. Add Network.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/25f79a61-36f8-a54d-c258-59f5d0e094ac.png">

ここでローカルのGanacheネットワークを追加します。

ネットワーク名はアプリに表示される識別子なのでわかりやすければなんでもOKです。
上記のように RPC Url に "http://10.0.2.2:7545" とホスト向けの"10.0.2.2"でアクセスするのがミソです。
ポート番号は Ganache の設定に合わせます。

続いてネットワークIDに7555、これもGanacheの設定に合わせて入力します。

"Save" で設定を保存し、正しく接続できると次の画面が"ちゃんと"表示されます。

<img width="50%" alt="9.Open Home.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/da599efe-c1e2-ee4e-9ba2-44786dcdf504.png">

うまく Ganache などの Ethereum ネットワークに接続できないと、この画面がリロードしっ放しになってしまいます。。。

それでは、仮想デバイスは一旦このままで、ホストPCからChromeを起動します。

ちょっとメニューの階層が深いですが、Chrome で検証ツールを起動し、検証ツールの右上の"..."メニューから"More Tools"→"Remote devices"を選択します。

<img width="50%" alt="10. Chrome Remote Device.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/07d30331-8bf7-d115-3b22-ad1b2bb249a0.png">

こちらの画面で、立ち上がっている仮想デバイスやUSB接続されているAndroid端末などが表示されます。

"WebView in io.metamask" との表示でちゃんと認識されていることがわかります。

"Inspect"をクリックすると Android 上の WebViewの中がデバッグできるようになります！

## 6.自前 dApps の実行とデバッグ

はやる気持ちを抑えて一旦、自前dAppsの開発サーバーを起動しましょう。

### 6-1.開発サーバーの起動とポートの開通

大抵のフレームワークは `npm start` で起動できると思います。

```
$ npm start
```

別ターミナルを開き、adbコマンドを叩きます。今回は React ですので 3000番を通過できるように設定します。

```
$ adb reverse tcp:3000 tcp:3000
```

Angular の場合は 4200 を指定すればOKです。

### 6-2.Metamask Mobile で開く

仮想デバイスの画面に戻ります。

Metamask 画面の下側の検索ボタンをクリックするか、一番上の"Browser"の箇所をクリックするとURLを直接、入力する画面が出ます。

<img width="50%" alt="11. Entre URL.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/5799856f-632e-c773-be10-de5d6cf83d2e.png">

ここで例によってホスト側の"10.0.2.2"を指定します。今回は3000番で開発サーバーが待ち受けているので、"http://10.0.2.2:3000" と指定します。

Metamask Mobile で無事に自前dAppsのHTMLが表示されたら、ホストのChromeの方を確認してみましょう。

<img width="50%" alt="12. Chrome Remote React App.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/aa7dd64c-f959-a1f1-e75f-cbddbe27e7b1.png">

正しく認識されていれば、ここで "WebView in io.metamask" そして、画面のタイトル(ここでは"React App")と "http://10.0.2.2:3000" が表示されていると思います。

右側の"Inspect"ボタンをクリックすると、仮想デバイス上のWebViewで開いている状態の自前dApps画面がデバッグできるようになります！

<img width="50%" alt="15.Debug Opensea.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/d21c6bd9-c74d-ee40-4c24-801175a1bb4a.png">
(こちらのスクショは[OpenSea](https://opensea.io/)を開いたところです。)

## 7. Metamask Mobile のデバッグ

Web3.jsの挙動が怪しい場合は自前dApps側だけでなく、Metamask内部の挙動まで追いたくなると思います。
というよりMetamask Mobileは絶賛、開発中のためWeb版では動くけどスマフォ版では動かない、ということが多々あります。

そんな場合は以下の手順でMetamask Mobileのデバッグが行えます。(React Nativeのデバッグですが。)

まず仮想デバイス上で`Ctrl+M`を押して、React Nativeのデバッグメニュー？を表示させます。

<img width="50%" alt="13.ReactNativeDebugMenu_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/96e5b1f7-4630-a82d-0499-a30ef078e877.png">

ここから"Debug JS Remotely" をクリックすると、以下のデバッグ用のChromeが立ち上がります。

<img width="50%" alt="14.Chrome ReactNativeDebugger-UI.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335150/b856094b-0489-ffb6-7e54-8c273b088a16.png">

画面にも説明書きがありますように`Ctrl+Shift+J`で検証メニューを開くとMetamask mobileアプリのDevTools画面が立ち上がります。

お疲れさまでした！！

## 8. エラーなどでハマったところ

上記の手順の構築中に、こちらの環境では以下のようなエラーが発生しました。完全に環境依存ですが一応、メモを残しておきます。

### 8-1. ANDROID_HOME がない。

React Native からMetamask Mobile を起動しようとして以下のように怒られました。

```
$ npm run start:android

...
...
What went wrong:
A problem occurred evaluating project ':app'.  
> SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.
...
```

はい、過去にADKをインストールした時には ADK_HOME は設定しましたが、`ANDROID_HOME` は未設定でした。。。

.bash_profile に `EXPORT ANDROID_HOME=$ADK_HOME` を追加いたしました。 

```shell:.bash_profile
...
EXPORT ANDROID_HOME=$ADK_HOME
...
```
はい。

### 8-2. SecretToolがない。

こちらもReact Native からMetamask Mobile を起動しようとしてSecret-toolコマンドがないと怒られました。

はい、インストールいたしました。。。

```
$ sudo apt install libsecret-tools
```

以上です！