Androidエミュレータ(AVD)からローカルのwebサーバにアクセス

Androidエミュレータ(AVD)内のブラウザから
ホストOS側で実行しているローカルwebサーバにアクセスする方法のメモです

・hostsファイルで任意ドメインをローカルに割り当てている場合
・[mkcert](https://github.com/FiloSottile/mkcert)で発行したSSL証明書を使ってSSL化している場合
についても補足します

※例示しているドメイン名(example.com)や、
webサーバの起動コマンド(http-server)は適宜読み替えてください
※わかりにくい点などありましたら、ご指摘いただけるとありがたいです

# 前提

Android Studio をインストールし
任意AndroidOSバージョンのAVD作成済みであることを前提にします

以下の記事もよかったらご参照ください
・[Android Studio のインストールとAVD作成](https://qiita.com/rkunihiro/items/433ec719396154f170f2)


# AVD内のブラウザからホスト側にhttpアクセス

AVD内からはホストOS側のIPアドレスは **10.0.2.2** になります

ホスト側でwebサーバを起動

```sh:NodeJSで動作するhttp-serverを利用する例
mkdir public
echo "<body>Hello,World!</body>" > ./public/index.html
npm install -g http-server
http-server -p 80 ./public
```

```sh:PHPの組み込み開発サーバを使う例
mkdir public
echo "<body>Hello,World!</body>" > ./public/index.html
php -S 0.0.0.0:80 -t ./public
```

エミュレータを起動してブラウザで http://10.0.2.2/ を開く
![emu-http.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73427/1348ed7f-4e17-4c73-c336-5b5227667444.png)




# 任意ドメインでアクセスできるようにする

ホスト側でhostsを書き換え任意ドメインでローカルwebサーバにアクセスできるようにしている場合
そのままではAVD内のブラウザから同様にアクセスすることができません
AVD内のhostsファイルにも設定する必要があります

## 準備: Android SDK のコマンドラインツールにPathを通す

起動オプションを指定してエミュレータを起動したり
AVD内のファイルを書き換えるためadbコマンドを使えるように
Android SDK インストールディレクトリ配下の
`platform-tools` と `emulator` を環境変数`Path`に追加

**macOS**

```sh:.zshrc
ANDROID_HOME=$HOME/Library/Android/sdk
PATH=$PATH:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator
export PATH
```

**Windows**

SDKは `C:\Users\(ユーザ名)\AppData\Local\Android\Sdk` あたりにインストールされているはずです
環境変数は`システムのプロパティ`で設定できます
(スタートメニューの`ファイル名を指定して実行`で`SystemPropertiesAdvanced`で起動できます
`詳細設定`タブ→`環境変数`押下→`(ユーザ名)のユーザ環境変数`の欄から`Path`を選んで`編集`押下)

以下2つをユーザー環境変数 `Path`に追加します

```
C:\Users\(ユーザ名)\AppData\Local\Android\Sdk\emulator
C:\Users\(ユーザ名)\AppData\Local\Android\Sdk\platform-tools
```

## AVDの hosts を設定

### ターミナルから、AVDを起動  

通常のAVD ManagerからAVDを起動した場合、hostsなどのシステムファイルに書き込むことができません

システムイメージへの書き込みを可能にするオプション`-writable-system`をつけてコマンドラインから起動します
※コマンドラインオプションについては[こちらの公式ドキュメント](https://developer.android.com/studio/run/emulator-commandline?hl=ja)もご参照ください

```sh:
emulator -avd "AVD Name" -writable-system
※"AVD Name"は起動したいAVDの名前に置き換えてください
```


### adb コマンドを用いてAVDのhostsを書き換える

※emulatorコマンドを実行したのとは別のターミナルで実行します

接続

```sh:
adb reconnect
```

再マウント

```sh:
adb remount
```

hosts取得

```sh:
adb pull /system/etc/hosts
```

取得したhostsを編集
(設定したいドメインを 10.0.2.2 に向ける)

```:hosts設定例
127.0.0.1 localhost
10.0.2.2 example.com
```

編集したhostsをpush

```
adb push hosts /system/etc
```

AVD内のブラウザを起動し http://example.com/ を入力すると  
アクセスできるようになっていると思います
![emu-http-vh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73427/65ac9346-fadf-9246-8469-91ecf6e6557f.png)


# HTTPS(SSL)でアクセスできるようにする

以前紹介した[mkcertで発行したSSL証明書](https://qiita.com/rkunihiro/items/530b5dc685bd3bff2082)を使用してhttpsサーバを起動している場合
AVD内のブラウザから有効な証明書としてアクセスできるようにするには
mkcertのルートCA証明書をAVD内にインストールします

## ルートCAインストール

ホスト側のmkcertがインストールしたルート証明書のインストール先を調べる

```sh:
mkcert -CAROOT
```

このディレクトリをwebサーバでホスト

```sh:
http-server -p 8000 -t (調べたディレクトリ)
```
※ポートは8000でなくてもよいです

エミュレータ内のブラウザから http://10.0.2.2:8000/ にアクセス
![emu-ca1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73427/03c9d006-317c-560c-2370-2bee98ec141d.png)

rootCA.pem をダウンロード
![emu-ca2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73427/685375f4-7b02-20be-7922-acde3bc2e3dd.png)
Certificate name を入力して `OK`
※エミュレータ内で端末のロックパスワード(パターンやPIN)を設定してない場合、ここで設定を求められる場合があります



## 試してみる

SSL証明書発行

```sh:mkcertでexample.comの証明書を発行する例
mkcert --cert-file=crt.pem --key-file=key.pem example.com
```

SSLサーバ起動

```sh:
http-server -S -C crt.pem -K key.pem -p 443 ./public
```

AVD内のブラウザから https://example.com/ にアクセスすると、SSLでアクセスできました
![emu-test-https.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73427/684c14e2-b38e-610b-b682-83350d2e2463.png)
※http-serverは古いバージョンのSSL(TLS v1.0など)に対応しておらず、
古いAndroidOSバージョンのAVDのブラウザでは証明書エラーになる場合があります