You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#rb none #ROBOMERGE-OWNER: ryan.vance #ROBOMERGE-AUTHOR: mitchell.wilson #ROBOMERGE-SOURCE: CL 4860421 in //UE4/Main/... #ROBOMERGE-BOT: DEVVR (Main -> Dev-VR) [CL 4860484 by mitchell wilson in Dev-VR branch]
371 lines
18 KiB
Plaintext
371 lines
18 KiB
Plaintext
INTSourceChangelist:0
|
||
Availability: Public
|
||
Crumbs:
|
||
Title: Android Configuration Rules System
|
||
Description: Taking a look at using the Android Configuration Rules System in your UE4 projects.
|
||
Type:
|
||
Version: 4.21
|
||
Parent: Platforms/Android
|
||
Order:
|
||
Tags: Android
|
||
Tags: Reference
|
||
|
||
|
||
The Android Configuration Rules system gives Android developers using Unreal Engine 4 (UE4) control over determining if a particular Android-based device has the needed hardware and software to run their project. The following information and steps will enable you to develop your UE4 projects for the devices and software you intend to support.
|
||
|
||
## Config Rules File
|
||
|
||
To get started, create a new text file called **configrules.txt** and place it in your projects **Build/Android** directory.
|
||
|
||
[REGION:lightbox]
|
||
[(w:800px)](AndroidConfigRules_File_Loaction.png)
|
||
[/REGION]
|
||
[REGION:caption]
|
||
Click for full image.
|
||
[/REGION]
|
||
|
||
Once you have the configrules.txt file created and placed in the Build/Android directory, open it up in your text editor of choice and add the following text, making sure that it is the first item in the file.
|
||
|
||
// version:1
|
||
|
||
The above text is the version code parsed by the ConfigRulesTool during packaging, and must be present in this form (one space between "//" and "version:", and no spaces after the colon). The number starts at one and should be incremented any time you update the file. UE4 will then use this number to determine if a newer version should be used than what is currently embedded in the Android Package (APK).
|
||
|
||
[REGION:note]
|
||
Any line that starts with a **//** or **semicolon(;)** is treated as a comment and ignored.
|
||
[/REGION]
|
||
|
||
Commands are used to manipulate case-sensitive variables which either trigger an immediate action or are passed on to the engine. Any variables still defined after the Config Rules runs may be queried from C++ with the following function:
|
||
|
||
FString* FAndroidMisc::GetConfigRulesVariable(const FString& Key);
|
||
|
||
**Example:**
|
||
|
||
#if PLATFORM_ANDROID
|
||
If (FAndroidMisc::GetConfigRulesVariable(TEXT(“myflag”) == TEXT(“true”))
|
||
{
|
||
UE_LOG(LogAndroid, Display, TEXT(“myflag was set!”));
|
||
}
|
||
#endif
|
||
|
||
|
||
It is also possible to get access to a TMap with the key/value entries if you would like to iterate over them:
|
||
|
||
TMap<FString, FString> FAndroidMisc::GetConfigRulesTMap();
|
||
|
||
**Example:**
|
||
|
||
#if PLATFORM_ANDROID
|
||
TMap<FString, FString> ConfigRules = FAndroidMisc::GetConfigRulesTMap();
|
||
for (const TPair<FString, FString>& Pair : ConfigRules)
|
||
{
|
||
FString VarKey = Pair.Key;
|
||
if (VarKey.StartsWith("myvars_"))
|
||
{
|
||
FString VarValue = Pair.Value;
|
||
UE_LOG(LogAndroid, Log, TEXT("Found variable %s = %s"), *VarKey, *VarValue);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
## Config Rules Variables
|
||
|
||
Variables may be used in values with the following syntax:
|
||
|
||
$(varname)
|
||
|
||
This means that the following:
|
||
|
||
“$(SRC_DeviceMake) $(SRC_DeviceModel)”
|
||
|
||
Would be replaced with the values of **SRC_DeviceMake** and **SRC_DeviceModel** separated by a space.
|
||
|
||
The following variables are defined automatically before configrules.txt is parsed:
|
||
|
||
|
||
| **Variable Name** | **Description** | **Example Value** |
|
||
| --- | --- | --- |
|
||
| memory | Total memory in megabytes. | 3550 |
|
||
| hardware | The chipset (either Hardware from /proc/cpuinfo or getprop ro.hardware). | Qualcomm Technologies, Inc SDM845 |
|
||
| ro.hardware | The result from "getprop ro.hardware". | blueline |
|
||
| processor | Processor type from /proc/cpuinfo. | AArch64 Processor rev 12 (aarch64) |
|
||
| processorCount | Processor count from /proc/cpuinfo. | 8 |
|
||
| useAffinity | Whether or not to set thread affinity to little cores for some threads. | true |
|
||
| hasNEON | Indicates processor supports NEON features (SIMD). | true |
|
||
| isARM64 | Indicates processor supports ARM64 ABI. | true |
|
||
| littleCoreMask | Bitmask indicating which cores are little. | 0x0f |
|
||
| bigCoreMask | Bitmask indicating which cores are big. | 0xf0 |
|
||
| SRC_GpuVendor | Vendor from GLES20.glGetString(GLES20.GL_VENDOR). | Qualcomm |
|
||
| SRC_GpuFamily | GPU family from GLES20.glGetString(GLES20.GL_RENDERER). | Adreno (TM) 630 |
|
||
| SRC_GlVersion | GL version from GLES20.glGetString(GLES20.GL_VERSION). | OpenGL ES 3.2 V@313.0 (GIT@3f88ca2, I42f6fe38fb) (Date:07/13/18) |
|
||
| SRC_AndroidVersion | Android version from android.os.Build.VERSION.RELEASE. | 9 |
|
||
| SRC_DeviceMake | Device manufacturer from android.os.Build.MANUFACTURER. | Google |
|
||
| SRC_DeviceModel | Device model from android.os.Build.MODEL. | Pixel 3 |
|
||
| SRC_DeviceBuildNumber | Device build number from android.os.Build.DISPLAY. | PD1A.180720.030 |
|
||
| SRC_VulkanVersion | Version of Vulkan support. | 1.1.0 |
|
||
| SRC_VulkanAvailable | Indicates if Vulkan is supported by the device. | true |
|
||
| SRC_UsingHoudini | Indicates ARM emulated on Intel processor by Houdini. | false |
|
||
| SRC_SDKLevel | SDK level from android.os.Build.VERSION.SDK_INT. | 28 |
|
||
| supportsFloatingPointRenderTargets | Indicates GPU supports FP render targets. | true |
|
||
| TextureFormats | Comma-separated list of supported texture formats by GPU. | ASTC,ATC,ETC2,ETC1 |
|
||
| navigationBarHeight | Height of Android navigation bar in pixels. | 132 |
|
||
| statusBarHeight | Height of Android status bar in pixels. | 66 |
|
||
| screenWidth | Screen width in pixels. | 1080 |
|
||
| screenHeight | Screen height in pixels. | 2160 |
|
||
|
||
|
||
## Config Rules Commands
|
||
|
||
Commands can be used with valid arguments in the forum of **action:argument**. These are defined below along with use case examples.
|
||
|
||
**Set** allows you to assign one or more variables and their specified values:
|
||
|
||
set:(myvar=true)
|
||
|
||
|
||
If you have more than one variable, you can use a **comma** (**,**) to separate them:
|
||
|
||
set:(myvar=false,myvar2=”something”,myvar3=”else”)
|
||
|
||
|
||
**clear** allows you to clear the value assigned to variables.
|
||
|
||
clear:(myvar)
|
||
|
||
You can clear more than one variable at a time using a **comma **(**,**) to separate the values you want to clear.
|
||
|
||
clear:(myvar,myvar3)
|
||
|
||
**condition** evaluates the list of conditions and if all are true it applies optional set and clear commands.
|
||
|
||
condition:((comparison)[,(comparison)],[(set)],[(clear)]
|
||
|
||
The comparisons are made up of three parts in parentheses separated by commas. The three parts are **SourceType**, **CompareType**, and **MatchString**.
|
||
|
||
(SourceType=isARM64,CompareType=CMP_EQUAL,MatchString=”true”)
|
||
|
||
**SourceType** specifies the first argument for comparison and will usually be a variable name. The following are the three special SourceType values that can be used:
|
||
|
||
|
||
| **Command Name** | **Description** |
|
||
| --- | --- |
|
||
| SRC_PreviousRegexMatch | The group returned from the last regex expression condition. |
|
||
| SRC_CommandLine | The command line embedded in the APK. |
|
||
| \[EXIST\] | Used with MatchString to see if a variable exists or not. |
|
||
|
||
|
||
**MatchString** is any string value to use for the comparison or the variable name for the **\[EXIST\]** case.
|
||
|
||
**CompareType** may be one of the following:
|
||
|
||
|
||
| **Command Name** | **Description** |
|
||
| --- | --- |
|
||
| CMP_Exist | True if variable name in MatchString is set. |
|
||
| CMP_NotExist | True if variable name in MatchString is not set. |
|
||
| CMP_Equal | True if variable name in MatchString is not set. |
|
||
| CMP_NotEqual | True if SourceType not equal to MatchString. |
|
||
| CMP_EqualIgnore | True if SourceType equals MatchString, ignoring case. |
|
||
| CMP_NotEqualIgnore | True if SourceType does not equal Matchstring, ignoring case. |
|
||
| CMP_Less | True if value of SourceType < value of MatchString. |
|
||
| CMP_LessEqual | True if value of SourceType <= value of MatchString. |
|
||
| CMP_Greater | True if value of SourceType > value of MatchString. |
|
||
| CMP_GreaterEqual | True if value of SourceType >= value of MatchString |
|
||
| CMP_Regex | True if regex in MatchString found in SourceType (matching group is available in SRC_PreviousRegexMatch for additional condition checks) |
|
||
|
||
|
||
The following examples show how you might setup and use the Android Config Rules Commands in your UE4 projects:
|
||
|
||
The following code will set **myvar** to **arm64** if **isARM64** is **true**:
|
||
|
||
condition:((SourceType=isARM64,CompareType=CMP_EQUAL,MatchString=”true”)),(myvar=”arm64”)
|
||
|
||
|
||
The following code will set **myvar** to **arm64** if **isARM64** is **true** and clears **notsupported**:
|
||
|
||
set:(notsupported=true)
|
||
condition:((SourceType=isARM64,CompareType=CMP_EQUAL,MatchString=”true”)),(myvar=”arm64”),(notsupported)
|
||
|
||
The following code uses **Regex** to extract the number in **Adreno (TM) 630** and compares it to see if it is less than **510** to flag an error.:
|
||
|
||
condition:((SourceType=SRC_GpuFamily,CompareType=CMP_Regex,MatchString="(?!Adreno \(TM\))([0-9][0-9]*)"),(SourceType=SRC_PreviousRegexMatch,CompareType=CMP_LessEqual,MatchString="510")), (error="CR_Info_UnsupportedGPU")
|
||
|
||
**chipset **is a shortcut to set a group of variables if the hardware string is equal to either ro.hardware or hardware. It sets useAffinity, chipset, GPU, processorCount, bigCoreMask, and littleCoreMask. useAffinity controls whether or not taskgroup threads are restricted to the little cores with the littleCoreMask.:
|
||
|
||
chipset: hardware string, useAffinity, part name, GPU name, processor count, big core mask, little core mask
|
||
|
||
Here are some examples:
|
||
|
||
~~~
|
||
chipset:"Qualcomm Technologies, Inc MSM8929", true, "Snapdragon 415", "Adreno (TM) 405", 8, 0xf0, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc MSM8937", true, "Snapdragon 435", "Adreno (TM) 505", 8, 0xf0, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc MSM8940", true, "Snapdragon 435", "Adreno (TM) 505", 8, 0xf0, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc MSM8952", true, "Snapdragon 617", "Adreno (TM) 405", 8, 0xf0, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc MSM8953", true, "Snapdragon 625/626", "Adreno (TM) 506", 8, 0xf0, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc MSM8956", true, "Snapdragon 650", "Adreno (TM) 510", 6, 0x03, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc MSM8976", true, "Snapdragon 652/653", "Adreno (TM) 510", 8, 0xf0, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc SDM630", true, "Snapdragon 630", "Adreno (TM) 508", 8, 0xf0, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc SDM636", true, "Snapdragon 636", "Adreno (TM) 509", 8, 0xf0, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc SDM660", true, "Snapdragon 660", "Adreno (TM) 512", 8, 0xf0, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc SDM640", true, "Snapdragon 640", "Adreno (TM) 610", 8, 0xc0, 0x3f
|
||
chipset:"Qualcomm Technologies, Inc SDM670", true, "Snapdragon 670", "Adreno (TM) 620", 8, 0xf0, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc SDM710", true, "Snapdragon 710", "Adreno (TM) 616", 8, 0xc0, 0x3f
|
||
chipset:"Qualcomm Technologies, Inc SDM730", true, "Snapdragon 730", "Adreno (TM) 615", 8, 0xc0, 0x3f
|
||
chipset:"Qualcomm Technologies, Inc MSM8992", true, "Snapdragon 808", "Adreno (TM) 418", 6, 0x30, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc MSM8994", true, "Snapdragon 810", "Adreno (TM) 430", 8, 0xf0, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc MSM8996", true, "Snapdragon 820/821", "Adreno (TM) 530", 4, 0x0c, 0x03
|
||
chipset:"Qualcomm Technologies, Inc MSM8998", true, "Snapdragon 835", "Adreno (TM) 540", 8, 0xf0, 0x0f
|
||
chipset:"Qualcomm Technologies, Inc SDM845", true, "Snapdragon 845", "Adreno (TM) 630", 8, 0xf0, 0x0f
|
||
chipset:"samsungexynos9810", true, "Samsung Exynos 9 Series (9810)", "Mali-G72 MP18", 8, 0xf0, 0x0f
|
||
chipset:"samsungexynos8895", true, "Samsung Exynos 9 Series (8895)", "Mali-G71 MP20", 8, 0xf0, 0x0f
|
||
chipset:"samsungexynos9610", true, "Samsung Exynos 7 Series (9610)", "Mali-G72 MP3", 8, 0xf0, 0x0f
|
||
chipset:"samsungexynos7885", true, "Samsung Exynos 7 Series (7885)", "Mali-G71 MP2", 8, 0xc0, 0x3f
|
||
chipset:"samsungexynos7880", false, "Samsung Exynos 7 Series (7880)", "Mali-T830 MP3", 8, 0xff, 0x00
|
||
chipset:"samsungexynos7882", true, "Samsung Exynos 5 Series (7872)", "Mali-G71 MP1", 6, 0x30, 0x0f
|
||
~~~
|
||
|
||
## Config Rules Special Variables
|
||
|
||
There are two special variables which trigger actions if set:
|
||
|
||
set:(log=”message for the logcat”)
|
||
|
||
The value of log after any command is evaluated will be written to the logcat output and cleared.
|
||
|
||
set:(dumpvars=1)
|
||
|
||
This will dump all the variables currently set and their values to logcat.
|
||
|
||
## Config Rules Profiles
|
||
|
||
You can set the **Profile** variable to override the device profile used instead of the one that would be picked by the **AndroidDeviceProfileMatchingRules** in **DefaultDeviceProfiles**.ini. If this value is not modified the normal rules will still apply. The following example would force the **Android\_Galaxy\_S9Plus_Adreno** setting for **SM-G965** models:
|
||
|
||
condition:((SourceType=sammodel,CompareType=CMP_Regex,MatchString="SM\-G965")), (Profile="Android_Galaxy_S9Plus_Adreno")
|
||
|
||
|
||
|
||
## Config Rules Dialog
|
||
|
||
You can customize the error and warning dialog messages that are displayed using the following variables:
|
||
|
||
* caption
|
||
* exitbutton
|
||
* continuebutton
|
||
* updatebutton
|
||
* helpbutton
|
||
|
||
The value placed in the caption or buttons is looked up in the string table to get the localized text for the dialog. You should make these string names unique and place them in a **ConfigurationStrings.xml** file in your project’s **Build/Android/res/values** directory for each localized language your project supports. (values-fr, for example, would be for French).
|
||
|
||
[REGION:note]
|
||
An example of where the ConfigurationStrings.xml file should be placed is shown below.
|
||
[/REGION]
|
||
|
||
[REGION:lightbox]
|
||
[(w:800px)](AndroidConfigRules_File_Location.png)
|
||
[/REGION]
|
||
[REGION:caption]
|
||
Click for full image.
|
||
[/REGION]
|
||
|
||
* **Error - **You can signal an **error** by setting the **error variable**. The dialog will show the string table entry for the value you assign to it. All processing of the configrules.txt will stop once this is set and the user will not be able to continue into your application.
|
||
* **Warning** - A **Warning** dialog is triggered by setting the **warning variable**. The dialog will provide a continue option and optionally update and/or help buttons if the corresponding variables are set. The help button will launch an external browser to the URL specified by the link variable. Evaluation of configrules.txt will continue until the end or error is set before the dialog is shown so you can change it again with different conditions if necessary.
|
||
|
||
The following example code was setup to display an error is the user tried to use an Android device that does not support ARM64.
|
||
|
||
set:(caption="CR_Caption_DeviceNotSupported", exitbutton="CR_Button_Quit", continuebutton="CR_Button_Continue", helpbutton="CR_Button_Help")
|
||
condition:((SourceType=isARM64,CompareType=CMP_EQUAL,MatchString=”false”)),(error=”CR_Info_RequiresARM64”)
|
||
|
||
When the above example is encountered, the error message that is displayed will come from the following string table.
|
||
|
||
~~~
|
||
<?xml version="1.0" encoding="utf-8"?>
|
||
<resources>
|
||
<!-- Button text -->
|
||
<string name="CR_Button_Quit">Quit</string>
|
||
<string name="CR_Button_Help">More Info</string>
|
||
<string name="CR_Button_Continue">Continue</string>
|
||
<string name="CR_Button_Update">Check for Update</string>
|
||
<!-- Dialog caption text -->
|
||
<string name="CR_Caption_DeviceNotSupported">Device Not Supported</string>
|
||
<!-- Dialog message text -->
|
||
<string name="CR_Info_RequiresARM64">This game requires an ARM64-v8a processor.</string>
|
||
</resources>
|
||
~~~
|
||
|
||
## Config Rules Build Files
|
||
|
||
The following additions to your project are required for the configrules.txt file to be included in your APK by compressing, and optionally encrypting, it. Start by registering the following **Unreal Plugin Language** (UPL) code in your project’s **Build.cs** file:
|
||
|
||
~~~
|
||
if (Target.Platform == UnrealTargetPlatform.Android)
|
||
{
|
||
// Add UPL to add configrules.txt to our APK
|
||
string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory, Target.RelativeEnginePath);
|
||
AdditionalPropertiesForReceipt.Add("AndroidPlugin", System.IO.Path.Combine(PluginPath, "MyGame_UPL.xml"));
|
||
}
|
||
~~~
|
||
|
||
Next you will want to create a new file called **MyGame_UPL.xm****l** which is placed in the same directory with the **Build.cs** file.
|
||
|
||
[REGION:lightbox]
|
||
[(w:800px)](AndroidConfigRules_MyGame_UPLLocation.png)
|
||
[/REGION]
|
||
[REGION:caption]
|
||
Click for full image.
|
||
[/REGION]
|
||
|
||
Open up the MyGame_UPL.xml file and then add the following code, saving the file when done (change the ConfigRulesKey to contain your unique encryption key):
|
||
|
||
~~~
|
||
<?xml version="1.0" encoding="utf-8"?>
|
||
<root xmlns:android="http://schemas.android.com/apk/res/android">
|
||
<!-- init section is always evaluated once per architecture -->
|
||
<init>
|
||
<!-- this is the key used for configrules encryption -->
|
||
<setString result="ConfigRulesKey" value="This is my encryption key"/>
|
||
</init>
|
||
<!-- Files to copy to gradle directory before Gradle runs -->
|
||
<gradleCopies>
|
||
<copyFile src="$S(BuildDir)/configrules.txt"
|
||
dst="$S(BuildDir)/gradle/app/configrules.txt"/>
|
||
</gradleCopies>
|
||
<gradleProperties>
|
||
<insertValue value="CONFIGRULESTOOL_KEY=$S(ConfigRulesKey)"/>
|
||
<insertNewline/>
|
||
<insertValue value="CONFIGRULESTOOL_JAR=$S(AbsEngineDir)/Build/Android/Prebuilt/ConfigRulesTool/bin/ConfigRulesTool.jar"/>
|
||
<insertNewline/>
|
||
</gradleProperties>
|
||
<gameActivityClassAdditions>
|
||
<insertValue value="public String CONFIGRULES_KEY = "$S(ConfigRulesKey)";"/>
|
||
<insertNewline/>
|
||
</gameActivityClassAdditions>
|
||
<buildGradleAdditions>
|
||
<insert>
|
||
<![CDATA[
|
||
task ProcessConfigRules(type: JavaExec) {
|
||
description 'Produces compressed and encrypted configules.bin.png in assets'
|
||
inputs.file file('configrules.txt')
|
||
outputs.file file('src/main/assets/configrules.bin.png')
|
||
main = "-jar"
|
||
args = [
|
||
"${CONFIGRULESTOOL_JAR}",
|
||
'c',
|
||
'configrules.txt',
|
||
'src/main/assets/configrules.bin.png',
|
||
"${CONFIGRULESTOOL_KEY}"
|
||
]
|
||
}
|
||
tasks.whenTaskAdded { task ->
|
||
if (CONFIGRULESTOOL_JAR != null) {
|
||
if (task.name == 'assembleRelease') {
|
||
task.dependsOn 'ProcessConfigRules'
|
||
}
|
||
if (task.name == 'assembleDebug') {
|
||
task.dependsOn 'ProcessConfigRules'
|
||
}
|
||
}
|
||
}
|
||
]]>
|
||
</insert>
|
||
</buildGradleAdditions>
|
||
</root>
|
||
~~~ |