adbコマンドを使って、UE4エディタや外部ツールからAndroid端末にConsole Commandを送る方法について（エディタ拡張プラグイン配布）

# はじめに
モバイル開発の場合、画面を4本の指でタップすることで表示されるウィンドウを使うことで、実機上でConsole Commandを実行することが可能です。
<img width="640" alt="TM_Phone_Console.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/667cfafa-4675-c68d-4f69-f40fcbbe95ca.jpeg">
引用：http://api.unrealengine.com/JPN/Platforms/Mobile/PostProcessEffects/

また、「Session Frontend」や**UE4.22で正式リリースされた「Device Output Log」**を使用することで、UE4エディタから実機にConsole Commandを送信することが可能です。
![20190220011301.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/251cae45-c04b-c847-f122-d5d3985d90e0.png)
引用：http://pafuhana1213.hatenablog.com/entry/2019/02/20/013340

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/2c0eae5e-b600-8d4a-a76a-39289ad14e6a.png)
> 新機能：デバイス出力ウィンドウの改善
> アウトプットログ ウィンドウが大幅に改善され、実験的機能ではなくなりました。アウトプットログ ウィンドウを使用して、PC から iOS デバイスにコンソール コマンドを送信できます。デバイス出力ログにアクセスするには、メイン メニューから[Window (ウィンドウ)] > [Developer Tools (デベロッパーツール)] > [Device Output Log (アウトプットログ)] をクリックします。
>https://www.unrealengine.com/ja/blog/unreal-engine-4-22-released

Android端末の場合、UE4エディタから実機へのConsole Commandの送信処理にはadb(Android Debug Bridge)コマンドというものが使われています。このadbコマンドは非常に多機能でConsole Command送信以外にも様々な処理を行うことが可能です。そして、adbコマンドはUE4特有のものではないため、Unreal C++やBPだけでなくUE4以外のツールからも実行することが可能です。

