DockerでReact Native環境作成から、Expo Clientで実機確認するまで

iOS、Android両方に対応するアプリを作成することができるReact Native。
最近、個人的に興味がわいたので、Docker環境作成にチャレンジしてみたのですが、あまり記事を見かけなかったので構築手順を書いておきます。

**※2019/9/21追記**
**後述しますが、自分がやった時にホットリロードが効かなかったり、エミュレータ環境との連動がうまくできなかったりしてます...。**
**自分のやり方が悪いだけかもしれませんが、あまりDockerで構築するメリットがないかもしれません。**

**2019/9/26追記**
WSLで環境作り直しました。
　→[WSLでReact Native + Expo環境を作ろう](https://qiita.com/h-yoshikawa/items/610ffea888f13275cde8)
## 前提
- docker導入済み
- docker-compose導入済み

## 環境構築手順
### 事前準備
React Nativeで開発をしていく上で開発支援サービスであるExpoを使うと便利です。
React Nativeのプロジェクト作成・ビルド・デプロイを容易にしてくれたり、UIコンポーネントの実装を簡単にしてくれるSDKなどを提供しています。
環境構築も比較的楽に行え、アプリの内容をQRコードで発行して簡単に実機確認を行うことができます。

Expoが対応しているライブラリやモジュール以外は利用することができないという制約（一応利用すること自体はできるが、Expoの機能が使えなくなる）はありますが、すぐReact Nativeの開発をしたいという人には便利なツールじゃないかと思います。

#### Expoアカウントを作成
![expo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206877/f9cc5189-0fcc-d2d4-0870-a839883fe94a.png)

1. [expo.io](https://expo.io/)にいき、「Create an account」を選択。
2. e-mail、ユーザ名、パスワードを入力して「Create your account」を選択。

#### Expo Clientをインストール
![expo-client.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206877/d7bc8c35-df6a-71a0-b07a-9cb05f518eee.png)

1. 使用するiOS/Android端末に[App Store](https://apps.apple.com/jp/app/expo-client/id982107779)/[Google play](https://play.google.com/store/apps/details?id=host.exp.exponent&hl=ja)からインストール。
2. 作成したExpoアカウントでログインしておく。

### Docker環境作成
自分の場合、この時点でのディレクトリ構成は以下のようになっています。

```
ReactNative(プロジェクトフォルダ)
├─ docker
|　├─ node
|　　　├─ dockerfile
├─ .env
├─ docker-compose.yml
```

#### Dockerfile
```dockerfile
FROM "node:10-alpine"

WORKDIR /usr/src/app/

RUN apk update && apk add bash

RUN yarn global add expo-cli
```
後ほど、`expo start`する際に`bash`が必要になりますが、使用しているイメージのalpine linuxには`bash`が入っていないため、インストールしています。
はじめから`bash`が入っているイメージを使用するのもありです。

React Nativeのプロジェクトを作成するCLIツールとして、以前は`create-react-native-app`があったそうなのですが、`expo-cli`に統合されたそうなのでこちらをインストール。

#### .env
```
REACT_NATIVE_PACKAGER_HOSTNAME=(自分のローカルPCのIPアドレス)
```
コンテナに渡す環境変数を定義します。
`REACT_NATIVE_PACKAGER_HOSTNAME`は、後ほど`$ expo start`でExpoアプリをホスティングする際のIPになります。デフォルトではコンテナのIPを使用してしまうために、Expo Clientから接続することができないので、ローカルPC自体のIPを指定しておきます。
IPはWindowsでは`$ ipconfig`、Macでは`$ ifconfig`で確認できます。

#### docker-compose.yml
```yml
version: "3"
services:
  node:
    build: ./docker/node
    volumes:
      - ./app/:/usr/src/app
    tty: true
    stdin_open: true
    environment:
      - REACT_NATIVE_PACKAGER_HOSTNAME=${REACT_NATIVE_PACKAGER_HOSTNAME}
    ports:
      - "19000:19000"
      - "19001:19001"
      - "19002:19002"
```
tty、stdin_open - `$ docker-compose up`したコンテナを起動させたままにするために設定。
environment - .envファイルで定義した環境変数を設定。
port - Expoで使用する3つのポートを設定。

#### 起動
バックグラウンドで起動

```
$ docker-compose up -d
```
`RUN yarn global add expo-cli`の個所でWARNがたくさん出ますが、ERRORがなければ動いてくれると思います。（すみません、WARNの内容まではちゃんと見れていません）

## Expoプロジェクト
### 作成
```
# コンテナの中に入る
$ docker-compose exec node bash

# expoプロジェクト作成
$ expo init .
```

テンプレートが選択できます。とりあえずはblankを選択してEnter。

```
bash-4.4# expo init .
? Choose a template: (Use arrow keys)
  ----- Managed workflow -----
❯ blank                 a minimal app as clean as an empty canvas
  blank (TypeScript)    same as blank but with TypeScript configuration
  tabs                  several example screens and tabs using react-navigation
  ----- Bare workflow -----
  minimal               bare and minimal, just the essentials to get you started
  minimal (TypeScript)  same as minimal but with TypeScript configuration
```

Expoプロジェクトの表示名を聞かれます。入力してEnter。

```
? Choose a template: expo-template-blank
? Please enter a few initial configuration values.
  Read more: https://docs.expo.io/versions/latest/workflow/configuration/ ‣ 0% completed
 {
   "expo": {
     "name": "<The name of your app visible on the home screen>",
     "slug": "app"
   }
 }
```

Yarnを使ってパッケージをインストールするか聞かれます。Yでインストール実行。(nを選択するとnpmでパッケージをインストールします）

```
? Yarn v1.17.3 found. Use Yarn to install dependencies? (Y/n)
```

これでExpoプロジェクトのひな型が作成されました。

### 起動
以下のいずれかでExpoサーバとして起動。

```
$ expo start

$ yarn start
```
しばらくするとQRコードが表示されます。
![expo-start.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206877/0f22eb14-1ec4-831a-687f-ba6fcc5206ba.png)

### Expo Clientで実機確認
表示されたQRコードをiOS/Android端末から読み込むと、Expo Clientが立ち上がりビルドが始まります。
なお、注意点として、ExpoサーバになるPCとiOS/Android端末は同じネットワークにつないでいる必要があります。
しばらくしてビルドが終わると初期ガイドが表示されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206877/c8913c91-bb40-59db-7f8b-ad7f19b856a7.png" width=40% alt="app-guide">

ガイドを消すと、Expoアプリの画面が表示されます。これが実行結果です。
blankテンプレートを選択したのでシンプルな画面ですね。
一連の手順で比較的楽に実機確認をすることができました。
**ただ、ホットリロードがうまく動作していないのか、コードの変更が即座に反映されませんでした。なぜ...。**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206877/166ca1e6-edbe-162f-6b50-6de647d07c0c.png" width=40% alt="app-preview.png">

## 補足
### http://localhost:19002
アクセスすると、Expo DevToolが使用できます。
ここからシミュレータを起動したりできるみたいです。
（X Code、Android Studioのインストールや設定が別途必要になるようです）
[後述](https://qiita.com/h-yoshikawa/items/51b631ec0a6beabdce2d#%E3%82%A8%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%82%BF%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)していますが、自分はうまくいきませんでした...。
![expo-devtool.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206877/73bc55e5-28b4-5d88-efdf-ce8e252bfabb.png)

### http://localhost:19001
HTMLが表示されます。
`expo start`時の表示でMetro Bundlerだと書いてありましたが、なんなのかはよくわかってません。
![metro-bundler.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206877/55517ea7-c5a1-2acc-0659-9741bc906557.png)

### http://localhost:19000
Expoプロジェクトの情報？が表示されます。
![expo-server.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206877/d7c7870a-38f0-8289-c942-1a251c614848.png)

### エミュレータについて
自分の環境はWindowsなので、Docker環境の中にAndroidのエミュレータ環境を作ろうとしましたがうまくいきませんでした...。

一応やってみたこととしては
1. openjdkをインストール
2. Android公式からコマンドラインのzipファイルをダウンロード
3. Andoid SDKを格納するディレクトリを作成し、zipファイルを解凍して配置
4. Android SDKに関するパスを設定
5. sdkmanager、avdmanagerコマンドが実行できることを確認
6. sdkmanagerコマンドで必要なSDKをインストール
　↑
ここでエミュレータをインストールしたのですが、なぜかemulatorコマンドが実行できませんでした。パスはちゃんと通しているはずなのに、ひたすら`No such file or directory`が出てしまい...。一体なんなのか。

WSLで環境構築した方が、早いかもしれませんね。
だからDockerで構築している記事がほとんどなかったんでしょうか...。


## 参考
- [Running Expo/React Native in Docker](https://medium.com/@hmajid2301/running-expo-react-native-in-docker-ff9c4f2a4388)
- [Expoのアカウントを作ってReact Nativeの開発環境を整える](https://qiita.com/hitotch/items/ea4de1ed408a9ca14fce#expo%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)
- [【React Native】Expo CLIを利用してReact Nativeプロジェクトを作成する](https://rennnosukesann.hatenablog.com/entry/2019/01/01/012758)