はじめに
UE4でAndroid向けのプラグインを作るときにサードパーティのライブラリを追加したり設定ファイルを変更したいことがあります。
プラグインを組み込んだプロジェクトでそんな変更をするのは大変です。
そこでこれらの設定をビルドツールで行い、凝ったプラグインでも簡単に導入することができるようにしたものがUnreal Plugin Languageです。
以下では、利用例やリファレンスを紹介します。
追記
公式ドキュメントにもUnreal プラグイン言語が作成されています。
利用例
こまけーことはいいんだ、という人は利用例を見た方が早いかもしれません。
GitHubとUE4をインストールしたフォルダのどちらでも見れますので、両方のパスを記載します。
※UE4のソースにアクセスするためには登録が必要なので、エンジンのソースコード取得とビルド手順のまとめ UE4.6改訂版を参考にしてください。サードパーティのプラグインは登録なしに見ることができます。
- GitHubのUE4のソース
- GearVR Plugin
- GoogleVR Plugin
- GoogleVRController Module
- GoogleVRHMD Module
- インストールしたUE4のソース
-
GearVR Plugin
[ENGINE INSTALL LOCATION]\Engine\Plugins\Runtime\GearVR\Source\GearVR\GearVR.Build.cs [ENGINE INSTALL LOCATION]\Engine\Plugins\Runtime\GearVR\Source\GearVR\GearVR_APL.xml
-
GoogleVR Plugin
-
GoogleVRController Module
[ENGINE INSTALL LOCATION]\Engine\Plugins\Runtime\GoogleVR\GoogleVRController\Source\GoogleVRController\GoogleVRController.Build.cs [ENGINE INSTALL LOCATION]\Engine\Plugins\Runtime\GoogleVR\GoogleVRController\Source\GoogleVRController\GoogleVRController_APL.xml
-
GoogleVRHMD Plugin
[ENGINE INSTALL LOCATION]\Engine\Plugins\Runtime\GoogleVR\GoogleVRHMD\Source\GoogleVRHMD\GoogleVRHMD.Build.cs [ENGINE INSTALL LOCATION]\Engine\Plugins\Runtime\GoogleVR\GoogleVRHMD\Source\GoogleVRHMD\GoogleVRHMD_APL.xml
-
-
- サードパーティのプラグイン
- Tango 4 Unreal Plug-in
- Parse Platform Plugin
Unreal Plugin Languageとは
Unreal Plugin LanguageはXMLベースの言語で次のような機能を提供します。
- ファイル、フォルダのコピー(主にライブラリやリソース)
- ファイルの削除
- AndroidのAndroidManifest.xml、proguard、GameActivity.javaにコード追加
- iOSのInfo.plistにコード追加
このXMLはBuild.cs
で読み込みます。
Build.cs
UPLの対象プラットフォームは以下の2種類です。
プラットフォーム | ReceiptPropertyのプロパティ名 |
---|---|
Android | AndroidPlugin |
iOS | IOSPlugin |
Androidの場合はGearVRやGoogleVRプラグインを真似して以下のコードでXMLを読み込めばよいでしょう。
if (Target.Platform == UnrealTargetPlatform.Android)
{
string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory, BuildConfiguration.RelativeEnginePath);
AdditionalPropertiesForReceipt.Add(new ReceiptProperty("AndroidPlugin", Path.Combine(PluginPath, "CppTest_APL.xml")));
}
Unreal Plugin Languageのリファレンス
現状、リファレンスはUnrealPluginLanguage.csにコメントで記述されたものだけなので、これを元に解説していきます。
空定義のXML
<?xml version="1.0" encoding="utf-8"?>
<root xmlns:android="http://schemas.android.com/apk/res/android">
<!-- ここに追加していく -->
</root>
デバッグ
<trace enable="true"/>
ログを有効にするかどうか設定できます。
<dumpvars/>
XMLの中で設定した変数の値をログに出力します。
<log text="..."/>
textで指定したメッセージをログに出力します。
各セクションで出力すると動作確認しやすくなります。
変数
-
$B(name)
: boolean -
$I(name)
: integer -
$S(name)
: string -
$E(name)
: XMLのelement
変数name
をそれぞれの型の値として参照できます。
定義済みの変数
-
$S(Architecture)
: アーキテクチャ名 (armeabi-armv7a
,arm64-v8a
,x86
,x86_64
) -
$S(PluginDir)
: XMLファイルが読み込まれたフォルダ名 -
$S(EngineDir)
: エンジンのフォルダ名 -
$S(BuildDir)
: プラットフォーム毎のビルドフォルダ名 (Intermediateフォルダ内) -
$S(ProjectDir)
: プロジェクトのフォルダ名 -
$B(Distribution)
: Distributionビルドならtrueが設定されます。 -
$S(Output)
: 後述するセクション毎にその内容が設定されるので、動的に変更することができます。
共通のセクション
init
<init></init>
アーキテクチャ毎に1回だけ実行されるセクションです。
変数を定義、操作したり<log text="..."/>
でログを出したりできます。
Android用のセクション
以下のセクションはReceiptProperty()
でAndroidPlugin
を指定すると適用されます。
androidmanifestUpdates
<androidManifestUpdates>
<addPermission android:name="..."/>
<addFeature android:name="..."/>
<addLibrary android:name="..."/>
<addElement tag="..." name="..."/>
<removeElement tag="..."/>
<addElements tag="..."></addElements>
<addAttribute tag="..." name="..." value="..."/>
<removeAttribute tag="..." name="..."/>
<loopElements tag="..."></loopElements>
</androidManifestUpdates>
[PROJECT LOCATION]/Intermediate/Android/APK/AndroidManifest.xml
に<uses-permission>
, <uses-feature>
, <uses-library>
を追加します。
また、任意の要素、属性を追加、削除することもできます。
proguardAdditions
<proguardAdditions>
<insert>...</insert>
</proguardAdditions>
タグ内で操作した内容が[PROJECT LOCATION]/Intermediate/Android/APK/proguard-project.txt
に反映されます。
prebuildCopies
<prebuildCopies>
<copyFile src="..." dst="..."/>
<deleteFiles filespec="..."/>
</prebuildCopies>
ndk-buildで必要なライブラリやファイルをビルド前にコピーするために使います。
resourceCopies
<resourceCopies>
<copyFile src="..." dst="..."/>
<deleteFiles filespec="..."/>
</resourceCopies>
ndk-buildの後に必要なファイルをコピーするために使います。
JavaのビルドはAPK作成時なので、追加したいJavaのソースファイルはこれでコピーすればよいです。
AARImports
<AARImports>
<insert>...</insert>
</AARImports>
aar-imports.txt
が$(Output)
に読み込まれるので<insert></insert>
などでAARを追加できます。
GameActivity.java更新用のセクション
ビルドターゲットにAndroidを追加すると以下のJavaソースファイルがコピーされます。
- コピー元:
[ENGINE INSTALL LOCATION]\Engine\Build\Android\java\src\com\epicgames\ue4\GameActivity.java
- コピー先:
[PROJECT LOCATION]\Intermediate\Android\APK\src\com\epicgames\ue4\GameActivity.java
このファイルはAPK作成時に独自のコードを追加するためのプレースホルダーがいくつかあり、以下のタグで操作することができます。
注意
GameActivity.java
が作られるとXMLのJavaコードを変更しても反映されません。
コピー先の方のGameActivity.java
を削除すると、次のAPK作成時に変更が反映されます。
gameActivityImportAdditions
<gameActivityImportAdditions>
<insert>...</insert>
</gameActivityImportAdditions>
GameActivityにimportを追加するときに使います。
コピー元のプレースホルダーは$${gameActivityImportAdditions}$$
です。
gameActivityClassAdditions
<gameActivityClassAdditions>
<insert>...</insert>
</gameActivityClassAdditions>
GameActivityにメンバ変数やメンバメソッドを追加するときに使います。
コピー元のプレースホルダーは$${gameActivityClassAdditions}$$
です。
gameActivityOnStartAdditions
<gameActivityOnStartAdditions>
<insert>...</insert>
</gameActivityOnStartAdditions>
GameActivityのonStart()
に処理を追加するときに使います。
コピー元のプレースホルダーは$${gameActivityOnStartAdditions}$$
です。
gameActivityReadMetadataAdditions
<gameActivityReadMetadataAdditions>
<insert>...</insert>
</gameActivityReadMetadataAdditions>
GameActivityのonCreate()
でAndroidManifest.xmlから設定を読み込むときに使います。
コピー元のプレースホルダーは$${gameActivityReadMetadataAdditions}$$
です。
gameActivityOnCreateAdditions
<gameActivityOnCreateAdditions>
<insert>...</insert>
</gameActivityOnCreateAdditions>
GameActivityのonCreate()
に処理を追加するときに使います。
コピー元のプレースホルダーは$${gameActivityOnCreateAdditions}$$
です。
gameActivityOnDestroyAdditions
<gameActivityOnDestroyAdditions>
<insert>...</insert>
</gameActivityOnDestroyAdditions>
GameActivityのonDestroy()
に処理を追加するときに使います。
コピー元のプレースホルダーは$${gameActivityOnDestroyAdditions}$$
です。
gameActivityOnStopAdditions
<gameActivityOnStopAdditions>
<insert>...</insert>
</gameActivityOnStopAdditions>
GameActivityのonStop()
に処理を追加するときに使います。
コピー元のプレースホルダーは$${gameActivityOnStopAdditions}$$
です。
gameActivityOnPauseAdditions
<gameActivityOnPauseAdditions>
<insert>...</insert>
</gameActivityOnPauseAdditions>
GameActivityのonPause()
に処理を追加するときに使います。
コピー元のプレースホルダーは$${gameActivityOnPauseAdditions}$$
です。
gameActivityOnResumeAdditions
<gameActivityOnResumeAdditions>
<insert>...</insert>
</gameActivityOnResumeAdditions>
GameActivityのonResume()
に処理を追加するときに使います。
コピー元のプレースホルダーは$${gameActivityOnResumeAdditions}$$
です。
gameActivityOnActivityResultAdditions
<gameActivityOnActivityResultAdditions>
<insert>...</insert>
</gameActivityOnActivityResultAdditions>
GameActivityのonActivityResult()
に処理を追加するときに使います。
コピー元のプレースホルダーは$${gameActivityOnActicityResultAdditions}$$
です。
soLoadLibrary
<soLoadLibrary>
<loadLibrary name="..." failmsg="..."/>
<insert>...</insert>
</soLoadLibrary>
GameActivityでロードしたいネイティブライブラリを追加するときに使います。
細かい処理をしたい場合は<insert></insert>
を使うこともできます。
コピー元のプレースホルダーは$${soLoadLibrary}$$
です。
iOS用のセクション
以下のセクションはReceiptProperty()
でIOSPlugin
を指定すると適用されます。
iosPListUpdates
<iosPListUpdates></iosPListUpdates>
このセクションの内容を[PROJECT LOCATION]/Intermediate/IOS/[GAME NAME]-Info.plist
に書き出します。
各種の操作
変数定義
<setBool result="..." value="..."/>
<setInt result="..." value="..."/>
<setString result="..." value="..."/>
<setElement result="..." value="..."/>
<setElement result="..." xml="..."/>
value
の値をresult
で指定した変数に代入します。
<setBoolFromProperty result="..." ini="..." section="..." property="..." default="..."/>
<setIntFromProperty result="..." ini="..." section="..." property="..." default="..."/>
<setStringFromProperty result="..." ini="..." section="..." property="..." default="..."/>
iniファイルから値を読み込みます。
ファイルやセクション、プロパティが存在しない場合はdefault
が代入されます。
演算
<setBoolNot result="..." source="..."/>
<setBoolAnd result="..." arg1="..." arg2="..."/>
<setBoolOr result="..." arg1="..." arg2="..."/>
<setBoolIsEqual result="..." arg1="..." arg2="..."/>
<setBoolIsLess result="..." arg1="..." arg2="..."/>
<setBoolIsLessEqual result="..." arg1="..." arg2="..."/>
<setBoolIsGreater result="..." arg1="..." arg2="..."/>
<setBoolIsGreaterEqual result="..." arg1="..." arg2="..."/>
論理演算した結果をresult
で指定した変数に代入します。
<setIntAdd result="..." arg1="..." arg2="..."/>
<setIntSubtract result="..." arg1="..." arg2="..."/>
<setIntMultiply result="..." arg1="..." arg2="..."/>
<setIntDivide result="..." arg1="..." arg2="..."/>
算術演算した結果をresult
で指定した変数に代入します。
<setStringAdd result="..." arg1="..." arg2="..."/>
<setStringSubstring result="..." source="..." start="..." length="..."/>
<setStringReplace result="..." source="..." find="..." with="..."/>
文字列操作した結果をresult
で指定した変数に代入します。
<setIntLength result="..." source="..."/>
source
の文字列の長さをresult
で指定した変数に代入します。
<setIntFindString result="..." source="..." find="..."/>
source
からfind
の文字列が一致したインデックスをresult
で指定した変数に代入します。
<setBoolStartsWith result="..." source="..." find="..."/>
<setBoolEndsWith result="..." source="..." find="..."/>
<setBoolContains result="..." source="..." find="..."/>
それぞれfind
で指定した文字列で始まる、終わる、含んでいるかチェックした結果をresult
で指定した変数に代入します。
Output変数の操作
<replace find="..." with="..."/>
変数$(Output)
からfind
と一致した文字列をwith
の文字列で置換します。
<insert>...</insert>
<insertValue value="..."/>
<insertNewLine/>
変数$(Output)
にタグ内の文字を追加します。
主にproguardAdditionsやGameActivity.javaのセクションで使います。
制御構文
<if condition="...">
<true>
<!-- executes if boolean variable in condition is true -->
</true>
<false>
<!-- executes if boolean variable in condition is false -->
</false>
</if>
condition
で条件を指定し、true
タグとfalse
タグでそれぞれの処理を設定できます。
<isArch arch="armeabi-armv7">
<!-- do stuff -->
</isArch>
アーキテクチャをチェックできるショートカットノードです。これは以下と同等の操作ができます。
<setBoolEquals result="temp" arg1="$S(Architecture)" arg2="armeabi-armv7">
<if condition="temp">
<true>
<!-- do stuff -->
</true>
</if>
<isDistribution>
<!-- do stuff -->
</isDistribution>
Distributionビルドかどうかチェックできます。
これもisArch
と同様にショートカットです。
<return/>
ここで処理を終了します。
<while condition="...">
<!-- do stuff -->
</while>
<break/>
<continue/>
ループ処理です。break
とcontinue
もあります。
XML操作
<addElement tag="..." name="..."/>
<addElements tag="..."> body </addElements>
<removeElement tag="..."/>
<setStringFromTag result="..." tag="..." name="..."/>
<setStringFromAttribute result="..." tag="..." name="..."/>
<addAttribute tag="..." name="..." value="..."/>
<removeAttribute tag="..." name="..."/>
<loopElements tag="..."> instructions </loopElements>
要素の追加および削除、属性の追加および削除、要素や属性の値を取得、繰り返し要素に対しての操作をできます。
主にAndroidManifest.xmlのintent-filterのように特定の操作が用意されていない要素を設定するために使います。
まとめ
全体を見ると結構な量がありますが、柔軟な定義をするためだと思います。
たとえばAndroid側にロジックを追加したいときはGameActivityのセクションしか使いません。
また、プラグインでなくてもプロジェクト単体でも利用できるので使える範囲は広いです。