本記事では、**「UE4プロジェクトからadbコマンドを呼び出す方法」**と**「adbコマンドを使ってAndroid端末にConsole Commandを送信する方法」**について解説します。これらを組み合わせることで、UE4エディタ上でadbコマンドを実行するEditor Utility Widgetを作成したり、JenkinsなどのCIツールからConsole Commandを送信することで自動テストなどの効率を向上させたりなどが可能になります。
[[UE4]エディタ上で動作するツール・エディタ拡張をUMGで簡単に作れる Editor Utility Widget について](https://qiita.com/EGJ-Kaz_Okada/items/9f530db3b53d0fde3f20)

なお、「細かい説明はいいからエディタ上で色んなadbコマンドを使いたい！」という方は以下の場所で公開しているプラグインをご利用ください。詳細はリンク先で。
https://github.com/pafuhana1213/AdbCommandWidgetSample
<img width="600" alt="ADB_Devices.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/1f08d330-6558-0139-dce0-4e733b83d56b.png">
> Android開発で使うadbコマンドをUE4エディタから実行できるツールです。adbコマンドを使うためだけにUE4以外のツール（コマンドプロンプトなど）を開くことが面倒だったので、UE4.22から入ったEditor Utility Widget機能を使って自分用に作成しました。
> 事前に用意されたadbコマンドのリストからどのコマンドを使用するか選択可能です
> コマンドを実行する対象の端末を選択、または接続中の全デバイスにadbコマンドを送る事が可能です
> コマンドの実行結果をツール下部から確認することも可能です
> コマンドの実行は非同期に行うため、コマンドが完了するまで作業を待つ必要はありません
> Editor Utility Widgetで実装しているため、BPだけで（ほぼ）カスタマイズ可能です。
> 開発はUE4.22.0で行いました。
> なお、手元の環境でしかテストをしていないため、動作保証はしていません。また、機能要望は受け付けていません。ご理解いただけますと幸いです。

# UE4とadbコマンドについて
モバイルVRを含むAndroid端末を使った開発において、adbコマンドは必要不可欠です。例えば接続中のAndroid端末のリストを表示するadbコマンド「adb devices」はよく使われます。
<img width="600" alt="ADB_Devices.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/176a954e-4988-defa-5aec-83647d4ad9a2.jpeg">
(引用：[公式ドキュメント「2.Android デバイスの設定」](http://api.unrealengine.com/JPN/Platforms/Android/GettingStarted/2/))

「adb devices」以外にも多数のコマンドがあります。そして、それらを使うことでWifi経由で端末と接続したり、端末とファイルをやり取りしたりなど、開発効率を格段に向上させることが可能です。特に複数端末を同時に動かしたい場合や有線だと煩わしいモバイルVR開発では非常に有用です。

[Android Developers 公式ドキュメント](https://developer.android.com/studio/command-line/adb)
[よく使うadbのコマンド](https://qiita.com/t2low/items/cb37cec5f864c4748e14)
[Android開発で役立つadbコマンド](https://www.itcowork.co.jp/blog/?p=2760)

UE4エディタでもadbコマンドは活用されており、エディタからAndroid端末にConsole Commandを送る処理は以下のコードで実装されています。

```cpp
inline void FAndroidTargetDevice::ExecuteConsoleCommand(const FString& ExecCommand) const
{
	FString AdbCommand = FString::Printf(TEXT("shell \"am broadcast -a android.intent.action.RUN -e cmd '%s'\""), *ExecCommand);
	ExecuteAdbCommand(AdbCommand, nullptr, nullptr);
}
```
このコードを見ての通り、Console Commandを送信するadbコマンドは以下のような形式になってます。細かい説明は割愛しますが、adbコマンドからシェルコマンドというものを呼び出す形です。この形式に従うことで、UE4外のツールからでもConsole Commandを送信できます。

```
shell "am broadcast -a android.intent.action.RUN -e cmd '●●●●●'"
(●●●●●：実行するConsoleCommand)
```
ただし、残念ながらこの処理はエンジン外には公開されていないため、プロジェクト内のBPやC++では使用することはできません。そのため、プロジェクト内で同様の処理を実装する必要があります（と言っても、コピペで十分対応完了です）。


# Console Commandを送信するadbコマンドを呼び出す処理の実装
まずはUE4エディタからadbコマンドを呼び出すための処理を実装します。上述の通り、UE4エディタでadbコマンドは活用されているので呼び出す処理は実装済みです( FAndroidTargetDevice.inl や FAndroidDeviceDetectionModule.cpp の ExecuteAdbCommand関数など )。しかし、残念ながらエンジン内の一部でしか呼び出せないようになっているので、実装コードをそのままプロジェクト側にコピペします。以下のコードはエンジン内の実装を簡略したものです。

```cpp
// Build.cs の PublicDependencyModuleNames に "AndroidDeviceDetection" を追加

#include "Interfaces/IAndroidDeviceDetectionModule.h"
#include "Interfaces/IAndroidDeviceDetection.h"

FString USampleBPLibrary::GetAdbPath()
{
	auto &AndroidDeviceDetection = FModuleManager::GetModuleChecked<IAndroidDeviceDetectionModule>("AndroidDeviceDetection");
	IAndroidDeviceDetection* DeviceDetection = AndroidDeviceDetection.GetAndroidDeviceDetection();
	return DeviceDetection->GetADBPath();
}

bool USampleBPLibrary::ExecuteAdbCommand(const FString& CommandLine, FString& OutStdOut, FString& OutStdErr, int32& OutErrorCode)
{
	OutStdOut.Empty();
	OutStdErr.Empty();
	FPlatformProcess::ExecProcess(*GetAdbPath(), *CommandLine, &OutErrorCode, &OutStdOut, &OutStdErr);

	if (OutErrorCode != 0)
	{
		return false;
	}
	return true;
}
```

上記の関数をBPノード化することで、以下のようにadbコマンドを呼び出すことが可能になります。あとはConsole Commandを送信するadbコマンドを指定するだけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/15172e45-e7d0-e8f9-0a77-133ff4828769.png)
先程実装したExecuteAdbCommandノードを使用する場合は以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/aa0a6e9b-83b0-6890-5f33-b23a86bc39cc.png)
これでUE4エディタからAndroid端末にConsole Commandを送信する処理をBPで実装できました。つまり、Editor Utility Widget機能を使うことで「よく使うConsole CommandをボタンひとつでAndroid端末に送信するツール」などを作ることが可能になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/82e36127-b44d-9791-407c-aaea78fd97fe.png)

前半で説明したとおり、adbコマンドはConsole Commandを送信する以外にも様々な機能があります。そして、それらをUE4エディタ内外で呼び出せるようにすることでAndroid開発の効率を大きく向上させることが可能です。是非いろいろ試してみてください！また、その際は以下のプラグインが少しでも参考になれば幸いです。
https://github.com/pafuhana1213/AdbCommandWidgetSample

# おまけ
## Androidパッケージ名の取得
```cpp
FString UAdbCommandEditorWidgetBPLibrary::GetAndroidPackageName()
{
	FString PackageName = GetMutableDefault<UAndroidRuntimeSettings>()->PackageName;
	if (PackageName.Contains("[PROJECT]"))
	{
		PackageName = PackageName.Replace(TEXT("[PROJECT]"), FApp::GetProjectName());
	}
	return PackageName;
}
```

## インストール済みのパッケージを起動するadbコマンド
```
shell am start -n ●●●●●/com.epicgames.ue4.SplashActivity 
(●●●●●：Androidパッケージ名)
```