Unreal Engine AndroidPluginLanguage Tutorial ?
언리얼 엔진에서 안드로이드 라이브러리나 Manifest.xml 기타 등등.. 을 직접 고칠 수 있는 스크립트 같은걸 준비 해 놓은것 같다.
4.10 노트에 언급이 있긴 하다..
https://docs.unrealengine.com/latest/KOR/Support/Builds/ReleaseNotes/2015/4_10/index.html
안드로이드
새로운 안드로이드 플러그인 시스템이 4.10 에 포함되었으며, GearVR 플러그인에서 사용되고 있습니다. 생성된 AndroidManifest.xml, proguard-project.xt, 그리고 GameActivity.java 에 대한 변경은 패키징 도중에도 가능하며, 여기에는 그 build.cs 에 AndroindPlugin 프로퍼티를 추가하여 명령이 들어있는 XML 파일을 레퍼런싱하는 것도 포함됩니다. AndroidPluginLanguage.cs 에 사용가능한 명령이 기술되어 있습니다.
그런데 어딜봐도 이거 사용법이라던가 사용법이라던가.. 가이드라던가 그런게 없다..
그나마 VR 라이브러리에 사용한 예가 있어서 그걸 토대로 어떻게 쓸 수 있는지 알아보겠다..
AndroidPluginLanguage.cs 에 있는 설명 주석
매우 길다.. 안 읽어보고 훑어보기만 해도 어지럽다.
/* AndroidPluginLanguage (APL) is a simple XML-based language for manipulating XML and returning
* strings. It contains an <init> section which is evaluated once per architecture before any
* other sections. The state is maintained and carried forward to the next section evaluated
* so the order the sections are executed matters.
*
* If you need to see the instructions executed in your plugin context add the following to
* enable tracing:
*
* <trace enable="true"/>
*
* After this instuction all the nodes actually executed in your context will be written to the
* log until you do a <trace enable="false"/>. You can also get a dump of all the variables in
* your context with this command:
*
* <dumpvars/>
*
* Bool, Int, and String variable types are supported. Any attribute may reference a variable
* and will be replaced with the string equivalent before evaluation using this syntax:
*
* $B(name) = boolean variable "name"'s value
* $I(name) = integer variable "name"'s value
* $S(name) = string variable "name"'s value
* $E(name) = element variable "name"'s value
*
* The following variables are initialized automatically:
*
* $S(Output) = the output returned for evaluating the section (initialized to Input)
* $S(Architecture) = target architecture (armeabi-armv7, armeabi-armv8, x86, x86_64)
* $S(PluginDir) = directory the XML file was loaded from
* $S(EngineDir) = engine directory
* $S(BuildDir) = project's Intermediate/Android/APK directory
* $B(Distribution) = true if distribution build
*
* Note: with the exception of the above variables, all are in the context of the plugin to
* prevent namespace collision; trying to set a new value to any of the above, with the
* exception of Output, will only affect the current context.
*
* The following nodes allow manipulation of variables:
*
* <setBool result="" value=""/>
* <setInt result="" value=""/>
* <setString result="" value=""/>
* <setElement result="" value=""/>
* <setElement result="" xml=""/>
*
* <setElement> with value creates an empty XML element with the tag set to value.
* <setElement> with xml will parse the XML provided. Remember to escape any special characters!
*
* Variables may also be set from a property in an ini file:
*
* <setBoolFromProperty result="" ini="" section="" property="" default=""/>
* <setIntFromProperty result="" ini="" section="" property="" default=""/>
* <setStringFromProperty result="" ini="" section="" property="" default=""/>
*
* Boolean variables may also be set to the result of applying operators:
*
* <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=""/>
*
* Integer variables may use these arithmetic operations:
*
* <setIntAdd result="" arg1="" arg2=""/>
* <setIntSubtract result="" arg1="" arg2=""/>
* <setIntMultiply result="" arg1="" arg2=""/>
* <setIntDivide result="" arg1="" arg2=""/>
*
* Strings are manipulated with the following:
*
* <setStringAdd result="" arg1="" arg2=""/>
* <setStringSubstring result="" source="" start="" length=""/>
* <setStringReplace result="" source="" find="" with=""/>
*
* String length may be retrieved with:
*
* <setIntLength result="" source=""/>
*
* The index of a search string may be found in source with:
*
* <setIntFindString result="" source="" find=""/>
*
* The following shortcut string comparisons may also be used instead of using <setIntFindString>
* and checking the result:
*
* <setBoolStartsWith result="" source="" find=""/>
* <setBoolEndsWith result="" source="" find=""/>
* <setBoolContains result="" source="" find=""/>
*
* Messages are written to the log with this node:
*
* <log text=""/>
*
* Conditional execution uses the following form:
*
* <if condition="">
* <true>
* <!-- executes if boolean variable in condition is true -->
* </true>
* <false>
* <!-- executes if boolean variable in condition is false -->
* </false>
* </if>
*
* The <true> and <false> blocks are optional. The condition must be in a boolean variable.
* The boolean operator nodes may be combined to create a final state for more complex
* conditions:
*
* <setBoolNot result="notDistribution" value="$B(Distribution)/>
* <setBoolEquals result="isX86" arg1="$S(Architecture)" arg2="x86"/>
* <setBoolEquals result="isX86_64" arg2="$S(Architecture)" arg2="x86_64/">
* <setBoolOr result="isIntel" arg1="$B(isX86)" arg2="$B(isX86_64)"/>
* <setBoolAnd result="intelAndNotDistribution" arg1="$B(isIntel)" arg2="$B(notDistribution)"/>
* <if condition="intelAndNotDistribution">
* <true>
* <!-- do something for Intel if not a distribution build -->
* </true>
* </if>
*
* Note the "isIntel" could also be done like this:
*
* <setStringSubstring result="subarch" source="$S(Architecture)" start="0" length="3"/>
* <setBoolEquals result="isIntel" arg1="$S(subarch)" arg2="x86"/>
*
* Two shortcut nodes are available for conditional execution:
*
* <isArch arch="armeabi-armv7">
* <!-- do stuff -->
* </isArch>
*
* is the equivalent of:
*
* <setBoolEquals result="temp" arg1="$S(Architecture)" arg2="armeabi-armv7">
* <if condition="temp">
* <true>
* <!-- do stuff -->
* </true>
* </if>
*
* and
*
* <isDistribution>
* <!-- do stuff -->
* </isDistribution>
*
* is the equivalent of:
*
* <if condition="$B(Distribution)">
* <!-- do stuff -->
* </if>
*
* Execution may be stopped with:
*
* <return/>
*
* Loops may be created using these nodes:
*
* <while condition="">
* <!-- do stuff -->
* </while>
*
* <break/>
* <continue/>
*
* The <while> body will execute until the condition is false or a <break/> is hit. The
* <continue/> will restart execution of the loop if the condition is still true or exit.
*
* Note: <break/> outside a <while> body will act the same as <return/>
*
* Here is an example loop which writes 1 to 5 to the log, skipping 3. Note the update of the
* while condition should be done before the continue otherwise it may not exit.
*
* <setInt result="index" value="0"/>
* <setBool result="loopRun" value="true"/>
* <while condition="loopRun">
* <setIntAdd result="index" arg1="$I(index)" arg2="1"/>
* <setBoolIsLess result="loopRun" arg1="$I(index)" arg2="5"/>
* <setBoolIsEqual result="indexIs3" arg1="$I(index)" arg2="3"/>
* <if condition="indexIs3">
* <true>
* <continue/>
* </true>
* </if>
* <log text="$I(index)"/>
* </while>
*
* It is possible to use variable replacement in generating the result variable
* name as well. This makes the creation of arrays in loops possible:
*
* <setString result="array_$I(index)" value="element $I(index) in array"/>
*
* This may be retrieved using the following (value is treated as the variable
* name):
*
* <setStringFrom result="out" value="array_$I(index)"/>
*
* For boolean and integer types, you may use <setBoolFrom/> and <setIntFrom/>.
*
* Nodes for inserting text into the section are as follows:
*
* <insert> body </insert>
* <insertValue value=""/>
* <loadLibrary name="" failmsg=""/>
*
* The first one will insert either text or nodes into the returned section
* string. Please note you must use escaped characters for:
*
* < = <
* > = >
* & = &
*
* <insertValue value=""/> evaluates variables in value before insertion. If value contains
* double quote ("), you must escape it with ".
*
* <loadLibrary name="" failmsg=""/> is a shortcut to insert a system.LoadLibrary try/catch
* block with an optional logged message for failure to load case.
*
* You can do a search and replace in the Output with:
*
* <replace find="" with=""/>
*
* Note you can also manipulate the actual $S(Output) directly, the above are more efficient:
*
* <setStringAdd result="Input" arg1="$S(Output)" arg2="sample\n"/>
* <setStringReplace result="Input" source="$S(Output)" find=".LAUNCH" with=".INFO"/>
*
* XML manipulation uses the following nodes:
*
* <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>
*
* The current element is referenced with tag="$". Element variables are referenced with $varname
* since using $E(varname) will be expanded to the string equivalent of the XML.
*
* <uses-permission> and <uses-feature> are updated with:
*
* <addPermission android:name="" .. />
* <addFeature android:name="" .. />
*
* Any attributes in the above commands are copied to the element added to the manifest so you
* can do the following, for example:
*
* <addFeature android:name="android.hardware.usb.host" android:required="true"/>
*
* Finally, these nodes allow copying of files useful for staging jar and so files:
*
* <copyFile src="" dst=""/>
* <copyDir src="" dst=""/>
*
* The following should be used as the base for the src and dst paths:
*
* $S(PluginDir) = directory the XML file was loaded from
* $S(EngineDir) = engine directory
* $S(BuildDir) = project's Intermediate/Android/APK directory
*
* While it is possible to write outside the APK directory, it is not recommended.
*
* If you must remove files (like development-only files from distribution builds) you can
* use this node:
*
* <removeFiles mask=""/>
*
* It is restricted to only removing files from the BuildDir. Here is example usage to remove
* the Oculus Signature Files (osig) from the assets directory:
*
* <removeFiles mask="assets/oculussig_*"/>
*
* The following sections are evaluated during the packaging or deploy stages:
*
* <!-- init section is always evaluated once per architecture -->
* <init> </init>
*
* <!-- optional updates applied to AndroidManifest.xml -->
* <androidManifestUpdates> </androidManifestUpdates>
*
* <!-- optional additions to proguard -->
* <proguardAdditions> </proguardAdditions>
*
* <!-- optional files or directories to copy or delete from Intermediate/Android/APK before ndk-build -->
* <prebuildCopies> </prebuildCopies>
*
* <!-- optional files or directories to copy or delete from Intermediate/Android/APK after ndk-build -->
* <resourceCopies> </resourceCopies>
*
* <!-- optional additions to the GameActivity imports in GameActivity.java -->
* <gameActivityImportAdditions> </gameActivityImportAdditions>
*
* <!-- optional additions to the GameActivity class in GameActivity.java -->
* <gameActivityClassAdditions> </gameActivityOnClassAdditions>
*
* <!-- optional additions to GameActivity onCreate metadata reading in GameActivity.java -->
* <gameActivityReadMetadata> </gameActivityReadMetadata>
*
* <!-- optional additions to GameActivity onCreate in GameActivity.java -->
* <gameActivityOnCreateAdditions> </gameActivityOnCreateAdditions>
*
* <!-- optional additions to GameActivity onDestroy in GameActivity.java -->
* <gameActivityOnDestroyAdditions> </gameActivityOnDestroyAdditions>
*
* <!-- optional additions to GameActivity onStart in GameActivity.java -->
* <gameActivityOnStartAdditions> </gameActivityOnStartAdditions>
*
* <!-- optional additions to GameActivity onStop in GameActivity.java -->
* <gameActivityOnStopAdditions> </gameActivityOnStopAdditions>
*
* <!-- optional additions to GameActivity onPause in GameActivity.java -->
* <gameActivityOnPauseAdditions> </gameActivityOnPauseAdditions>
*
* <!-- optional additions to GameActivity onResume in GameActivity.java -->
* <gameActivityOnResumeAdditions> </gameActivityOnResumeAdditions>
*
* <!-- optional additions to GameActivity onActivityResult in GameActivity.java -->
* <gameActivityOnActivityResultAdditions> </gameActivityOnActivityResultAdditions>
*
* <!-- optional libraries to load in GameActivity.java before libUE4.so -->
* <soLoadLibrary> </soLoadLibrary>
*
*
* Here is the complete list of supported nodes:
*
* <isArch arch="">
* <isDistribution>
* <if> => <true> / <false>
* <while condition="">
* <return/>
* <break/>
* <continue/>
* <log text=""/>
* <insert> </insert>
* <insertValue value=""/>
* <replace find="" with""/>
* <copyFile src="" dst=""/>
* <copyDir src="" dst=""/>
* <loadLibrary name="" failmsg=""/>
* <setBool result="" value=""/>
* <setBoolFrom result="" value=""/>
* <setBoolFromProperty result="" ini="" section="" property="" 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=""/>
* <setInt result="" value=""/>
* <setIntFrom result="" value=""/>
* <setIntFromProperty result="" ini="" section="" property="" default=""/>
* <setIntAdd result="" arg1="" arg2=""/>
* <setIntSubtract result="" arg1="" arg2=""/>
* <setIntMultiply result="" arg1="" arg2=""/>
* <setIntDivide result="" arg1="" arg2=""/>
* <setIntLength result="" source=""/>
* <setIntFindString result="" source="" find=""/>
* <setString result="" value=""/>
* <setStringFrom result="" value=""/>
* <setStringFromProperty result="" ini="" section="" property="" default=""/>
* <setStringAdd result="" arg1="" arg2=""/>
* <setStringSubstring result="" source="" index="" length=""/>
* <setStringReplace result="" source="" find="" with=""/>
*
*/
예제인 GearVR_APL.xml
-keep class com.oculus.** { *; } -keep class android.app.** { *; } /** Whether this application was packaged for GearVR or not */ public boolean PackagedForGearVR = false; // check the manifest to determine if we are a GearVR application public boolean AndroidThunkJava_IsGearVRApplication() { return PackagedForGearVR; } if(bundle.containsKey("com.samsung.android.vr.application.mode")) { PackagedForGearVR = true; String VRMode = bundle.getString("com.samsung.android.vr.application.mode"); Log.debug("Found GearVR mode = " + VRMode); com.oculus.svclib.OVREntitlementChecker.doAutomatedCheck(this); } else { PackagedForGearVR = false; Log.debug("No GearVR mode detected."); }
사용 예를 통해서.. APL을 써서 할 수 있는것
AndroidManifest.xml 수정
proguard 옵션 수정
리소스 복사(jar , so ..)
GameActivity.java 에 코드 추가/(수정?) ...
보니까 이런 것들이 가능하다..
필수 사항은 아니지만 해도 그만 안하면 고생이다.
(.a) static library 는 이전 글을 참조.
2016/05/30 - [컴퓨터공학/언리얼엔진] - Unreal Engine 4.11 안드로이드 라이브러리 적용
APL Hello World
우선 적당한 build.cs 에
using System; using System.IO; ... if (Target.Platform == UnrealTargetPlatform.Android) { string PluginPath = Utils.MakePathRelativeTo (ModuleDirectory, BuildConfiguration.RelativeEnginePath); System.Console.WriteLine ("_______________________ Path " + PluginPath); AdditionalPropertiesForReceipt.Add (new ReceiptProperty ("AndroidPlugin", Path.Combine (PluginPath, "TEST_APL.xml"))); }
추가
거기에 쓸 APL.xml은 build.cs와 같은 폴더에다가.. 위치시키고 코드는
이렇게 하고
안드로이드 타겟 - 실행을 시킬 때
출력로그에서
LogPlayLevel: mono: Cleaning up files based on template dir /Users/kimsang-u/Documents/Unreal Projects/vehicle410/Build/Android/src/com/com2us/vehicletest
LogPlayLevel: mono: Building Java with SDK API level 'android-21'
LogPlayLevel: mono: APL Init: armeabi-v7a
LogPlayLevel: mono: Hello TEST APL init
LogPlayLevel: mono: bPackageDataInsideApk = False
를 확인할 수 있다.
APL File Copy
TEST_APL.xml에다가....
이런 식으로 추가하니
TEST_APL.xml 이 있는 폴더 아래에 /libs/ 가
빌드 할 때
/Intermediate/Android/APK/libs/ 로 바로 복사시켜 준다.
$S(PluginDir) 와 $S(BuildDir) 예약어 덕분이다.
JavaLibs 에 들어가는 것들은 <resourcecopies> 대신
<prebuildCopies> 를 써야
JavaLibrary가 연관된 빌드/런타임 에러가 발생하지 않는다.
src 폴더 지정시 상위 폴더로 올라가는 " /../../ " 이거 잘 안된다..
dst 폴더에 제대로 복사를 안시켜준다.. 어째서?
AndroidManifest.xml 수정
TEST_APL.xml..
제일 바깥쪽 <manifest> </manifest>에 뭔가를 추가 할 때
에디터에 메뉴가 이미 있기때문에 쓸때는 없지만 uses-permission 추가 할 때
Permission 이나 feature 같은 건 중복검사를 해주고 있어서 속성 중복 추가 걱정할 건 없다.
Android Plugin Language
'컴퓨터공학 > 언리얼엔진' 카테고리의 다른 글
언리얼 엔진 빌드 CPU 스레드 차이 i5 vs i7 (0) | 2018.06.15 |
---|---|
프로젝트 셋팅 iOS Mobile Provision 에서 인증서, 프로비저닝 목록이 안뜨는 경우 (0) | 2016.10.26 |
맥 Xcode에서 Indexing 끄기.. (0) | 2016.09.27 |
4.13 Unreal Plugin Langauge로 기존 APL을 대체 (0) | 2016.08.19 |
FString (Hex String) to TArray<uint8> (byteArray) (0) | 2016.07.19 |
Unreal Engine 4.11 안드로이드 라이브러리 적용 (0) | 2016.05.30 |
Unreal Engine 4 Custom Widget (C++) (0) | 2016.05.20 |