public override void Package(ProjectParams Params, DeploymentContext SC, int WorkingCL) { string[] Architectures = UnrealBuildTool.AndroidToolChain.GetAllArchitectures(); string[] GPUArchitectures = UnrealBuildTool.AndroidToolChain.GetAllGPUArchitectures(); bool bMakeSeparateApks = UnrealBuildTool.Android.UEDeployAndroid.ShouldMakeSeparateApks(); bool bPackageDataInsideApk = UnrealBuildTool.Android.UEDeployAndroid.PackageDataInsideApk(false); var Deploy = UEBuildDeploy.GetBuildDeploy(UnrealTargetPlatform.Android); string BaseApkName = GetFinalApkName(Params, SC.StageExecutables[0], true, "", ""); Log("BaseApkName = {0}", BaseApkName); // Create main OBB with entire contents of staging dir. This // includes any PAK files, movie files, etc. string LocalObbName = SC.StageDirectory.TrimEnd(new char[] { '/', '\\' }) + ".obb"; // Always delete the target OBB file if it exists if (File.Exists(LocalObbName)) { File.Delete(LocalObbName); } // Now create the OBB as a ZIP archive. Log("Creating {0} from {1}", LocalObbName, SC.StageDirectory); using (ZipFile ObbFile = new ZipFile(LocalObbName)) { ObbFile.CompressionMethod = CompressionMethod.None; ObbFile.CompressionLevel = Ionic.Zlib.CompressionLevel.None; int ObbFileCount = 0; ObbFile.AddProgress += delegate(object sender, AddProgressEventArgs e) { if (e.EventType == ZipProgressEventType.Adding_AfterAddEntry) { ObbFileCount += 1; Log("[{0}/{1}] Adding {2} to OBB", ObbFileCount, e.EntriesTotal, e.CurrentEntry.FileName); } }; ObbFile.AddDirectory(SC.StageDirectory + "/" + SC.ShortProjectName, SC.ShortProjectName); ObbFile.Save(); } foreach (string Architecture in Architectures) { foreach (string GPUArchitecture in GPUArchitectures) { string ApkName = GetFinalApkName(Params, SC.StageExecutables[0], true, bMakeSeparateApks ? Architecture : "", bMakeSeparateApks ? GPUArchitecture : ""); if (!SC.IsCodeBasedProject) { string UE4GameApkName = GetFinalApkName(Params, SC.StageExecutables[0], false, bMakeSeparateApks ? Architecture : "", bMakeSeparateApks ? GPUArchitecture : ""); if (FileExists_NoExceptions(UE4GameApkName) == false) { Log("Failed to find game apk " + UE4GameApkName); AutomationTool.ErrorReporter.Error("Stage Failed.", (int)AutomationTool.ErrorCodes.Error_MissingExecutable); throw new AutomationException("Could not find apk {0}. You may need to build the UE4 project with your target configuration and platform.", UE4GameApkName); } } string BatchName = GetFinalBatchName(ApkName, Params, bMakeSeparateApks ? Architecture : "", bMakeSeparateApks ? GPUArchitecture : ""); if (!Params.Prebuilt) { string CookFlavor = SC.FinalCookPlatform.IndexOf("_") > 0 ? SC.FinalCookPlatform.Substring(SC.FinalCookPlatform.IndexOf("_")) : ""; string SOName = GetSONameWithoutArchitecture(Params, SC.StageExecutables[0]); Deploy.PrepForUATPackageOrDeploy(Params.ShortProjectName, SC.ProjectRoot, SOName, SC.LocalRoot + "/Engine", Params.Distribution, CookFlavor, false); } // Create APK specific OBB in case we have a detached OBB. string DeviceObbName = ""; string ObbName = ""; if (!bPackageDataInsideApk) { DeviceObbName = GetDeviceObbName(ApkName); ObbName = GetFinalObbName(ApkName); CopyFile(LocalObbName, ObbName); } // Write install batch file(s). string PackageName = GetPackageInfo(ApkName, false); // make a batch file that can be used to install the .apk and .obb files string[] BatchLines; if (Utils.IsRunningOnMono) { Log("Writing shell script for install with {0}", bPackageDataInsideApk ? "data in APK" : "separate obb"); BatchLines = new string[] { "#!/bin/sh", "cd \"`dirname \"$0\"`\"", "ADB=", "if [ \"$ANDROID_HOME\" != \"\" ]; then ADB=$ANDROID_HOME/platform-tools/adb; else ADB=" + Environment.GetEnvironmentVariable("ANDROID_HOME") + "; fi", "DEVICE=", "if [ \"$1\" != \"\" ]; then DEVICE=\"-s $1\"; fi", "echo", "echo Uninstalling existing application. Failures here can almost always be ignored.", "$ADB $DEVICE uninstall " + PackageName, "echo", "echo Installing existing application. Failures here indicate a problem with the device \\(connection or storage permissions\\) and are fatal.", "$ADB $DEVICE install " + Path.GetFileName(ApkName), "if [ $? -eq 0 ]; then", "\techo", "\techo Removing old data. Failures here are usually fine - indicating the files were not on the device.", "\t$ADB $DEVICE shell 'rm -r $EXTERNAL_STORAGE/UE4Game/" + Params.ShortProjectName + "'", "\t$ADB $DEVICE shell 'rm -r $EXTERNAL_STORAGE/UE4Game/UE4CommandLine.txt" + "'", "\t$ADB $DEVICE shell 'rm -r $EXTERNAL_STORAGE/" + TargetAndroidLocation + PackageName + "'", bPackageDataInsideApk ? "" : "\techo", bPackageDataInsideApk ? "" : "\techo Installing new data. Failures here indicate storage problems \\(missing SD card or bad permissions\\) and are fatal.", bPackageDataInsideApk ? "" : "\tSTORAGE=$(echo \"`$ADB $DEVICE shell 'echo $EXTERNAL_STORAGE'`\" | cat -v | tr -d '^M')", bPackageDataInsideApk ? "" : "\t$ADB $DEVICE push " + Path.GetFileName(ObbName) + " $STORAGE/" + DeviceObbName, bPackageDataInsideApk ? "if [ 1 ]; then" : "\tif [ $? -eq 0 ]; then", "\t\techo", "\t\techo Installation successful", "\t\texit 0", "\tfi", "fi", "echo", "echo There was an error installing the game or the obb file. Look above for more info.", "echo", "echo Things to try:", "echo Check that the device (and only the device) is listed with \\\"$ADB devices\\\" from a command prompt.", "echo Make sure all Developer options look normal on the device", "echo Check that the device has an SD card.", "exit 1" }; } else { Log("Writing bat for install with {0}", bPackageDataInsideApk ? "data in APK" : "separate OBB"); BatchLines = new string[] { "setlocal", "set ANDROIDHOME=%ANDROID_HOME%", "if \"%ANDROIDHOME%\"==\"\" set ANDROIDHOME=" + Environment.GetEnvironmentVariable("ANDROID_HOME"), "set ADB=%ANDROIDHOME%\\platform-tools\\adb.exe", "set DEVICE=", "if not \"%1\"==\"\" set DEVICE=-s %1", "for /f \"delims=\" %%A in ('%ADB% %DEVICE% " + GetStorageQueryCommand() + "') do @set STORAGE=%%A", "@echo.", "@echo Uninstalling existing application. Failures here can almost always be ignored.", "%ADB% %DEVICE% uninstall " + PackageName, "@echo.", "@echo Installing existing application. Failures here indicate a problem with the device (connection or storage permissions) and are fatal.", "%ADB% %DEVICE% install " + Path.GetFileName(ApkName), "@if \"%ERRORLEVEL%\" NEQ \"0\" goto Error", "%ADB% %DEVICE% shell rm -r %STORAGE%/UE4Game/" + Params.ShortProjectName, "%ADB% %DEVICE% shell rm -r %STORAGE%/UE4Game/UE4CommandLine.txt", // we need to delete the commandline in UE4Game or it will mess up loading "%ADB% %DEVICE% shell rm -r %STORAGE%/" + TargetAndroidLocation + PackageName, bPackageDataInsideApk ? "" : "@echo.", bPackageDataInsideApk ? "" : "@echo Installing new data. Failures here indicate storage problems (missing SD card or bad permissions) and are fatal.", bPackageDataInsideApk ? "" : "%ADB% %DEVICE% push " + Path.GetFileName(ObbName) + " %STORAGE%/" + DeviceObbName, bPackageDataInsideApk ? "" : "if \"%ERRORLEVEL%\" NEQ \"0\" goto Error", "@echo.", "@echo Installation successful", "goto:eof", ":Error", "@echo.", "@echo There was an error installing the game or the obb file. Look above for more info.", "@echo.", "@echo Things to try:", "@echo Check that the device (and only the device) is listed with \"%ADB$ devices\" from a command prompt.", "@echo Make sure all Developer options look normal on the device", "@echo Check that the device has an SD card.", "@pause" }; } File.WriteAllLines(BatchName, BatchLines); if (Utils.IsRunningOnMono) { CommandUtils.FixUnixFilePermissions(BatchName); } } } PrintRunTime(); }
public override void Package(ProjectParams Params, DeploymentContext SC, int WorkingCL) { var Architectures = UnrealBuildTool.AndroidToolChain.GetAllArchitectures(); var GPUArchitectures = UnrealBuildTool.AndroidToolChain.GetAllGPUArchitectures(); bool bMakeSeparateApks = UnrealBuildTool.Android.UEDeployAndroid.ShouldMakeSeparateApks(); bool bPackageDataInsideApk = UnrealBuildTool.Android.UEDeployAndroid.PackageDataInsideApk(false); var Deploy = UEBuildDeploy.GetBuildDeploy(UnrealTargetPlatform.Android); string BaseApkName = GetFinalApkName(Params, SC.StageExecutables[0], true, "", ""); Log("BaseApkName = {0}", BaseApkName); // Create main OBB with entire contents of staging dir. This // includes any PAK files, movie files, etc. string LocalObbName = SC.StageDirectory.TrimEnd(new char[] { '/', '\\' }) + ".obb"; // Always delete the target OBB file if it exists if (File.Exists(LocalObbName)) { File.Delete(LocalObbName); } // Now create the OBB as a ZIP archive. Log("Creating {0} from {1}", LocalObbName, SC.StageDirectory); using (ZipFile ObbFile = new ZipFile(LocalObbName)) { ObbFile.CompressionMethod = CompressionMethod.None; ObbFile.CompressionLevel = Ionic.Zlib.CompressionLevel.None; int ObbFileCount = 0; ObbFile.AddProgress += delegate(object sender, AddProgressEventArgs e) { if (e.EventType == ZipProgressEventType.Adding_AfterAddEntry) { ObbFileCount += 1; Log("[{0}/{1}] Adding {2} to OBB", ObbFileCount, e.EntriesTotal, e.CurrentEntry.FileName); } }; ObbFile.AddDirectory(SC.StageDirectory + "/" + SC.ShortProjectName, SC.ShortProjectName); ObbFile.Save(); } foreach (string Architecture in Architectures) { foreach (string GPUArchitecture in GPUArchitectures) { string ApkName = GetFinalApkName(Params, SC.StageExecutables[0], true, bMakeSeparateApks ? Architecture : "", bMakeSeparateApks ? GPUArchitecture : ""); if (!SC.IsCodeBasedProject) { string UE4SOName = GetFinalApkName(Params, SC.StageExecutables[0], false, bMakeSeparateApks ? Architecture : "", bMakeSeparateApks ? GPUArchitecture : ""); UE4SOName = UE4SOName.Replace(".apk", ".so"); if (FileExists_NoExceptions(UE4SOName) == false) { Log("Failed to find game .so " + UE4SOName); throw new AutomationException(ErrorCodes.Error_MissingExecutable, "Stage Failed. Could not find .so {0}. You may need to build the UE4 project with your target configuration and platform.", UE4SOName); } } if (!Params.Prebuilt) { string CookFlavor = SC.FinalCookPlatform.IndexOf("_") > 0 ? SC.FinalCookPlatform.Substring(SC.FinalCookPlatform.IndexOf("_")) : ""; string SOName = GetSONameWithoutArchitecture(Params, SC.StageExecutables[0]); Deploy.PrepForUATPackageOrDeploy(Params.ShortProjectName, SC.ProjectRoot, SOName, SC.LocalRoot + "/Engine", Params.Distribution, CookFlavor, false); } // Create APK specific OBB in case we have a detached OBB. string DeviceObbName = ""; string ObbName = ""; if (!bPackageDataInsideApk) { DeviceObbName = GetDeviceObbName(ApkName); ObbName = GetFinalObbName(ApkName); CopyFile(LocalObbName, ObbName); } // Write install batch file(s). string BatchName = GetFinalBatchName(ApkName, Params, bMakeSeparateApks ? Architecture : "", bMakeSeparateApks ? GPUArchitecture : "", false); string PackageName = GetPackageInfo(ApkName, false); // make a batch file that can be used to install the .apk and .obb files string[] BatchLines = GenerateInstallBatchFile(bPackageDataInsideApk, PackageName, ApkName, Params, ObbName, DeviceObbName, false); File.WriteAllLines(BatchName, BatchLines); // If we aren't packaging data in the APK then lets write out a bat file to also let us test without the OBB // on the device. String NoInstallBatchName = GetFinalBatchName(ApkName, Params, bMakeSeparateApks ? Architecture : "", bMakeSeparateApks ? GPUArchitecture : "", true); // if(!bPackageDataInsideApk) { BatchLines = GenerateInstallBatchFile(bPackageDataInsideApk, PackageName, ApkName, Params, ObbName, DeviceObbName, true); File.WriteAllLines(NoInstallBatchName, BatchLines); } if (Utils.IsRunningOnMono) { CommandUtils.FixUnixFilePermissions(BatchName); if (File.Exists(NoInstallBatchName)) { CommandUtils.FixUnixFilePermissions(NoInstallBatchName); } } } } PrintRunTime(); }