【Node.js】Macに接続しているAndroidのWifi情報をブラウザから見る【Android開発支援】

# こんなことがあった


企画さん「Android端末にDNS設定したんですがうまく動きません」
僕「どれどれ」
[ipinfoアプリ](https://play.google.com/store/apps/details?id=com.ipinfo)を立ち上げる。
ゲートウェイとIPアドレスを覚える
設定画面を開いてWifi設定を開いて接続してるWifiのカラムを長押し、「詳細設定項目」をタップ、「IP設定」をタップして「静的」を選択、IPアドレス、ゲートウェイ、DNS1に入力しようとする。
 
僕「ゲートウェイいくつだっけ・・・」
 
一旦設定アプリをバックグラウンドに、ipinfoアプリをフォアグラウンドに、ゲートウェイIPをコピー、再び設定アプリをフォアグラウンドに、ゲートウェイの欄にペースト、続いて
 
僕「IPアドレスいくつだっけ・・・」
 
一旦設定アプリをバックグラウンドに、ipinfoアプリをフォアグラウンドに、IPをコピー、再び設定アプリをフォアグラウンドに、IPの欄にペースト、続いて
 
僕「DNS1にはx.x.x.x」
僕「あ、ミスってコピペした」
そのとき誤ってホームボタンを押した。
再び設定画面を開いてWifi設定を開いて接続してるWifiのカラムを長押し、「詳細設定項目」をタップ、「IP設定」をタップして「静的」を選択、IPアドレス、ゲートウェイ、DNS1を確認しようとすると
IP設定がDHCPに戻ってるうううううううううううううううううううううううううう
 
全部やりなおしいいいいいいいいいいいいいいいいいいいいいいいいいいいいいいいいい
 
僕「**くそがあああああああああああああああああああああああ**」
 
企画さん（なにこのエンジニア突然叫びだしたキモい）

## だからつくることにした、開発端末に接続しているAndroidのネットワーク情報取るやーつ
PC画面からネットワーク情報を確認できるツールをつくった。
勉強も兼ねてnode.jsで。あとadbコマンドの勉強も。
あれこれコードを書いてはナニコレおもしろいとか思っていたが、コードを最適化していったら大した行数じゃなくなった。
よく考えたらコマンドライン実行した結果をただ画面に表示してるだけで、あんまnode関係ない。
でも同期にいろいろ教わることもできたのでJavaScriptの勉強にはなった。

## 構想
* Node.jsでadbコマンドを実行 → 出力結果をWebページに表示するだけ
* MacOSで動作する

## Node.js導入とexpress導入

Node.jsの導入
まあ方法はいくらでもあるが、下記参考で入れましょう
[HamaTechさんの記事](http://qiita.com/HamaTech/items/adc3b07565eb29b0ed9f)

expressの導入
[pakilnさんの記事](http://qiita.com/pakiln/items/826a9199697576e2e24a)


## child_processを使います
nodeからコマンド実行の結果を受けるにはchild_processモジュールが必要らしい。Nodeのバージョンによってはない可能性があるので都度インストールしないといけないかも。
とりあえず自分の実行環境では標準で入っていたので、下記を参考にプログラムに追記する
[Node.jsからシェルコマンドを実行する](http://tkybpp.hatenablog.com/entry/2016/04/25/163246)

```JavaScript
var execSync = require("child_process").execSync;
```
※これは同期的関数です。非同期で処理する場合はexec関数があります。

#### 使い方
```JavaScript
execSync("ls").toString();// lsの実行結果を取得できる
```

```JavaScript
function getAdbResult() {
    var resultObj = {
                        ipaddress: execSync("adb shell ip route | cut -d ' ' -f 12").toString(),
                        device: execSync("adb devices | sed -n '2,2p' | cut -f 1").toString(),
                        gateway: execSync("adb shell cat /proc/net/arp | sed -n '2,2p' | cut -d' ' -f 1").toString(),
                        dns1: execSync("adb shell getprop net.dns1").toString(),
                        dns2: execSync("adb shell getprop net.dns2").toString(),
                        wifistat: execSync("adb shell dumpsys netstats | grep -E 'iface' | sed -n '1,1p'").toString(),
                        devicemodel: execSync("adb shell getprop ro.product.model").toString(),
                        androidversion: execSync("adb shell getprop ro.build.version.release").toString()
                    };
    return resultObj;
}
```
こんな感じでJSONオブジェクトにして、Viewに渡すデータをつくる。

各adbコマンドや、シェルの組み合わせの解説はここではしないが、このコマンド群で必要な情報は取れる。

※adbコマンドが実行できていないなどのエラーが出る場合はadbコマンドのパスを通す必要があります。
[adbをMacのターミナルで使えるようにする](http://qiita.com/furusin_oriver/items/f956848788c7a63922bd)

ポイントはこの辺です。
* execSync関数またはexec関数でadbコマンドを実行
* adbコマンドの実行結果しだいではcut,sedを使って加工してやる

Viewにデータを渡して表示する部分

```JavaScript
var express = require("express");
var app = express();

// listen()メソッドを実行して3000番ポートで待受。
var server = app.listen(3000, function() {
    console.log("Node.js is listening to PORT:" + server.address().port);
});

// "/"へのGETリクエストでindex.ejsを表示する。拡張子(.ejs)は省略されているらしい
app.get("/", function(req, res, next) {
    res.render("index",getAdbResult()); // さっきつくっておいた関数を呼んでJsonを渡すだけ
});
```

## 追加修正したプログラムの全体

```JavaScript:app.js
// 1. expressモジュールをロードし、インスタンス化してappに代入
var express = require("express");
var app = express();
var execSync = require("child_process").execSync;

// 2, listen()メソッドを実行して3000番ポートで待受。
var server = app.listen(3000, function() {
    console.log("Node.js is listening to PORT:" + server.address().port);
});

// View EngineにEJSを指定。
app.set('view engine', 'ejs');

// "/"へのGETリクエストでindex.ejsを表示する。拡張子(.ejs)は省略されているらしい
app.get("/", function(req, res, next) {
    res.render("index",getAdbResult());
});

function getAdbResult() {
    var resultObj = {
                        ipaddress: execSync("adb shell ip route | cut -d ' ' -f 12").toString(),
                        device: execSync("adb devices | sed -n '2,2p' | cut -f 1").toString(),
                        gateway: execSync("adb shell cat /proc/net/arp | sed -n '2,2p' | cut -d' ' -f 1").toString(),
                        dns1: execSync("adb shell getprop net.dns1").toString(),
                        dns2: execSync("adb shell getprop net.dns2").toString(),
                        wifistat: execSync("adb shell dumpsys netstats | grep -E 'iface' | sed -n '1,1p'").toString(),
                        devicemodel: execSync("adb shell getprop ro.product.model").toString(),
                        androidversion: execSync("adb shell getprop ro.build.version.release").toString()
                    };
    return resultObj;
}
```

```ejs:./views/index.ejs
<!doctype html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Connected Device Info.</title>
</head>
<body>
    <h1>Your Connected Device Info</h1>
    <p>Device ID: <%= device %></p>
    <p>Device Model: <%= devicemodel %></p>
    <p>Android Version: <%= androidversion %></p>
    <p>Wifi Status: <%= wifistat %></p>
    <p>IPAddress: <%= ipaddress %></p>
    <p>Gateway: <%= gateway %></p>
    <p>DNS1: <%= dns1 %></p>
    <p>DNS2: <%= dns2 %></p>
</body>
</html>
```

[https://github.com/shotakeu/AndroidNetworkInfoGetter](https://github.com/shotakeu/AndroidNetworkInfoGetter)
一応公開しました。

## 現状のUI
いっちょまえにCSSやら適応してみた結果
![https://i1.wp.com/takelab.sub.jp/wp-content/uploads/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2017-09-17-10.32.29.png?w=676](https://i1.wp.com/takelab.sub.jp/wp-content/uploads/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2017-09-17-10.32.29.png?w=676)