ADB備忘録

#エンジニア一年生のバッチファイル第二弾
###あらすじ
なんでもやりますから仕事をくださいと言った。
アンドロイドのお仕事があるよと言われてありがたく頂戴した。
いわゆるキッティングというやつで、そこそこ量もあったので、せっかくだから自動化した。

※なお本稿の筆者は今年の八月に初めてエンジニアとしての勉強を始めました。
誤認識等あれば後学のためご指摘いただければ幸いです。

***

###前提
- Android端末は[設定]-[システム]-[ビルド番号]連打を済ませて開発オプションを表示してある　[やり方（Qiita内リンク）](https://qiita.com/knakamigawa/items/5b8bd2793920b517bf25)
- [開発オプション]をオンにして、[USBデバッグ]のスイッチをオンにした状態で、データ転送可能なUSBケーブルを使ってPCに接続している
- アプリのインストールをさせる場合、APKというやつを抜き出してPC側に持っている必要がある：[やり方](https://blog.clock-up.jp/entry/2015/02/28/android-pull-apk)：なお筆者はコマンドプロンプトさんでgrepを使う方法？と困惑した挙句 >> package.txt　として書き出してエディタの検索機能に拾っていただきました。
  - あとそういえば引っこ抜いてくるときは「base.APK」的な名前だったんですけど実際APKリストに載ってた名前が違ってたので「base.APK」をバックアップとしてコピー&リネームでリストと同じ名前にしたやつを流し込みましたが、正常にインストール、動作しているもようです。

##使ったものたち
***バッチ側***
- set　：準備 / set /p check=""でpause代わりに
- %~dp0　：準備で使った / 現在地の取得
- pushd / popd　：証跡pngの保存先とAPKの保存先を行ったり来たりした
- timeout　：処理が走りがち（端末側の画面遷移が遅かった）だったので止めた
- echo　：ログファイル作るときに echo f | echo piyo >> ~.log
- call　：タスクキルの操作をひとまとめにして呼んでた
- if( else )　：インストールちゃんと終わったかどうかとか判別してた
- goto　：「間違いなくこの処理をしてほしい」時に指定して飛ばした

***adb側***
- "shell"がつくやつ
  - am start　：アプリを立ち上げた
  - input( tap/keyevent/swipe/text )　：Android機の画面操作をした
  - screencap　：Android機でスクショを撮った
  - rm　：↓のpullはコピーなのでAndroid機にデータが残る　のでrmで消した
- "shell"がつかないやつ
  - pull　：screencapで撮ったスクショをPCに引っ張った
  - install　：PC側で持っているAPKを指定してAndroid機にインストールさせた
  - devices　：PCと接続されている端末のチェックをした

##気が狂ったポイント
startで[設定]を呼ぶとする。
立ち上がった時点でkeyevent20を送ったときの動きと、自動化したときにstart→keyevent20の流れで送った時の挙動が違う。
###しんどかったからtapで座標指定した。

##構成
- 準備
  - @echo off：実質呪文
  - set here=%~dp0：実質呪文
    - %here%は~~/imakoko/のように末尾に/がついているので、気になる時は%here:~0,-1%とかするといいかもしれない。→参照　[バッチ：文字列の加工](https://web.plus-idea.net/2016/09/windows-bat-substr/)
  - set PATH=%PATH%;%here%-adbのセットアップファイルを置いてるとこ-
  - [pushd](https://qiita.com/sta/items/8cab80fe74b8dcfa5336) "%here%"
    - この後Android機に流し込むAPKファイルが同じフォルダ内にあるので現在地をはっきりさせておきたかった&&後で戻ってきたかったのでcdじゃなくてpushdにした
  - adb devices
    - ↑でパスを通したのがちゃんと通っているか（通っていなければエラー出る）&&セットアップ対象のAndroid端末がちゃんとコマンドを受け付けるかどうか

地味に困ったのはAndroid端末にコマンドを送るときにドライバが必要だったこと。
自宅PCなら余裕でやったけれども会社のPCでは怖い。そういうものだと思う。
今回はメーカの公式HPからドライバをDLできたので非常に助かりました。

***

- 処理
  - adb shell am start -a android.intent.action.MAIN -n com.android.settings/.Settings：設定を開く（※いまひとつ理解はできていない）
    - -a：<ACTION>って書いてあったのでactionって書いてあるとこを書いた
    - -n：<COMPONENT>って書いてあった。「何をするどこを開きたいの」って聞かれているところだと解釈している（[設定]以下のメニューとかたしかここで直で指定できた）
  - adb shell input ( tap/keyevent/text )：画面操作用
    - タップするときは座標を指定する。[設定]-[開発オプション]-[タップ位置を表示]的なメニューをオンにすると画面上に出る。左上がx,y/0,0と思う。
    - textでマルチバイト文字（日本語だいたいそう）を指定するとえらいことになるらしいのでやめた方がいいと思った。
    - 参考までに　[Windowsでadbコマンドを使用する際の注意](https://qiita.com/satosystems/items/3f78c3abc4c3dbde3ef9)[adbコマンドを使ってマルチバイトテキストをスマホに送る方法](https://qiita.com/yuki-nakamura/items/4bd0ea7524521e731335)[Android 端末にadbで日本語を送りたい](https://teratail.com/questions/19574
5) /筆者はビビりなので、特に必要に駆られもしなかったということもありADBKeyboardを試していません。
  - adb shell input swipe
    - 始点と終点を**始x y 終x y**の順番で書く。スワイプにかける時間を指定するときは**始x y 終x y 時間**の順番で書く。ここで時間を何千とかにするとアイコンを握ったままスワイプさせて動かすとかもできた。時間の単位はミリ秒。
  - adb shell screencap -p <filePATH>：証跡管理用
    - [やり方（Qiita内リンク）](https://qiita.com/TNaruto/items/b2407f5668e15e42bedd)：SDCard以下を指定すると権限がない旨のエラーが発生したのでSDCard内に保存し削除した。-pは拡張子を「png」で保存するオプション。-pを外しても、保存の時に<PATH>/piyo.png　と指定したら問題なくpngで保存されるらしい。【参考】[screencapに対する考察 - adbでスクリーンキャプチャを取る方法（Qiita内リン
ク）](https://qiita.com/frameair/items/0c8113c716f87ccb8a37)

***

- 分岐
  - APKインストールの時
    - 成功したら「Success」と標準出力に出てくるので、adb install -r <APK> | find /c "Success"　で　if %ERRORLEVEL%==0 ( インストールが完了したときの処理 ) else ( インストールが完了しなかったときの処理 )にした。
    - この時の分岐は「やれって言ったことだけやってほしい」のでgotoで確実に処理を飛ばすことにした。ラベル読み込みで処理遅延が出るという[記事（Qiita内リンク）](https://qiita.com/sawa_tsuka/items/afd17bb4d0532d5288ad)を見かけたが、現時点での筆者の技量では速度はさほど重視されていないため。
  - タスクキルの時
    - 厳密に言えば分岐ではないがcallでラベルを呼んできた。[設定]の中でいろんな項目の設定をしたいが[戻る]を使うと処理や画面、メニューの表示形式がブレる、というような現象が発生していたため。
    - callで呼ぶラベルの末尾にはexit /bを使うこと。でないと帰ってこなくなってバッチごと終わる。uleFone触ったときはタスクキル後に「deep cleaning」かなんかの表示が出てたのでtimeoutを入れた。

***

##参考資料
一年生が頑張って解説をしようするより資料を列挙した方が後々よいと思う。

- [input keyevent](https://seesaawiki.jp/w/moonlight_aska/d/%A5%AD%A1%BC%A5%B3%A1%BC%A5%C9%B0%EC%CD%F7)
  - keyeventの一覧。19～23あたりと4、61、66は頻繁に使った。

***

###メモ
- setでpathを通すとコマンドプロンプトを落とした後はpath追加前の状態に戻る　→　%PATH%の中身を他の処理に持ち越すことがない　→　安心
- Wi-Fi経由での端末への接続　→　adb connect　<ip>
  - 次回試せるときが来たら同一ネットワークに乗せなければならないのかどうか、Android端末側は4G回線でもいいのかどうか　は確認したい
  - ***ポートを開ける必要があるかもしれない***
  - **adb tcpip 5555 | findstr /b C:/"restarting"**
    - ※"restarting"はtcpipのコマンドが正常終了したときに標準出力される
- adb shell input KeyEvent ~のやつはKEYCODE_TAB的な奴で指定しようというのが当初の目論見だったが、そんなコマンドはない的なエラーとヘルプが出たので数字で指定をした
- 今回はやらなかったが順次実行なら**&&**でコマンドをつなげばできるらしい
- アプリの実行は**run-as**でもできるらしい（インストールさせずにテスト的に動かすとかそういうやつだろうかと思いつつ試していないので試してみたい）
- アプリのアンインストールは**uninstall [-k] package**でできる。-kオプションはキャッシュ等を保持するオプションなので、不要なら外して全部まるごと消せばよい
- みんな大好きGET EVENTは**adb shell getevent -pl**でやる
- 例のdd[【参考】（Qiita内）](https://qiita.com/pm11op/items/e0142d156423c95e407c)
  - > 操作の受け取り（入力）を操作（出力）に引き継ぐ
  - > adb shell "dd if=/dev/input/event5 of=/sdcard/sample2"
  - > adb shell "dd if=/sdcard/sample2 of=/dev/input/event5"
  - 尚例のddを使うには***→getevemtでdev\input\~~に書き出す→どっかしらのテキストファイルにリダイレクト→リダイレクト先のテキストファイルを開き、中身をバイナリに変換して配列化し、sendeventの位置として送る***必要があるらしい。
    - ファイル→バイナリ：certutil -encodehex [コマンド] <変換元ファイル名> <変換先ファイル名>
    - バイナリ→ファイル：certutil -decodehex [コマンド] <変換元ファイル名> <変換先ファイル名>
    - > getevent /dev/input/event1 > /sdcard/event.txt
    - > 　（[Ctrl]+[C]を押下すると記録を終了する）
    - > cat /sdcard/event.txt|while read a;do set $a;sendevent /dev/input/event1 $((0x$1)) $((0x$2)) $((0x$3));done
    - [【参考】](https://blog.8796.jp/8796kanri/2014/03/android%E3%81%AEgetevent%E3%81%A8sendevent%E3%82%92%E7%B0%A1%E5%8D%98%E3%81%AB%E4%BD%BF%E3%81%8A%E3%81%86.html)
    - [【参考２】](https://blog.totoraj.net/article/2017-09-25/adb/)
- adbは接続してしまった後はUNIXベースの技術であるので、UNIXのコマンドが使えることも多いらしい　※ただし筆者はUNIXと聞いたらRedhatとかCentOSが出てきて「それLINUXや」と一人芝居をする程度の人間　[【参考】](https://www.javadrive.jp/android/commnadline/index5.html)

##ふりかえり
- 各コマンドのオプション等を理解する間もなく一日で組んで二日目にテストしながら実機作業だったので、動いたけど本当に正しいのかがわからない
  - 次回までにリファレンスを呼んでみたりQiitaを散歩したりで勉強したい
- Qiitaでみんなが言ってるなーと思ってはいたけどinputでの操作がだいぶ遅い
  - keyeventでバンバン羅列して送ったら歯抜けになってあらぬところを操作しはじめたりもしたので、なるほど遅いのにもきっと理由があるのだろう、とは思った。それにしてもたしかに遅い。しかしddとかその辺は一日では組めないと思って諦めた。これもできれば次回までに情報集めておきたい
- とはいっても次回がいつ来るかの予定は未定なのでとりあえず案件的には無事終了してよかったなというきもち。次の仕事がほしい（来ない）
- 複数の端末を接続して、例えば「端末ごとの名前のついたフォルダにスクショを引っ張ってくる」というような画一ではない動作をさせた場合、処理が混線してえらいことになるらしいと聞いてビビってやらなかった。実機がいっぱいあるうちに試しておけばよかった

***

自分用まとめなので、使ったものたちに書いてるけど準備とか分岐とかそこへんで出てきてないやつとかもあります。追記のご希望等なにかあればご連絡ください。