移动端指定启动参数

UE4 打出来的 Windows 包可以使用 XXXX.exe -Params 等方式来传递给游戏参数,但是移动平台 (IOS/Android) 打包出来的怎么传递参数呢?

Android 启动参数

看了一下引擎里的代码,在 Launch 模块下 Launch\Private\Android\LaunchAndroid.cpp 中有 InitCommandLine 函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// Launch\Private\Android\LaunchAndroid.cpp
static void InitCommandLine()
{
static const uint32 CMD_LINE_MAX = 16384u;

// initialize the command line to an empty string
FCommandLine::Set(TEXT(""));

AAssetManager* AssetMgr = AndroidThunkCpp_GetAssetManager();
AAsset* asset = AAssetManager_open(AssetMgr, TCHAR_TO_UTF8(TEXT("UE4CommandLine.txt")), AASSET_MODE_BUFFER);
if (nullptr != asset)
{
const void* FileContents = AAsset_getBuffer(asset);
int32 FileLength = AAsset_getLength(asset);

char CommandLine[CMD_LINE_MAX];
FileLength = (FileLength < CMD_LINE_MAX - 1) ? FileLength : CMD_LINE_MAX - 1;
memcpy(CommandLine, FileContents, FileLength);
CommandLine[FileLength] = '\0';

AAsset_close(asset);

// chop off trailing spaces
while (*CommandLine && isspace(CommandLine[strlen(CommandLine) - 1]))
{
CommandLine[strlen(CommandLine) - 1] = 0;
}

FCommandLine::Append(UTF8_TO_TCHAR(CommandLine));
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("APK Commandline: %s"), FCommandLine::Get());
}

// read in the command line text file from the sdcard if it exists
FString CommandLineFilePath = GFilePathBase + FString("/UE4Game/") + (!FApp::IsProjectNameEmpty() ? FApp::GetProjectName() : FPlatformProcess::ExecutableName()) + FString("/UE4CommandLine.txt");
FILE* CommandLineFile = fopen(TCHAR_TO_UTF8(*CommandLineFilePath), "r");
if(CommandLineFile == NULL)
{
// if that failed, try the lowercase version
CommandLineFilePath = CommandLineFilePath.Replace(TEXT("UE4CommandLine.txt"), TEXT("ue4commandline.txt"));
CommandLineFile = fopen(TCHAR_TO_UTF8(*CommandLineFilePath), "r");
}

if(CommandLineFile)
{
char CommandLine[CMD_LINE_MAX];
fgets(CommandLine, ARRAY_COUNT(CommandLine) - 1, CommandLineFile);

fclose(CommandLineFile);

// chop off trailing spaces
while (*CommandLine && isspace(CommandLine[strlen(CommandLine) - 1]))
{
CommandLine[strlen(CommandLine) - 1] = 0;
}

// initialize the command line to an empty string
FCommandLine::Set(TEXT(""));

FCommandLine::Append(UTF8_TO_TCHAR(CommandLine));
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Override Commandline: %s"), FCommandLine::Get());
}

#if !UE_BUILD_SHIPPING
if (FString* ConfigRulesCmdLineAppend = FAndroidMisc::GetConfigRulesVariable(TEXT("cmdline")))
{
FCommandLine::Append(**ConfigRulesCmdLineAppend);
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("ConfigRules appended: %s"), **ConfigRulesCmdLineAppend);
}
#endif
}

简单来说就是在 UE4Game/ProjectName/ue4commandline.txt 中把启动参数写到里面,引擎启动的时候会从这个文件去读,然后添加到 FCommandLine 中。

IOS 启动参数

与 Android 的做法相同,IOS 的参数传递是在 main 函数中调用FIOSCommandLineHelper::InitCommandArgs(FString());,不过路径和 Android 不一样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
static void InitCommandArgs(FString AdditionalCommandArgs)
{
// initialize the commandline
FCommandLine::Set(TEXT(""));

FString CommandLineFilePath = FString([[NSBundle mainBundle] bundlePath]) + TEXT("/ue4commandline.txt");

// read in the command line text file (coming from UnrealFrontend) if it exists
FILE* CommandLineFile = fopen(TCHAR_TO_UTF8(*CommandLineFilePath), "r");
if(CommandLineFile)
{
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Found ue4commandline.txt file") LINE_TERMINATOR);

char CommandLine[CMD_LINE_MAX] = {0};
char* DataExists = fgets(CommandLine, ARRAY_COUNT(CommandLine) - 1, CommandLineFile);
if (DataExists)
{
// chop off trailing spaces
while (*CommandLine && isspace(CommandLine[strlen(CommandLine) - 1]))
{
CommandLine[strlen(CommandLine) - 1] = 0;
}

FCommandLine::Append(UTF8_TO_TCHAR(CommandLine));
}
}
else
{
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("No ue4commandline.txt [%s] found") LINE_TERMINATOR, *CommandLineFilePath);
}

if (!AdditionalCommandArgs.IsEmpty() && !FChar::IsWhitespace(AdditionalCommandArgs[0]))
{
FCommandLine::Append(TEXT(" "));
}
FCommandLine::Append(*AdditionalCommandArgs);

// now merge the GSavedCommandLine with the rest
FCommandLine::Append(*GSavedCommandLine);

FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Combined iOS Commandline: %s") LINE_TERMINATOR, FCommandLine::Get());
}

关键就是 [[NSBundle mainBundle] bundlePath] 这一句,它获取的是 App 的包路径,所以把 UE4CommandLine.txt 放到包路径下就可以了,可以使用 iMaZing 或者爱思助手之类的工具访问 App 的数据目录,放入 ue4commandline.txt 即可。