はじめに
UnityのSceneをAndroidのSubView(FrameLayout)として埋め込むまで
https://qiita.com/_nonono/items/253aa15d6027ecc8ad66
このような記事があり、AndroidにUnityのシーンをFrameLayoutに埋め込むことができます(便利
Unityで開発せずビルド成果物(AARファイル)のみ必要な場合
1.指定のバージョンのUnityをインストール
2.Unityを立ち上げAndroidプロジェクトをExport
3.Android Studioでビルド
上の3つの作業を手作業で行うので一苦労だと思います
Unity、Android Studioのバージョンを意識したりしなければならいので良い方法が必要です
「なんとか良い方法を!」と思って Unityの入ったDockerイメージを使ってAARの生成を自動化
してみたので、作業を下に記していきます
TL;DR
いきなり一連の作業をスクリプトにできないので、dockerの中で作業を1つずつして、最後にスクリプトにまとめます
やったこと
docker pull gableroux/unity3d
- Dockerコンテナに入りライセンスファイルを用意
- ライセンスファイルをコピー
- ビルド用クラスを作成
- Unityプロジェクトをビルド
- build.gradleとAndroidManifest.xmlを編集
- GradleでAndroidプロジェクトをビルド
- build.shを書いて完全自動化
実際の環境
・MacBook Pro (15-inch, 2016) macOS 10.13.6(17G10007)
・docker desktop ver. 2.1.0.5(40693)
1. Unityの入ったDockerイメージをpullする
まずは、Unityの入っているDockerイメージをインターネットから落としてきます
次のコマンドを実行すると最新版のコンテナが自分のローカルに保存されます
docker pull gableroux/unity3d
しかし、このイメージではAndroidプロジェクトを生成/ビルドができないので、Unityバージョン
とUnityプロジェクトのビルドターゲット
を指定しなければなりません。
この記事では、 Unity 2018.4.5f1
でビルドターゲットをAndroid
とするので、Dockerイメージのtagに2018.4.5f1-android
を指定します
※目的のバージョンのイメージが無い場合があるので、 DockerHub のページで確認しておきましょう
docker pull gableroux/unity3d:2018.4.5f1-android
docker images
を実行するとpullしてきたイメージが確認できます
cha84rakanal$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
gableroux/unity3d 2018.4.5f1-android 3cc6afa5c2bd 3 months ago 6.7GB
docker run -it {image name} bash
を実行すればイメージからコンテナが作成され、Dokcer内のターミナルに接続できる
なので、接続してUnity
とAndroid SDK
があるかを確認しておきます
cha84rakanal$ docker run -it --rm gableroux/unity3d:2018.4.5f1-android bash
root@7462f939f4d0:/# echo $ANDROID_HOME
/opt/android-sdk-linux
root@7462f939f4d0:/# ls /opt/
android-sdk-linux Unity Unity-2018.4.5f1
root@7462f939f4d0:/#
2. Dockerコンテナに入ったUnity用のライセンスを生成する(1回のみ・手作業)
普段使うmacOSやWindowsでUnityを一番最初に起動すると次の画面が出てアクティベーションをする必要があります
次の作業は、DockerコンテナにインストールされているUnityのアクティベーションを行います
まず、Unityプロジェクトジェクトのディレクトリに移動してdockerコンテナを立ち上げます
※ パスワードを平打ちするので気をつけましょう
cd /path/to/project
docker run -it --rm \
-e "UNITY_USERNAME=username@example.com" \
-e "UNITY_PASSWORD=example_password" \
-e "TEST_PLATFORM=linux" \
-e "WORKDIR=/root/project" \
-v "$(pwd):/root/project" \
gableroux/unity3d:gableroux/unity3d:2018.4.5f1-android \
bash
次に、Dockerコンテナ内で以下のコマンドを実行します
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
/opt/Unity/Editor/Unity \
-logFile /dev/stdout \
-batchmode \
-username "$UNITY_USERNAME" -password "$UNITY_PASSWORD"
すると、出力に次のようなXMLが表示されるので、表示されたXMLを unity3d.alf
というファイル名で保存します
LICENSE SYSTEM [2017723 8:6:38] Posting <?xml version="1.0" encoding="UTF-8"?><root><SystemInfo><IsoCode>en</IsoCode><UserName>[...]
もし、XMLではなく401
エラーが出た場合は、2段階認証を切りましょう
Googleでサインイン
やFaceBookでサインイン
でUnity IDを作成している場合でも 401
エラーがでるので、メールアドレスから作成したUnityIDを使いましょう
Can't activate unity: No sufficient permissions while processing request HTTP error code 401
unity3d.alf
が用意できたら https://license.unity3d.com/manual にアクセスします。アクセスしたらサイトの指示に従ってunity3d.alf
をアップロード、質問に答えていきましょう。すべて終わるとUnity_v2018.x.ulf
かUnity_v2019.x.ulf
がダウンロードできるので保存しておきます。
このUnity_v*.x.ulfファイル
は今後必要になるので大切に保管しておきます
プロジェクトチームの誰かがこの作業をやれば、Unityのバージョンを変えない限り、
3以降の作業でUnity_v2018.x.ulf
を使いまわすことができます(多分
※アクティベーションの詳しい手順は このページ に書いてありますが、まとめとしてこの記事にも記しています
3. Dockerコンテナに入ったUnityにライセンスを当てる
2の手順でダウンロードしてきたファイルUnity_v2018.x.ulf
をUnityプロジェクトのルートディレクトにおきます
/path/to/project
├── Assets
├── Library
├── Logs
├── Packages
├── ProjectSettings
├── README.md
└── Unity_v2018.x.ulf
次に、Unityプロジェクトジェクトのディレクトリに移動してdockerコンテナを立ち上げます
cd /path/to/project
docker run -it --rm \
-v "$(pwd):/root/project" \
gableroux/unity3d:gableroux/unity3d:2018.4.5f1-android \
bash
ここから先の作業7.が終わるまでは、dockerコンテナ内のターミナルでexit
をしてはいけません
ライセンスファイルをUnityプロジェクトのルートディレクトに設置できたら、dockerコンテナ内のターミナルで次のコマンドを実行します。これでライセンスファイルの設置は完了です
set -e
set -x
mkdir -p /root/.cache/unity3d
mkdir -p /root/.local/share/unity3d/Unity/
set +x
cp ~/project/Unity_v2018.x.ulf /root/.local/share/unity3d/Unity/Unity_lic.ulf
4. ビルド用クラスを作成してAssets/Scripts/Editorに配置
Unityプロジェクトをコマンドラインからビルドできるように次のC#ソースをAssets/Scripts/Editor
に設置します
using UnityEngine;
using System;
using System.Linq;
public static class ApplicationBuild {
private static string[] GetAllScenePaths() {
return EditorBuildSettings.scenes
.Where(scene => scene.enabled)
.Select(scene => scene.path)
.ToArray();
}
public static void AndroidBuild() {
string[] scenes = GetAllScenePaths();
BuildPipeline.BuildPlayer(scenes, "./Build/", BuildTarget.Android, BuildOptions.AcceptExternalModificationsToPlayer);
}
}
公式ドキュメント を確認すると、 ビルドのパラメータを色々設定できます。
今回は、プロジェクトのエクポートパスは./Build
、ビルドターゲットはAndroidなので BuildTarget.Android
、AndroidのビルドはExternalで行うのでオプションに BuildOptions.AcceptExternalModificationsToPlayer
を指定しています
BuildPipeline.BuildPlayer
BuildPlayer(EditorBuildSettingsScene[] levels, string locationPathName, BuildTarget target, BuildOptions options)
パラメータ | |
---|---|
levels | The Scenes to be included in the build. If empty, the currently open Scene will be built. Paths are relative to the project folder (Assets/MyLevels/MyScene.unity). |
locationPathName | 成果物の保存先のパス |
target | ビルドする BuildTarget |
options | ビルドしたプレイヤーを実行するか、などの追加の BuildOptions |
5. コマンドラインからUnityプロジェクトをビルド
次のコマンドでUnityプロジェクトをコマンドラインからビルドできます
/opt/Unity/Editor/Unity -batchmode -quit -nographics -logFile ./build.log -projectPath . -executeMethod ApplicationBuild.AndroidBuild
ログは ./build.log
に保存されるので、エディタ等で確認するとビルドが進んでるのがわかります
ビルド中は、ターミナルに何かこれといって表示されるものは無いです(無視できるエラーとかは出る
ビルドが完了するとログに次の行が記録されます
Exiting batchmode successfully now!
※成果物の保存先のパス ./Build
ディレクトリがすでにあるとビルドが停止してしまうので消しておきましょう
6. APKではなくAARを作成するようにbuild.gradleとAndroidManifest.xmlを編集
5の作業が終わり、ビルドが成功すると、./Build
ディレクトリにAndroidプロジェクトが生成されます
/path/to/project
├── Assets
├── Build
│ └── {Project Name}
│ ├── build.gradle
│ ├── gradle.properties
│ ├── libs
│ ├── local.properties
│ ├── proguard-unity.txt
│ └── src
├── Library
├── Logs
├── Packages
├── ProjectSettings
├── README.md
└── Unity_v2018.x.ulf
デバイスにインストールする.apk
の作成であれば、gradle
コマンドでビルドして終了です
今回は、.aar
の作成なので、build.gradle
とAndroidManifest.xml
を編集する必要があります
build.gradle
-
apply plugin: 'com.android.application'
をapply plugin: 'com.android.library'
に変更 -
applicationId 'com.project.unitytest'
を削除 -
bundle
をコメントアウト(Unity2018.3.x以降??)
--- apply plugin: 'com.android.application'
+++ apply plugin: 'com.android.library'
--- applicationId 'com.project.unitytest'
--- bundle {
+++ /*bundle {
language {
enableSplit = false
}
density {
enableSplit = false
}
abi {
enableSplit = true
}
--- }
+++ }*/
AndroidManifest.xml
- 該当のintent-filterタグとその子をすべてコメントアウト
<!--<intent-filter>-->
<!--<action android:name="android.intent.action.MAIN" />-->
<!--<category android:name="android.intent.category.LAUNCHER" />-->
<!--<category android:name="android.intent.category.LEANBACK_LAUNCHER" />-->
<!--</intent-filter>-->
UnityプロジェクトからAARファイルの生成を行うには、この作業も自動化しておく必要があるので、
UnityのPostProcessの機構を使って自動化しておきます
[Unity] PostProcessでビルド後に処理を差し込む
https://qiita.com/edo_m18/items/346439f7678218e85e69
※ build.gradle
の文字コードは UTF-8
で書き出すこと、 C#のでのUTF8Encoding
はUTF-8 with BOM
であるので注意が必要。 UTF-8 with BOM
のbuild.gradle
をgradle
に渡すとエラーになるので注意
※UnityのPostProcessBuildにはこの記事ではふれません
※build.gradle
の bundle
のコメントアウトだが このページ によれば次に示す置換でも問題ない
--- bundle {
+++ splits {
language {
--- enableSplit = false
+++ enable false
}
density {
--- enableSplit = false
+++ enable false
}
abi {
--- enableSplit = true
+++ enable true
}
}
build_text = build_text.Replace("bundle {", "splits {");
build_text = build_text.Replace("enableSplit = false", "enable false");
build_text = build_text.Replace("enableSplit = true", "enable true");
7. コマンドラインでAndroidプロジェクトをビルド
残る作業は./Build
ディレクトリに生成されたAndroidプロジェクトをビルドしてAARファイルを生成するだけです
生成されたAndroidプロジェクトのディレクトリ(build.gradle
があるディレクトリ)に移動して次のコマンドを実行するだけです
gradle bundleDebugAar
gradle bundleReleaseAar
デバッグとリリースがあるので必要に応じて使い分けましょう
ビルドが成功するとプロジェクトのディレクトリにbuild
ディレクトリが生成されて、
その中に {PROJECT_NAME}-debug.aar
{PROJECT_NAME}-release.aar
が生成されます
/path/to/project
├── Assets
├── Build
│ └── {Project Name}
│ ├── build
│ │ └── outputs
│ │ └── aar
│ │ ├── {PROJECT_NAME}-debug.aar
│ │ └── {PROJECT_NAME}-release.aar
│ ├── build.gradle
│ ├── gradle.properties
│ ├── libs
│ ├── local.properties
│ ├── proguard-unity.txt
│ └── src
├── Library
├── Logs
├── Packages
├── ProjectSettings
├── README.md
└── Unity_v2018.x.ulf
8. 作業をシェルスクリプトにまとめる
4から7の作業をまとめて、コマンド一行でAARファイルの生成できるようにします
ライセンスファイルはUnityプロジェクトのルートディレクトリに設置して、6の作業はUnityのPostProcessBuildで自動化しておきましょう
そうして作業をまとめたスクリプトが次になります
#!/usr/bin/env bash
set -e
set -x
mkdir -p /root/.cache/unity3d
mkdir -p /root/.local/share/unity3d/Unity/
set +x
cp ~/project/Unity_v2018.x.ulf /root/.local/share/unity3d/Unity/Unity_lic.ulf
cd ~/project/ && rm -r ./Build && /opt/Unity/Editor/Unity -batchmode -quit -nographics -logFile ./build.log -projectPath . -executeMethod ApplicationBuild.AndroidBuild
cd ~/project/Build/{Project Name} && gradle bundleDebugAar
Unityプロジェクトのルートディレクトリに移動して、dockerコンテナ内でbuild.sh
を実行します
cd /path/to/project
chmod 777 build.sh
docker run -it --rm \
-v "$(pwd):/root/project" \
gableroux/unity3d:gableroux/unity3d:2018.4.5f1-android \
/bin/bash -c "/root/project/build.sh"
さいごに
これでコマンドを実行してビルドされるのを待つだけになりました!
これをBitbucket Pipeline
や CircleCI
、 GitHub Actions
とかのCIツールに載せていけるといいですね
まとめている間に、既にmacOSやWindowsにUnityがインストールされていて、かつ、Android SDKがインストールされているなら、Docker上じゃなくていいかなと思いました
余談
cha84rakanal$ time docker run -it --rm -e "WORKDIR=/root/project" -v "$(pwd):/root/project" gableroux/unity3d:2018.4.5f1-android /bin/bash -c "/root/project/build.sh"
+ mkdir -p /root/.cache/unity3d
+ mkdir -p /root/.local/share/unity3d/Unity/
+ set +x
ALSA lib confmisc.c:767:(parse_card) cannot find card '0'
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1246:(snd_func_refer) error evaluating name
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5007:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM default
ALSA lib confmisc.c:767:(parse_card) cannot find card '0'
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1246:(snd_func_refer) error evaluating name
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5007:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM default
/home/builduser/buildslave/unity/build/Editor/Platform/Linux/UsbDevices.cpp:UsbDevicesQuery
Welcome to Gradle 5.1.1!
Here are the highlights of this release:
- Control which dependencies can be retrieved from which repositories
- Production-ready configuration avoidance APIs
For more details see https://docs.gradle.org/5.1.1/release-notes.html
Starting a Gradle Daemon (subsequent builds will be faster)
> Task :help
Welcome to Gradle 5.1.1.
To run a build, run gradle <task> ...
To see a list of available tasks, run gradle tasks
To see a list of command-line options, run gradle --help
To see more detail about a task, run gradle help --task <task>
For troubleshooting, visit https://help.gradle.org
BUILD SUCCESSFUL in 5s
1 actionable task: 1 executed
debugger-agent: Unable to listen on 28
Starting a Gradle Daemon (subsequent builds will be faster)
Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.5.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 2m 7s
21 actionable tasks: 21 executed
real 33m9.065s
user 0m0.162s
sys 0m0.178s
cha84rakanal$
time
コマンドで実行時間を図ったら30分もビルドしてるので、dockerコンテナ内よりホスト側でビルドした方がはやいやんけw