public override List <FileReference> FinalizeBinaryPaths(FileReference BinaryName, FileReference ProjectFile, ReadOnlyTargetRules Target) { AndroidToolChain ToolChain = CreateToolChain(Target) as AndroidToolChain; List <string> Architectures = ToolChain.GetAllArchitectures(); List <string> GPUArchitectures = ToolChain.GetAllGPUArchitectures(); // make multiple output binaries List <FileReference> AllBinaries = new List <FileReference>(); foreach (string Architecture in Architectures) { foreach (string GPUArchitecture in GPUArchitectures) { string BinaryPath; if (Target.bShouldCompileAsDLL) { BinaryPath = Path.Combine(BinaryName.Directory.FullName, Target.Configuration.ToString(), "libUE4.so"); } else { BinaryPath = AndroidToolChain.InlineArchName(BinaryName.FullName, Architecture, GPUArchitecture); } AllBinaries.Add(new FileReference(BinaryPath)); } } return(AllBinaries); }
private string GetSdkApiLevel(AndroidToolChain ToolChain) { if (CachedSDKLevel == null) { // ask the .ini system for what version to use ConfigCacheIni Ini = GetConfigCacheIni("Engine"); string SDKLevel; Ini.GetString("/Script/AndroidPlatformEditor.AndroidSDKSettings", "SDKAPILevel", out SDKLevel); // if we want to use whatever version the ndk uses, then use that if (SDKLevel == "matchndk") { SDKLevel = ToolChain.GetNdkApiLevel(); } // run a command and capture output if (SDKLevel == "latest") { // we expect there to be one, so use the first one string AndroidCommandPath = Environment.ExpandEnvironmentVariables("%ANDROID_HOME%/tools/android" + (Utils.IsRunningOnMono ? "" : ".bat")); var ExeInfo = new ProcessStartInfo(AndroidCommandPath, "list targets"); ExeInfo.UseShellExecute = false; ExeInfo.RedirectStandardOutput = true; using (var GameProcess = Process.Start(ExeInfo)) { PossibleApiLevels = new List<string>(); GameProcess.BeginOutputReadLine(); GameProcess.OutputDataReceived += ParseApiLevel; GameProcess.WaitForExit(); } if (PossibleApiLevels != null && PossibleApiLevels.Count > 0) { SDKLevel = ToolChain.GetLargestApiLevel(PossibleApiLevels.ToArray()); } else { throw new BuildException("Can't make an APK without an API installed (see \"android.bat list targets\")"); } } Console.WriteLine("Building Java with SDK API level '{0}'", SDKLevel); CachedSDKLevel = SDKLevel; } return CachedSDKLevel; }
public override List <string> FinalizeBinaryPaths(string BinaryName) { string[] Architectures = AndroidToolChain.GetAllArchitectures(); string[] GPUArchitectures = AndroidToolChain.GetAllGPUArchitectures(); // make multiple output binaries List <string> AllBinaries = new List <string>(); foreach (string Architecture in Architectures) { foreach (string GPUArchitecture in GPUArchitectures) { AllBinaries.Add(AndroidToolChain.InlineArchName(BinaryName, Architecture, GPUArchitecture)); } } return(AllBinaries); }
public override List <FileReference> FinalizeBinaryPaths(FileReference BinaryName, FileReference ProjectFile, ReadOnlyTargetRules Target) { AndroidToolChain ToolChain = new AndroidToolChain(ProjectFile, false, Target.AndroidPlatform.Architectures, Target.AndroidPlatform.GPUArchitectures); List <string> Architectures = ToolChain.GetAllArchitectures(); List <string> GPUArchitectures = ToolChain.GetAllGPUArchitectures(); // make multiple output binaries List <FileReference> AllBinaries = new List <FileReference>(); foreach (string Architecture in Architectures) { foreach (string GPUArchitecture in GPUArchitectures) { AllBinaries.Add(new FileReference(AndroidToolChain.InlineArchName(BinaryName.FullName, Architecture, GPUArchitecture))); } } return(AllBinaries); }
public override List <FileReference> FinalizeBinaryPaths(FileReference BinaryName, FileReference ProjectFile) { AndroidToolChain ToolChain = new AndroidToolChain(ProjectFile); var Architectures = ToolChain.GetAllArchitectures(); var GPUArchitectures = ToolChain.GetAllGPUArchitectures(); // make multiple output binaries List <FileReference> AllBinaries = new List <FileReference>(); foreach (string Architecture in Architectures) { foreach (string GPUArchitecture in GPUArchitectures) { AllBinaries.Add(new FileReference(AndroidToolChain.InlineArchName(BinaryName.FullName, Architecture, GPUArchitecture))); } } return(AllBinaries); }
public override List <FileReference> FinalizeBinaryPaths(FileReference BinaryName, FileReference ProjectFile, ReadOnlyTargetRules Target) { // the CppPlatform here doesn't actually matter, so this will work even for sub-platforms AndroidToolChain ToolChain = CreateToolChain(CppPlatform.Android, Target) as AndroidToolChain; List <string> Architectures = ToolChain.GetAllArchitectures(); List <string> GPUArchitectures = ToolChain.GetAllGPUArchitectures(); // make multiple output binaries List <FileReference> AllBinaries = new List <FileReference>(); foreach (string Architecture in Architectures) { foreach (string GPUArchitecture in GPUArchitectures) { AllBinaries.Add(new FileReference(AndroidToolChain.InlineArchName(BinaryName.FullName, Architecture, GPUArchitecture))); } } return(AllBinaries); }
public override void SetUpEnvironment(UEBuildTarget InBuildTarget) { // we want gcc toolchain 4.9, but fall back to 4.8 or 4.6 for now if it doesn't exist string NDKPath = Environment.GetEnvironmentVariable("NDKROOT"); NDKPath = NDKPath.Replace("\"", ""); AndroidToolChain ToolChain = new AndroidToolChain(InBuildTarget.ProjectFile); string GccVersion = "4.6"; int NDKVersionInt = ToolChain.GetNdkApiLevelInt(); if (Directory.Exists(Path.Combine(NDKPath, @"sources/cxx-stl/gnu-libstdc++/4.9"))) { GccVersion = "4.9"; } else if (Directory.Exists(Path.Combine(NDKPath, @"sources/cxx-stl/gnu-libstdc++/4.8"))) { GccVersion = "4.8"; } Log.TraceInformation("NDK version: {0}, GccVersion: {1}", NDKVersionInt.ToString(), GccVersion); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("PLATFORM_DESKTOP=0"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("PLATFORM_CAN_SUPPORT_EDITORONLY_DATA=0"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WITH_OGGVORBIS=1"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("UNICODE"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("_UNICODE"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("PLATFORM_ANDROID=1"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("ANDROID=1"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WITH_DATABASE_SUPPORT=0"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WITH_EDITOR=0"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("USE_NULL_RHI=0"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("REQUIRES_ALIGNED_INT_ACCESS"); InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/include"); // the toolchain will actually filter these out InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/armeabi-v7a/include"); InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/arm64-v8a/include"); InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86/include"); InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86_64/include"); InBuildTarget.GlobalLinkEnvironment.Config.LibraryPaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/armeabi-v7a"); InBuildTarget.GlobalLinkEnvironment.Config.LibraryPaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/arm64-v8a"); InBuildTarget.GlobalLinkEnvironment.Config.LibraryPaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86"); InBuildTarget.GlobalLinkEnvironment.Config.LibraryPaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86_64"); InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/android/native_app_glue"); InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/android/cpufeatures"); //@TODO: Tegra Gfx Debugger - standardize locations - for now, change the hardcoded paths and force this to return true to test if (UseTegraGraphicsDebugger(InBuildTarget)) { //InBuildTarget.GlobalLinkEnvironment.Config.LibraryPaths.Add(UEBuildConfiguration.UEThirdPartySourceDirectory + "NVIDIA/TegraGfxDebugger"); //InBuildTarget.GlobalLinkEnvironment.Config.LibraryPaths.Add("F:/NVPACK/android-kk-egl-t124-a32/stub"); //InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("Nvidia_gfx_debugger_stub"); } InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("gnustl_shared"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("gcc"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("z"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("c"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("m"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("log"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("dl"); if (!UseTegraGraphicsDebugger(InBuildTarget)) { InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("GLESv2"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("EGL"); } InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("OpenSLES"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("android"); UEBuildConfiguration.bCompileSimplygon = false; UEBuildConfiguration.bCompileSimplygonSSF = false; BuildConfiguration.bDeployAfterCompile = true; bool bBuildWithVulkan = IsVulkanSDKAvailable() && IsVulkanSupportEnabled(); if (bBuildWithVulkan) { InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("PLATFORM_ANDROID_VULKAN=1"); Log.TraceInformationOnce("building with VULKAN define"); } else { Log.TraceInformationOnce("building WITHOUT VULKAN define"); } }
public override void SetUpEnvironment(ReadOnlyTargetRules Target, CppCompileEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment) { // we want gcc toolchain 4.9, but fall back to 4.8 or 4.6 for now if it doesn't exist string NDKPath = Environment.GetEnvironmentVariable("NDKROOT"); NDKPath = NDKPath.Replace("\"", ""); AndroidToolChain ToolChain = new AndroidToolChain(Target.ProjectFile, false, Target.AndroidPlatform.Architectures, Target.AndroidPlatform.GPUArchitectures); // figure out the NDK version string NDKToolchainVersion = "unknown"; string NDKDefine = "100500"; // assume r10e string SourcePropFilename = Path.Combine(NDKPath, "source.properties"); if (File.Exists(SourcePropFilename)) { string RevisionString = ""; string[] PropertyContents = File.ReadAllLines(SourcePropFilename); foreach (string PropertyLine in PropertyContents) { if (PropertyLine.StartsWith("Pkg.Revision")) { RevisionString = PropertyLine; break; } } int EqualsIndex = RevisionString.IndexOf('='); if (EqualsIndex > 0) { string[] RevisionParts = RevisionString.Substring(EqualsIndex + 1).Trim().Split('.'); int RevisionMinor = int.Parse(RevisionParts.Length > 1 ? RevisionParts[1] : "0"); char RevisionLetter = Convert.ToChar('a' + RevisionMinor); int RevisionBeta = 0; // @TODO NDKToolchainVersion = "r" + RevisionParts[0] + (RevisionMinor > 0 ? Char.ToString(RevisionLetter) : ""); NDKDefine = RevisionParts[0] + string.Format("{0:00}", RevisionMinor + 1) + string.Format("{0:00}", RevisionBeta); } } else { string ReleaseFilename = Path.Combine(NDKPath, "RELEASE.TXT"); if (File.Exists(ReleaseFilename)) { string[] PropertyContents = File.ReadAllLines(SourcePropFilename); NDKToolchainVersion = PropertyContents[0]; } } // PLATFORM_ANDROID_NDK_VERSION is in the form 150100, where 15 is major version, 01 is the letter (1 is 'a'), 00 indicates beta revision if letter is 00 Log.TraceInformation("PLATFORM_ANDROID_NDK_VERSION = {0}", NDKDefine); CompileEnvironment.Definitions.Add("PLATFORM_ANDROID_NDK_VERSION=" + NDKDefine); string GccVersion = "4.6"; int NDKVersionInt = ToolChain.GetNdkApiLevelInt(); if (Directory.Exists(Path.Combine(NDKPath, @"sources/cxx-stl/gnu-libstdc++/4.9"))) { GccVersion = "4.9"; } else if (Directory.Exists(Path.Combine(NDKPath, @"sources/cxx-stl/gnu-libstdc++/4.8"))) { GccVersion = "4.8"; } Log.TraceInformation("NDK toolchain: {0}, NDK version: {1}, GccVersion: {2}, ClangVersion: {3}", NDKToolchainVersion, NDKVersionInt.ToString(), GccVersion, ToolChain.GetClangVersionString()); CompileEnvironment.Definitions.Add("PLATFORM_DESKTOP=0"); CompileEnvironment.Definitions.Add("PLATFORM_CAN_SUPPORT_EDITORONLY_DATA=0"); CompileEnvironment.Definitions.Add("WITH_OGGVORBIS=1"); CompileEnvironment.Definitions.Add("UNICODE"); CompileEnvironment.Definitions.Add("_UNICODE"); CompileEnvironment.Definitions.Add("PLATFORM_ANDROID=1"); CompileEnvironment.Definitions.Add("ANDROID=1"); CompileEnvironment.Definitions.Add("WITH_DATABASE_SUPPORT=0"); CompileEnvironment.Definitions.Add("WITH_EDITOR=0"); CompileEnvironment.Definitions.Add("USE_NULL_RHI=0"); CompileEnvironment.Definitions.Add("REQUIRES_ALIGNED_INT_ACCESS"); CompileEnvironment.IncludePaths.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/include"); // the toolchain will actually filter these out CompileEnvironment.IncludePaths.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/armeabi-v7a/include"); CompileEnvironment.IncludePaths.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/arm64-v8a/include"); CompileEnvironment.IncludePaths.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86/include"); CompileEnvironment.IncludePaths.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86_64/include"); LinkEnvironment.LibraryPaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/armeabi-v7a"); LinkEnvironment.LibraryPaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/arm64-v8a"); LinkEnvironment.LibraryPaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86"); LinkEnvironment.LibraryPaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86_64"); CompileEnvironment.IncludePaths.SystemIncludePaths.Add("$(NDKROOT)/sources/android/native_app_glue"); CompileEnvironment.IncludePaths.SystemIncludePaths.Add("$(NDKROOT)/sources/android/cpufeatures"); //@TODO: Tegra Gfx Debugger - standardize locations - for now, change the hardcoded paths and force this to return true to test if (UseTegraGraphicsDebugger(Target)) { //LinkEnvironment.LibraryPaths.Add("ThirdParty/NVIDIA/TegraGfxDebugger"); //LinkEnvironment.LibraryPaths.Add("F:/NVPACK/android-kk-egl-t124-a32/stub"); //LinkEnvironment.AdditionalLibraries.Add("Nvidia_gfx_debugger_stub"); } SetupGraphicsDebugger(Target, CompileEnvironment, LinkEnvironment); LinkEnvironment.AdditionalLibraries.Add("gnustl_shared"); LinkEnvironment.AdditionalLibraries.Add("gcc"); LinkEnvironment.AdditionalLibraries.Add("z"); LinkEnvironment.AdditionalLibraries.Add("c"); LinkEnvironment.AdditionalLibraries.Add("m"); LinkEnvironment.AdditionalLibraries.Add("log"); LinkEnvironment.AdditionalLibraries.Add("dl"); if (!UseTegraGraphicsDebugger(Target)) { LinkEnvironment.AdditionalLibraries.Add("GLESv2"); LinkEnvironment.AdditionalLibraries.Add("EGL"); } LinkEnvironment.AdditionalLibraries.Add("OpenSLES"); LinkEnvironment.AdditionalLibraries.Add("android"); }
private void MakeApk(AndroidToolChain ToolChain, string ProjectName, string ProjectDirectory, string OutputPath, string EngineDirectory, bool bForDistribution, string CookFlavor, bool bMakeSeparateApks, bool bIncrementalPackage, bool bDisallowPackagingDataInApk) { Log.TraceInformation("\n===={0}====PREPARING TO MAKE APK=================================================================", DateTime.Now.ToString()); // cache some tools paths string NDKBuildPath = Environment.ExpandEnvironmentVariables("%NDKROOT%/ndk-build" + (Utils.IsRunningOnMono ? "" : ".cmd")); // set up some directory info string IntermediateAndroidPath = Path.Combine(ProjectDirectory, "Intermediate/Android/"); string UE4BuildPath = Path.Combine(IntermediateAndroidPath, "APK"); string UE4JavaFilePath = Path.Combine(ProjectDirectory, "Build", "Android", GetUE4JavaSrcPath()); string UE4BuildFilesPath = GetUE4BuildFilePath(EngineDirectory); string GameBuildFilesPath = Path.Combine(ProjectDirectory, "Build/Android"); // Generate Java files string PackageName = GetPackageName(ProjectName); string TemplateDestinationBase = Path.Combine(ProjectDirectory, "Build", "Android", "src", PackageName.Replace('.', Path.DirectorySeparatorChar)); MakeDirectoryIfRequired(TemplateDestinationBase); // We'll be writing the OBB data into the same location as the download service files string UE4OBBDataFileName = GetUE4JavaOBBDataFileName(TemplateDestinationBase); string UE4DownloadShimFileName = GetUE4JavaDownloadShimFileName(UE4JavaFilePath); // Template generated files string JavaTemplateSourceDir = GetUE4TemplateJavaSourceDir(EngineDirectory); var templates = from template in Directory.EnumerateFiles(JavaTemplateSourceDir, "*.template") let RealName = Path.GetFileNameWithoutExtension(template) select new TemplateFile { SourceFile = template, DestinationFile = GetUE4TemplateJavaDestination(TemplateDestinationBase, RealName) }; // Generate the OBB and Shim files here string ObbFileLocation = ProjectDirectory + "/Saved/StagedBuilds/Android" + CookFlavor + ".obb"; // This is kind of a small hack to get around a rewrite problem // We need to make sure the file is there but if the OBB file doesn't exist then we don't want to replace it if (File.Exists(ObbFileLocation) || !File.Exists(UE4OBBDataFileName)) { WriteJavaOBBDataFile(UE4OBBDataFileName, PackageName, new List<string> { ObbFileLocation }); } // Make sure any existing proguard file in project is NOT used (back it up) string ProjectBuildProguardFile = Path.Combine(GameBuildFilesPath, "proguard-project.txt"); if (File.Exists(ProjectBuildProguardFile)) { string ProjectBackupProguardFile = Path.Combine(GameBuildFilesPath, "proguard-project.backup"); File.Move(ProjectBuildProguardFile, ProjectBackupProguardFile); } WriteJavaDownloadSupportFiles(UE4DownloadShimFileName, templates, new Dictionary<string, string>{ { "$$GameName$$", ProjectName }, { "$$PublicKey$$", GetPublicKey() }, { "$$PackageName$$",PackageName } }); // Sometimes old files get left behind if things change, so we'll do a clean up pass { string CleanUpBaseDir = Path.Combine(ProjectDirectory, "Build", "Android", "src"); var files = Directory.EnumerateFiles(CleanUpBaseDir, "*.java", SearchOption.AllDirectories); Log.TraceInformation("Cleaning up files based on template dir {0}", TemplateDestinationBase); // Make a set of files that are okay to clean up var cleanFiles = new HashSet<string>(); cleanFiles.Add("OBBData.java"); foreach (var template in templates) { cleanFiles.Add(Path.GetFileName(template.DestinationFile)); } foreach (var filename in files) { if (filename == UE4DownloadShimFileName) // we always need the shim, and it'll get rewritten if needed anyway continue; string filePath = Path.GetDirectoryName(filename); // grab the file's path if (filePath != TemplateDestinationBase) // and check to make sure it isn't the same as the Template directory we calculated earlier { // Only delete the files in the cleanup set if (!cleanFiles.Contains(Path.GetFileName(filename))) continue; Log.TraceInformation("Cleaning up file {0} with path {1}", filename, filePath); File.Delete(filename); // Check to see if this file also exists in our target destination, and if so nuke it too string DestFilename = Path.Combine(UE4BuildPath, Utils.MakePathRelativeTo(filePath, UE4BuildFilesPath)); if (File.Exists(filename)) { File.Delete(filename); } } } // Directory clean up code var directories = Directory.EnumerateDirectories(CleanUpBaseDir, "*", SearchOption.AllDirectories).OrderByDescending(x => x); foreach (var directory in directories) { if (Directory.Exists(directory) && Directory.GetFiles(directory, "*.*", SearchOption.AllDirectories).Count() == 0) { Log.TraceInformation("Cleaning Directory {0} as empty.", directory); Directory.Delete(directory, true); } }; } // cache if we want data in the Apk bool bPackageDataInsideApk = PackageDataInsideApk(bDisallowPackagingDataInApk); bool bDisableVerifyOBBOnStartUp = DisableVerifyOBBOnStartUp(); // check to see if any "meta information" is newer than last time we build string CurrentBuildSettings = GetAllBuildSettings(ToolChain, UE4BuildPath, bForDistribution, bMakeSeparateApks, bPackageDataInsideApk, bDisableVerifyOBBOnStartUp); string BuildSettingsCacheFile = Path.Combine(UE4BuildPath, "UEBuildSettings.txt"); // do we match previous build settings? bool bBuildSettingsMatch = true; // get application name and whether it changed, needing to force repackage string ApplicationDisplayName; if (CheckApplicationName(UE4BuildPath, ProjectName, out ApplicationDisplayName)) { bBuildSettingsMatch = false; Log.TraceInformation("Application display name is different than last build, forcing repackage."); } // if the manifest matches, look at other settings stored in a file if (bBuildSettingsMatch) { if (File.Exists(BuildSettingsCacheFile)) { string PreviousBuildSettings = File.ReadAllText(BuildSettingsCacheFile); if (PreviousBuildSettings != CurrentBuildSettings) { bBuildSettingsMatch = false; Log.TraceInformation("Previous .apk file(s) were made with different build settings, forcing repackage."); } } } // only check input dependencies if the build settings already match if (bBuildSettingsMatch) { // check if so's are up to date against various inputs var JavaFiles = new List<string>{ UE4OBBDataFileName, UE4DownloadShimFileName }; // Add the generated files too JavaFiles.AddRange(from t in templates select t.SourceFile); JavaFiles.AddRange(from t in templates select t.DestinationFile); bBuildSettingsMatch = CheckDependencies(ToolChain, ProjectName, ProjectDirectory, UE4BuildFilesPath, GameBuildFilesPath, EngineDirectory, JavaFiles, CookFlavor, OutputPath, UE4BuildPath, bMakeSeparateApks, bPackageDataInsideApk); } var Arches = ToolChain.GetAllArchitectures(); var GPUArchitectures = ToolChain.GetAllGPUArchitectures(); // Initialize APL contexts for each architecture enabled List<string> NDKArches = new List<string>(); foreach (var Arch in Arches) { string NDKArch = GetNDKArch(Arch); if (!NDKArches.Contains(NDKArch)) { NDKArches.Add(NDKArch); } } UPL.Init(NDKArches, bForDistribution, EngineDirectory, UE4BuildPath); IEnumerable<Tuple<string, string, string>> BuildList = null; if (!bBuildSettingsMatch) { BuildList = from Arch in Arches from GPUArch in GPUArchitectures let manifest = GenerateManifest(ToolChain, ProjectName, bForDistribution, bPackageDataInsideApk, GameBuildFilesPath, RequiresOBB(bDisallowPackagingDataInApk, ObbFileLocation), bDisableVerifyOBBOnStartUp, Arch, GPUArch, CookFlavor) select Tuple.Create(Arch, GPUArch, manifest); } else { BuildList = from Arch in Arches from GPUArch in GPUArchitectures let manifestFile = Path.Combine(IntermediateAndroidPath, Arch + "_" + GPUArch + "_AndroidManifest.xml") let manifest = GenerateManifest(ToolChain, ProjectName, bForDistribution, bPackageDataInsideApk, GameBuildFilesPath, RequiresOBB(bDisallowPackagingDataInApk, ObbFileLocation), bDisableVerifyOBBOnStartUp, Arch, GPUArch, CookFlavor) let OldManifest = File.Exists(manifestFile) ? File.ReadAllText(manifestFile) : "" where manifest != OldManifest select Tuple.Create(Arch, GPUArch, manifest); } // Now we have to spin over all the arch/gpu combinations to make sure they all match int BuildListComboTotal = BuildList.Count(); if (BuildListComboTotal == 0) { Log.TraceInformation("Output .apk file(s) are up to date (dependencies and build settings are up to date)"); return; } // Once for all arches code: // make up a dictionary of strings to replace in xml files (strings.xml) Dictionary<string, string> Replacements = new Dictionary<string, string>(); Replacements.Add("${EXECUTABLE_NAME}", ApplicationDisplayName); if (!bIncrementalPackage) { // Wipe the Intermediate/Build/APK directory first, except for dexedLibs, because Google Services takes FOREVER to predex, and it almost never changes // so allow the ANT checking to win here - if this grows a bit with extra libs, it's fine, it _should_ only pull in dexedLibs it needs Log.TraceInformation("Performing complete package - wiping {0}, except for predexedLibs", UE4BuildPath); DeleteDirectory(UE4BuildPath, "dexedLibs"); } // If we are packaging for Amazon then we need to copy the file to the correct location Log.TraceInformation("bPackageDataInsideApk = {0}", bPackageDataInsideApk); if (bPackageDataInsideApk) { Console.WriteLine("Obb location {0}", ObbFileLocation); string ObbFileDestination = UE4BuildPath + "/assets"; Console.WriteLine("Obb destination location {0}", ObbFileDestination); if (File.Exists(ObbFileLocation)) { Directory.CreateDirectory(UE4BuildPath); Directory.CreateDirectory(ObbFileDestination); Console.WriteLine("Obb file exists..."); var DestFileName = Path.Combine(ObbFileDestination, "main.obb.png"); // Need a rename to turn off compression var SrcFileName = ObbFileLocation; if (!File.Exists(DestFileName) || File.GetLastWriteTimeUtc(DestFileName) < File.GetLastWriteTimeUtc(SrcFileName)) { Console.WriteLine("Copying {0} to {1}", SrcFileName, DestFileName); File.Copy(SrcFileName, DestFileName); } } } else // try to remove the file it we aren't packaging inside the APK { string ObbFileDestination = UE4BuildPath + "/assets"; var DestFileName = Path.Combine(ObbFileDestination, "main.obb.png"); if (File.Exists(DestFileName)) { File.Delete(DestFileName); } } //Copy build files to the intermediate folder in this order (later overrides earlier): // - Shared Engine // - Shared Engine NoRedist (for Epic secret files) // - Game // - Game NoRedist (for Epic secret files) CopyFileDirectory(UE4BuildFilesPath, UE4BuildPath, Replacements); CopyFileDirectory(UE4BuildFilesPath + "/NotForLicensees", UE4BuildPath, Replacements); CopyFileDirectory(UE4BuildFilesPath + "/NoRedist", UE4BuildPath, Replacements); CopyFileDirectory(GameBuildFilesPath, UE4BuildPath, Replacements); CopyFileDirectory(GameBuildFilesPath + "/NotForLicensees", UE4BuildPath, Replacements); CopyFileDirectory(GameBuildFilesPath + "/NoRedist", UE4BuildPath, Replacements); //Extract AAR and Jar files with dependencies ExtractAARAndJARFiles(EngineDirectory, UE4BuildPath, NDKArches); //Now validate GooglePlay app_id if enabled ValidateGooglePlay(UE4BuildPath); //determine which orientation requirements this app has bool bNeedLandscape = false; bool bNeedPortrait = false; DetermineScreenOrientationRequirements(out bNeedPortrait, out bNeedLandscape); //Now keep the splash screen images matching orientation requested PickSplashScreenOrientation(UE4BuildPath, bNeedPortrait, bNeedLandscape); //Similarly, keep only the downloader screen image matching the orientation requested PickDownloaderScreenOrientation(UE4BuildPath, bNeedPortrait, bNeedLandscape); // at this point, we can write out the cached build settings to compare for a next build File.WriteAllText(BuildSettingsCacheFile, CurrentBuildSettings); // at this point, we can write out the cached build settings to compare for a next build File.WriteAllText(BuildSettingsCacheFile, CurrentBuildSettings); /////////////// // in case the game had an AndroidManifest.xml file, we overwrite it now with the generated one //File.WriteAllText(ManifestFile, NewManifest); /////////////// Log.TraceInformation("\n===={0}====PREPARING NATIVE CODE=================================================================", DateTime.Now.ToString()); bool HasNDKPath = File.Exists(NDKBuildPath); // get Ant verbosity level ConfigCacheIni Ini = GetConfigCacheIni("Engine"); string AntVerbosity; Ini.GetString("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "AntVerbosity", out AntVerbosity); foreach (var build in BuildList) { string Arch = build.Item1; string GPUArchitecture = build.Item2; string Manifest = build.Item3; string NDKArch = GetNDKArch(Arch); string SourceSOName = AndroidToolChain.InlineArchName(OutputPath, Arch, GPUArchitecture); // if the source binary was UE4Game, replace it with the new project name, when re-packaging a binary only build string ApkFilename = Path.GetFileNameWithoutExtension(OutputPath).Replace("UE4Game", ProjectName); string DestApkName = Path.Combine(ProjectDirectory, "Binaries/Android/") + ApkFilename + ".apk"; // As we are always making seperate APKs we need to put the architecture into the name DestApkName = AndroidToolChain.InlineArchName(DestApkName, Arch, GPUArchitecture); // Write the manifest to the correct locations (cache and real) String ManifestFile = Path.Combine(IntermediateAndroidPath, Arch + "_" + GPUArchitecture + "_AndroidManifest.xml"); File.WriteAllText(ManifestFile, Manifest); ManifestFile = Path.Combine(UE4BuildPath, "AndroidManifest.xml"); File.WriteAllText(ManifestFile, Manifest); // copy prebuild plugin files UPL.ProcessPluginNode(NDKArch, "prebuildCopies", ""); // update metadata files (like project.properties, build.xml) if we are missing a build.xml or if we just overwrote project.properties with a bad version in it (from game/engine dir) UpdateProjectProperties(ToolChain, UE4BuildPath, ProjectName); // update GameActivity.java if out of date UpdateGameActivity(Arch, NDKArch, EngineDirectory, UE4BuildPath); // Copy the generated .so file from the binaries directory to the jni folder if (!File.Exists(SourceSOName)) { throw new BuildException("Can't make an APK without the compiled .so [{0}]", SourceSOName); } if (!Directory.Exists(UE4BuildPath + "/jni")) { throw new BuildException("Can't make an APK without the jni directory [{0}/jni]", UE4BuildFilesPath); } String FinalSOName; if (HasNDKPath) { string LibDir = UE4BuildPath + "/jni/" + GetNDKArch(Arch); FinalSOName = LibDir + "/libUE4.so"; // check to see if libUE4.so needs to be copied if (BuildListComboTotal > 1 || FilesAreDifferent(SourceSOName, FinalSOName)) { Log.TraceInformation("\nCopying new .so {0} file to jni folder...", SourceSOName); Directory.CreateDirectory(LibDir); // copy the binary to the standard .so location File.Copy(SourceSOName, FinalSOName, true); } } else { // if no NDK, we don't need any of the debugger stuff, so we just copy the .so to where it will end up FinalSOName = UE4BuildPath + "/libs/" + GetNDKArch(Arch) + "/libUE4.so"; // check to see if libUE4.so needs to be copied if (BuildListComboTotal > 1 || FilesAreDifferent(SourceSOName, FinalSOName)) { Log.TraceInformation("\nCopying .so {0} file to jni folder...", SourceSOName); Directory.CreateDirectory(Path.GetDirectoryName(FinalSOName)); File.Copy(SourceSOName, FinalSOName, true); } } // remove any read only flags FileInfo DestFileInfo = new FileInfo(FinalSOName); DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly; File.SetLastWriteTimeUtc(FinalSOName, File.GetLastWriteTimeUtc(SourceSOName)); // if we need to run ndk-build, do it now if (HasNDKPath) { string LibSOName = UE4BuildPath + "/libs/" + GetNDKArch(Arch) + "/libUE4.so"; // always delete libs up to this point so fat binaries and incremental builds work together (otherwise we might end up with multiple // so files in an apk that doesn't want them) // note that we don't want to delete all libs, just the ones we copied TimeSpan Diff = File.GetLastWriteTimeUtc(LibSOName) - File.GetLastWriteTimeUtc(FinalSOName); if (!File.Exists(LibSOName) || Diff.TotalSeconds < -1 || Diff.TotalSeconds > 1) { foreach (string Lib in Directory.EnumerateFiles(UE4BuildPath + "/libs", "libUE4*.so", SearchOption.AllDirectories)) { File.Delete(Lib); } string CommandLine = "APP_ABI=\"" + GetNDKArch(Arch) + " " + "\""; if (!bForDistribution) { CommandLine += " NDK_DEBUG=1"; } RunCommandLineProgramWithException(UE4BuildPath, NDKBuildPath, CommandLine, "Preparing native code for debugging...", true); File.SetLastWriteTimeUtc(LibSOName, File.GetLastWriteTimeUtc(FinalSOName)); } } // after ndk-build is called, we can now copy in the stl .so (ndk-build deletes old files) // copy libgnustl_shared.so to library (use 4.8 if possible, otherwise 4.6) CopySTL(ToolChain, UE4BuildPath, Arch, NDKArch, bForDistribution); CopyGfxDebugger(UE4BuildPath, Arch, NDKArch); // copy postbuild plugin files UPL.ProcessPluginNode(NDKArch, "resourceCopies", ""); Log.TraceInformation("\n===={0}====PERFORMING FINAL APK PACKAGE OPERATION================================================", DateTime.Now.ToString()); string AntBuildType = "debug"; string AntOutputSuffix = "-debug"; if (bForDistribution) { // Generate the Proguard file contents and write it string ProguardContents = GenerateProguard(NDKArch, UE4BuildFilesPath, GameBuildFilesPath); string ProguardFilename = Path.Combine(UE4BuildPath, "proguard-project.txt"); if (File.Exists(ProguardFilename)) { File.Delete(ProguardFilename); } File.WriteAllText(ProguardFilename, ProguardContents); // this will write out ant.properties with info needed to sign a distribution build PrepareToSignApk(UE4BuildPath); AntBuildType = "release"; AntOutputSuffix = "-release"; } // Use ant to build the .apk file string ShellExecutable = Utils.IsRunningOnMono ? "/bin/sh" : "cmd.exe"; string ShellParametersBegin = Utils.IsRunningOnMono ? "-c '" : "/c "; string ShellParametersEnd = Utils.IsRunningOnMono ? "'" : ""; switch (AntVerbosity.ToLower()) { default: case "quiet": if (RunCommandLineProgramAndReturnResult(UE4BuildPath, ShellExecutable, ShellParametersBegin + "\"" + GetAntPath() + "\" -quiet " + AntBuildType + ShellParametersEnd, "Making .apk with Ant... (note: it's safe to ignore javac obsolete warnings)") != 0) { RunCommandLineProgramAndReturnResult(UE4BuildPath, ShellExecutable, ShellParametersBegin + "\"" + GetAntPath() + "\" " + AntBuildType + ShellParametersEnd, "Making .apk with Ant again to show errors"); } break; case "normal": RunCommandLineProgramAndReturnResult(UE4BuildPath, ShellExecutable, ShellParametersBegin + "\"" + GetAntPath() + "\" " + AntBuildType + ShellParametersEnd, "Making .apk with Ant again to show errors"); break; case "verbose": RunCommandLineProgramAndReturnResult(UE4BuildPath, ShellExecutable, ShellParametersBegin + "\"" + GetAntPath() + "\" -verbose " + AntBuildType + ShellParametersEnd, "Making .apk with Ant again to show errors"); break; } // make sure destination exists Directory.CreateDirectory(Path.GetDirectoryName(DestApkName)); // now copy to the final location File.Copy(UE4BuildPath + "/bin/" + ProjectName + AntOutputSuffix + ".apk", DestApkName, true); } }
private string GetAllBuildSettings(AndroidToolChain ToolChain, string BuildPath, bool bForDistribution, bool bMakeSeparateApks, bool bPackageDataInsideApk, bool bDisableVerifyOBBOnStartUp) { // make the settings string - this will be char by char compared against last time StringBuilder CurrentSettings = new StringBuilder(); CurrentSettings.AppendLine(string.Format("NDKROOT={0}", Environment.GetEnvironmentVariable("NDKROOT"))); CurrentSettings.AppendLine(string.Format("ANDROID_HOME={0}", Environment.GetEnvironmentVariable("ANDROID_HOME"))); CurrentSettings.AppendLine(string.Format("ANT_HOME={0}", Environment.GetEnvironmentVariable("ANT_HOME"))); CurrentSettings.AppendLine(string.Format("JAVA_HOME={0}", Environment.GetEnvironmentVariable("JAVA_HOME"))); CurrentSettings.AppendLine(string.Format("SDKVersion={0}", GetSdkApiLevel(ToolChain))); CurrentSettings.AppendLine(string.Format("bForDistribution={0}", bForDistribution)); CurrentSettings.AppendLine(string.Format("bMakeSeparateApks={0}", bMakeSeparateApks)); CurrentSettings.AppendLine(string.Format("bPackageDataInsideApk={0}", bPackageDataInsideApk)); CurrentSettings.AppendLine(string.Format("bDisableVerifyOBBOnStartUp={0}", bDisableVerifyOBBOnStartUp)); // all AndroidRuntimeSettings ini settings in here ConfigCacheIni Ini = GetConfigCacheIni("Engine"); ConfigCacheIni.IniSection Section = Ini.FindSection("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings"); if (Section != null) { foreach (string Key in Section.Keys) { List<string> Values = Section[Key]; foreach (string Value in Values) { CurrentSettings.AppendLine(string.Format("{0}={1}", Key, Value)); } } } Section = Ini.FindSection("/Script/AndroidPlatformEditor.AndroidSDKSettings"); if (Section != null) { foreach (string Key in Section.Keys) { List<string> Values = Section[Key]; foreach (string Value in Values) { CurrentSettings.AppendLine(string.Format("{0}={1}", Key, Value)); } } } var Arches = ToolChain.GetAllArchitectures(); foreach (string Arch in Arches) { CurrentSettings.AppendFormat("Arch={0}{1}", Arch, Environment.NewLine); } var GPUArchitectures = ToolChain.GetAllGPUArchitectures(); foreach (string GPUArch in GPUArchitectures) { CurrentSettings.AppendFormat("GPUArch={0}{1}", GPUArch, Environment.NewLine); } return CurrentSettings.ToString(); }
private void UpdateProjectProperties(AndroidToolChain ToolChain, string UE4BuildPath, string ProjectName) { Log.TraceInformation("\n===={0}====UPDATING BUILD CONFIGURATION FILES====================================================", DateTime.Now.ToString()); // get all of the libs (from engine + project) string JavaLibsDir = Path.Combine(UE4BuildPath, "JavaLibs"); string[] LibDirs = Directory.GetDirectories(JavaLibsDir); // get existing project.properties lines (if any) string ProjectPropertiesFile = Path.Combine(UE4BuildPath, "project.properties"); string[] PropertiesLines = new string[] { }; if (File.Exists(ProjectPropertiesFile)) { PropertiesLines = File.ReadAllLines(ProjectPropertiesFile); } // figure out how many libraries were already listed (if there were more than this listed, then we need to start the file over, because we need to unreference a library) int NumOutstandingAlreadyReferencedLibs = 0; foreach (string Line in PropertiesLines) { if (Line.StartsWith("android.library.reference.")) { NumOutstandingAlreadyReferencedLibs++; } } // now go through each one and verify they are listed in project properties, and if not, add them List<string> LibsToBeAdded = new List<string>(); foreach (string LibDir in LibDirs) { // put it in terms of the subdirectory that would be in the project.properties string RelativePath = "JavaLibs/" + Path.GetFileName(LibDir); // now look for this in the existing file bool bWasReferencedAlready = false; foreach (string Line in PropertiesLines) { if (Line.StartsWith("android.library.reference.") && Line.EndsWith(RelativePath)) { // this lib was already referenced, don't need to readd bWasReferencedAlready = true; break; } } if (bWasReferencedAlready) { // if it was, no further action needed, and count it off NumOutstandingAlreadyReferencedLibs--; } else { // otherwise, we need to add it to the project properties LibsToBeAdded.Add(RelativePath); } } // now at this point, if there are any outstanding already referenced libs, we have too many, so we have to start over if (NumOutstandingAlreadyReferencedLibs > 0) { // @todo android: If a user had a project.properties in the game, NEVER do this Log.TraceInformation("There were too many libs already referenced in project.properties, tossing it"); File.Delete(ProjectPropertiesFile); LibsToBeAdded.Clear(); foreach (string LibDir in LibDirs) { // put it in terms of the subdirectory that would be in the project.properties LibsToBeAdded.Add("JavaLibs/" + Path.GetFileName(LibDir)); } } // now update the project for each library string AndroidCommandPath = Environment.ExpandEnvironmentVariables("%ANDROID_HOME%/tools/android" + (Utils.IsRunningOnMono ? "" : ".bat")); string UpdateCommandLine = "--silent update project --subprojects --name " + ProjectName + " --path . --target " + GetSdkApiLevel(ToolChain); foreach (string Lib in LibsToBeAdded) { string LocalUpdateCommandLine = UpdateCommandLine + " --library " + Lib; // make sure each library has a build.xml - --subprojects doesn't create build.xml files, but it will create project.properties // and later code needs each lib to have a build.xml RunCommandLineProgramWithException(UE4BuildPath, AndroidCommandPath, "--silent update lib-project --path " + Lib + " --target " + GetSdkApiLevel(ToolChain), ""); RunCommandLineProgramWithException(UE4BuildPath, AndroidCommandPath, LocalUpdateCommandLine, "Updating project.properties, local.properties, and build.xml for " + Path.GetFileName(Lib) + "..."); } }
private static void CopySTL(AndroidToolChain ToolChain, string UE4BuildPath, string UE4Arch, string NDKArch, bool bForDistribution) { string GccVersion = "4.6"; if (Directory.Exists(Environment.ExpandEnvironmentVariables("%NDKROOT%/sources/cxx-stl/gnu-libstdc++/4.9"))) { GccVersion = "4.9"; } else if (Directory.Exists(Environment.ExpandEnvironmentVariables("%NDKROOT%/sources/cxx-stl/gnu-libstdc++/4.8"))) { GccVersion = "4.8"; } // copy it in! string SourceSTLSOName = Environment.ExpandEnvironmentVariables("%NDKROOT%/sources/cxx-stl/gnu-libstdc++/") + GccVersion + "/libs/" + NDKArch + "/libgnustl_shared.so"; string FinalSTLSOName = UE4BuildPath + "/libs/" + NDKArch + "/libgnustl_shared.so"; // check to see if libgnustl_shared.so is newer than last time we copied (or needs stripping for distribution) bool bFileExists = File.Exists(FinalSTLSOName); TimeSpan Diff = File.GetLastWriteTimeUtc(FinalSTLSOName) - File.GetLastWriteTimeUtc(SourceSTLSOName); if (bForDistribution || !bFileExists || Diff.TotalSeconds < -1 || Diff.TotalSeconds > 1) { if (bFileExists) { File.Delete(FinalSTLSOName); } Directory.CreateDirectory(Path.GetDirectoryName(FinalSTLSOName)); if (bForDistribution) { // Strip debug symbols for distribution builds StripDebugSymbols(SourceSTLSOName, FinalSTLSOName, UE4Arch); } else { File.Copy(SourceSTLSOName, FinalSTLSOName, true); } } }
public override bool PrepForUATPackageOrDeploy(FileReference ProjectFile, string ProjectName, string ProjectDirectory, string ExecutablePath, string EngineDirectory, bool bForDistribution, string CookFlavor, bool bIsDataDeploy) { //Log.TraceInformation("$$$$$$$$$$$$$$ PrepForUATPackageOrDeploy $$$$$$$$$$$$$$$$$"); // note that we cannot allow the data packaged into the APK if we are doing something like Launch On that will not make an obb // file and instead pushes files directly via deploy AndroidToolChain ToolChain = new AndroidToolChain(ProjectFile); MakeApk(ToolChain, ProjectName, ProjectDirectory, ExecutablePath, EngineDirectory, bForDistribution: bForDistribution, CookFlavor: CookFlavor, bMakeSeparateApks: ShouldMakeSeparateApks(), bIncrementalPackage: false, bDisallowPackagingDataInApk: bIsDataDeploy); return true; }
public override bool PrepTargetForDeployment(UEBuildTarget InTarget) { //Log.TraceInformation("$$$$$$$$$$$$$$ PrepTargetForDeployment $$$$$$$$$$$$$$$$$"); AndroidToolChain ToolChain = new AndroidToolChain(InTarget.ProjectFile); // we need to strip architecture from any of the output paths string BaseSoName = ToolChain.RemoveArchName(InTarget.OutputPaths[0].FullName); // get the receipt UnrealTargetPlatform Platform = InTarget.Platform; UnrealTargetConfiguration Configuration = InTarget.Configuration; string ProjectBaseName = Path.GetFileName(BaseSoName).Replace("-" + Platform, "").Replace("-" + Configuration, "").Replace(".so", ""); string ReceiptFilename = TargetReceipt.GetDefaultPath(InTarget.ProjectDirectory.FullName, ProjectBaseName, Platform, Configuration, ""); Log.TraceInformation("Receipt Filename: {0}", ReceiptFilename); SetAndroidPluginData(ToolChain.GetAllArchitectures(), CollectPluginDataPaths(TargetReceipt.Read(ReceiptFilename))); // make an apk at the end of compiling, so that we can run without packaging (debugger, cook on the fly, etc) MakeApk(ToolChain, InTarget.AppName, InTarget.ProjectDirectory.FullName, BaseSoName, BuildConfiguration.RelativeEnginePath, bForDistribution: false, CookFlavor: "", bMakeSeparateApks: ShouldMakeSeparateApks(), bIncrementalPackage: true, bDisallowPackagingDataInApk: false); // if we made any non-standard .apk files, the generated debugger settings may be wrong if (ShouldMakeSeparateApks() && (InTarget.OutputPaths.Count > 1 || !InTarget.OutputPaths[0].FullName.Contains("-armv7-es2"))) { Console.WriteLine("================================================================================================================================"); Console.WriteLine("Non-default apk(s) have been made: If you are debugging, you will need to manually select one to run in the debugger properties!"); Console.WriteLine("================================================================================================================================"); } return true; }
public override List<FileReference> FinalizeBinaryPaths(FileReference BinaryName, FileReference ProjectFile) { AndroidToolChain ToolChain = new AndroidToolChain(ProjectFile); var Architectures = ToolChain.GetAllArchitectures(); var GPUArchitectures = ToolChain.GetAllGPUArchitectures(); // make multiple output binaries List<FileReference> AllBinaries = new List<FileReference>(); foreach (string Architecture in Architectures) { foreach (string GPUArchitecture in GPUArchitectures) { AllBinaries.Add(new FileReference(AndroidToolChain.InlineArchName(BinaryName.FullName, Architecture, GPUArchitecture))); } } return AllBinaries; }
public override void SetUpEnvironment(UEBuildTarget InBuildTarget) { // we want gcc toolchain 4.9, but fall back to 4.8 or 4.6 for now if it doesn't exist string NDKPath = Environment.GetEnvironmentVariable("NDKROOT"); NDKPath = NDKPath.Replace("\"", ""); AndroidToolChain ToolChain = new AndroidToolChain(InBuildTarget.ProjectFile); string GccVersion = "4.6"; int NDKVersionInt = ToolChain.GetNdkApiLevelInt(); if (Directory.Exists(Path.Combine(NDKPath, @"sources/cxx-stl/gnu-libstdc++/4.9"))) { GccVersion = "4.9"; } else if (Directory.Exists(Path.Combine(NDKPath, @"sources/cxx-stl/gnu-libstdc++/4.8"))) { GccVersion = "4.8"; } Log.TraceInformation("NDK version: {0}, GccVersion: {1}", NDKVersionInt.ToString(), GccVersion); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("PLATFORM_DESKTOP=0"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("PLATFORM_CAN_SUPPORT_EDITORONLY_DATA=0"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WITH_OGGVORBIS=1"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("UNICODE"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("_UNICODE"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("PLATFORM_ANDROID=1"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("ANDROID=1"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WITH_DATABASE_SUPPORT=0"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WITH_EDITOR=0"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("USE_NULL_RHI=0"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("REQUIRES_ALIGNED_INT_ACCESS"); InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/include"); // the toolchain will actually filter these out InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/armeabi-v7a/include"); InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/arm64-v8a/include"); InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86/include"); InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86_64/include"); InBuildTarget.GlobalLinkEnvironment.Config.LibraryPaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/armeabi-v7a"); InBuildTarget.GlobalLinkEnvironment.Config.LibraryPaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/arm64-v8a"); InBuildTarget.GlobalLinkEnvironment.Config.LibraryPaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86"); InBuildTarget.GlobalLinkEnvironment.Config.LibraryPaths.Add("$(NDKROOT)/sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86_64"); InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/android/native_app_glue"); InBuildTarget.GlobalCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.Add("$(NDKROOT)/sources/android/cpufeatures"); //@TODO: Tegra Gfx Debugger - standardize locations - for now, change the hardcoded paths and force this to return true to test if (UseTegraGraphicsDebugger(InBuildTarget)) { //InBuildTarget.GlobalLinkEnvironment.Config.LibraryPaths.Add(UEBuildConfiguration.UEThirdPartySourceDirectory + "NVIDIA/TegraGfxDebugger"); //InBuildTarget.GlobalLinkEnvironment.Config.LibraryPaths.Add("F:/NVPACK/android-kk-egl-t124-a32/stub"); //InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("Nvidia_gfx_debugger_stub"); } InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("gnustl_shared"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("gcc"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("z"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("c"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("m"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("log"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("dl"); if (!UseTegraGraphicsDebugger(InBuildTarget)) { InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("GLESv2"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("EGL"); } InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("OpenSLES"); InBuildTarget.GlobalLinkEnvironment.Config.AdditionalLibraries.Add("android"); UEBuildConfiguration.bCompileSimplygon = false; UEBuildConfiguration.bCompileSimplygonSSF = false; BuildConfiguration.bDeployAfterCompile = true; bool bBuildWithVulkan = IsVulkanSDKAvailable() && IsVulkanSupportEnabled(); if (bBuildWithVulkan) { InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("PLATFORM_ANDROID_VULKAN=1"); Log.TraceInformationOnce("building with VULKAN define"); } else { Log.TraceInformationOnce("building WITHOUT VULKAN define"); } }
private bool CheckDependencies(AndroidToolChain ToolChain, string ProjectName, string ProjectDirectory, string UE4BuildFilesPath, string GameBuildFilesPath, string EngineDirectory, List<string> SettingsFiles, string CookFlavor, string OutputPath, string UE4BuildPath, bool bMakeSeparateApks, bool bPackageDataInsideApk) { var Arches = ToolChain.GetAllArchitectures(); var GPUArchitectures = ToolChain.GetAllGPUArchitectures(); // check all input files (.so, java files, .ini files, etc) bool bAllInputsCurrent = true; foreach (string Arch in Arches) { foreach (string GPUArch in GPUArchitectures) { string SourceSOName = AndroidToolChain.InlineArchName(OutputPath, Arch, GPUArch); // if the source binary was UE4Game, replace it with the new project name, when re-packaging a binary only build string ApkFilename = Path.GetFileNameWithoutExtension(OutputPath).Replace("UE4Game", ProjectName); string DestApkName = Path.Combine(ProjectDirectory, "Binaries/Android/") + ApkFilename + ".apk"; // if we making multiple Apks, we need to put the architecture into the name if (bMakeSeparateApks) { DestApkName = AndroidToolChain.InlineArchName(DestApkName, Arch, GPUArch); } // check to see if it's out of date before trying the slow make apk process (look at .so and all Engine and Project build files to be safe) List<String> InputFiles = new List<string>(); InputFiles.Add(SourceSOName); InputFiles.AddRange(Directory.EnumerateFiles(UE4BuildFilesPath, "*.*", SearchOption.AllDirectories)); if (Directory.Exists(GameBuildFilesPath)) { InputFiles.AddRange(Directory.EnumerateFiles(GameBuildFilesPath, "*.*", SearchOption.AllDirectories)); } // make sure changed java files will rebuild apk InputFiles.AddRange(SettingsFiles); // rebuild if .pak files exist for OBB in APK case if (bPackageDataInsideApk) { string PAKFileLocation = ProjectDirectory + "/Saved/StagedBuilds/Android" + CookFlavor + "/" + ProjectName + "/Content/Paks"; if (Directory.Exists(PAKFileLocation)) { var PakFiles = Directory.EnumerateFiles(PAKFileLocation, "*.pak", SearchOption.TopDirectoryOnly); foreach (var Name in PakFiles) { InputFiles.Add(Name); } } } // look for any newer input file DateTime ApkTime = File.GetLastWriteTimeUtc(DestApkName); foreach (var InputFileName in InputFiles) { if (File.Exists(InputFileName)) { // skip .log files if (Path.GetExtension(InputFileName) == ".log") { continue; } DateTime InputFileTime = File.GetLastWriteTimeUtc(InputFileName); if (InputFileTime.CompareTo(ApkTime) > 0) { bAllInputsCurrent = false; Log.TraceInformation("{0} is out of date due to newer input file {1}", DestApkName, InputFileName); break; } } } } } return bAllInputsCurrent; }
/// <summary> /// /// </summary> /// <param name="SourceFile"></param> /// <param name="TargetFile"></param> public static void StripSymbols(FileReference SourceFile, FileReference TargetFile) { AndroidToolChain ToolChain = new AndroidToolChain(null, false, null, null); ToolChain.StripSymbols(SourceFile, TargetFile); }
public virtual void SetUpSpecificEnvironment(ReadOnlyTargetRules Target, CppCompileEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment) { string NDKPath = Environment.GetEnvironmentVariable("NDKROOT"); NDKPath = NDKPath.Replace("\"", ""); AndroidToolChain ToolChain = new AndroidToolChain(Target.ProjectFile, false, Target.AndroidPlatform.Architectures, Target.AndroidPlatform.GPUArchitectures); // figure out the NDK version string NDKToolchainVersion = ToolChain.NDKToolchainVersion; string NDKDefine = ToolChain.NDKDefine; string GccVersion = "4.9"; // PLATFORM_ANDROID_NDK_VERSION is in the form 150100, where 15 is major version, 01 is the letter (1 is 'a'), 00 indicates beta revision if letter is 00 Log.TraceInformation("PLATFORM_ANDROID_NDK_VERSION = {0}", NDKDefine); CompileEnvironment.Definitions.Add("PLATFORM_ANDROID_NDK_VERSION=" + NDKDefine); int NDKVersionInt = ToolChain.GetNdkApiLevelInt(); Log.TraceInformation("NDK toolchain: {0}, NDK version: {1}, GccVersion: {2}, ClangVersion: {3}", NDKToolchainVersion, NDKVersionInt.ToString(), GccVersion, ToolChain.GetClangVersionString()); ToolChain.ShowNDKWarnings(); CompileEnvironment.Definitions.Add("PLATFORM_DESKTOP=0"); CompileEnvironment.Definitions.Add("PLATFORM_CAN_SUPPORT_EDITORONLY_DATA=0"); CompileEnvironment.Definitions.Add("WITH_OGGVORBIS=1"); CompileEnvironment.Definitions.Add("UNICODE"); CompileEnvironment.Definitions.Add("_UNICODE"); CompileEnvironment.Definitions.Add("PLATFORM_ANDROID=1"); CompileEnvironment.Definitions.Add("ANDROID=1"); CompileEnvironment.Definitions.Add("WITH_EDITOR=0"); CompileEnvironment.Definitions.Add("USE_NULL_RHI=0"); DirectoryReference NdkDir = new DirectoryReference(NDKPath); //CompileEnvironment.SystemIncludePaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/llvm-libc++/include")); // the toolchain will actually filter these out LinkEnvironment.LibraryPaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/llvm-libc++/libs/armeabi-v7a")); LinkEnvironment.LibraryPaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/llvm-libc++/libs/arm64-v8a")); LinkEnvironment.LibraryPaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/llvm-libc++/libs/x86")); LinkEnvironment.LibraryPaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/llvm-libc++/libs/x86_64")); CompileEnvironment.SystemIncludePaths.Add(DirectoryReference.Combine(NdkDir, "sources/android/native_app_glue")); CompileEnvironment.SystemIncludePaths.Add(DirectoryReference.Combine(NdkDir, "sources/android/cpufeatures")); //@TODO: Tegra Gfx Debugger - standardize locations - for now, change the hardcoded paths and force this to return true to test if (UseTegraGraphicsDebugger(Target)) { //LinkEnvironment.LibraryPaths.Add("ThirdParty/NVIDIA/TegraGfxDebugger"); //LinkEnvironment.LibraryPaths.Add("F:/NVPACK/android-kk-egl-t124-a32/stub"); //LinkEnvironment.AdditionalLibraries.Add("Nvidia_gfx_debugger_stub"); } if (!UseTegraGraphicsDebugger(Target)) { LinkEnvironment.AdditionalLibraries.Add("GLESv2"); LinkEnvironment.AdditionalLibraries.Add("EGL"); } LinkEnvironment.AdditionalLibraries.Add("android"); LinkEnvironment.AdditionalLibraries.Add("OpenSLES"); }
public override void SetUpEnvironment(ReadOnlyTargetRules Target, CppCompileEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment) { // we want gcc toolchain 4.9, but fall back to 4.8 or 4.6 for now if it doesn't exist string NDKPath = Environment.GetEnvironmentVariable("NDKROOT"); NDKPath = NDKPath.Replace("\"", ""); AndroidToolChain ToolChain = new AndroidToolChain(Target.ProjectFile, false, Target.AndroidPlatform.Architectures, Target.AndroidPlatform.GPUArchitectures); // figure out the NDK version string NDKToolchainVersion = ToolChain.NDKToolchainVersion; string NDKDefine = ToolChain.NDKDefine; // PLATFORM_ANDROID_NDK_VERSION is in the form 150100, where 15 is major version, 01 is the letter (1 is 'a'), 00 indicates beta revision if letter is 00 Log.TraceInformation("PLATFORM_ANDROID_NDK_VERSION = {0}", NDKDefine); CompileEnvironment.Definitions.Add("PLATFORM_ANDROID_NDK_VERSION=" + NDKDefine); string GccVersion = "4.6"; int NDKVersionInt = ToolChain.GetNdkApiLevelInt(); if (Directory.Exists(Path.Combine(NDKPath, @"sources/cxx-stl/gnu-libstdc++/4.9"))) { GccVersion = "4.9"; } else if (Directory.Exists(Path.Combine(NDKPath, @"sources/cxx-stl/gnu-libstdc++/4.8"))) { GccVersion = "4.8"; } Log.TraceInformation("NDK toolchain: {0}, NDK version: {1}, GccVersion: {2}, ClangVersion: {3}", NDKToolchainVersion, NDKVersionInt.ToString(), GccVersion, ToolChain.GetClangVersionString()); CompileEnvironment.Definitions.Add("PLATFORM_DESKTOP=0"); CompileEnvironment.Definitions.Add("PLATFORM_CAN_SUPPORT_EDITORONLY_DATA=0"); CompileEnvironment.Definitions.Add("WITH_OGGVORBIS=1"); CompileEnvironment.Definitions.Add("UNICODE"); CompileEnvironment.Definitions.Add("_UNICODE"); CompileEnvironment.Definitions.Add("PLATFORM_ANDROID=1"); CompileEnvironment.Definitions.Add("ANDROID=1"); CompileEnvironment.Definitions.Add("WITH_DATABASE_SUPPORT=0"); CompileEnvironment.Definitions.Add("WITH_EDITOR=0"); CompileEnvironment.Definitions.Add("USE_NULL_RHI=0"); CompileEnvironment.Definitions.Add("REQUIRES_ALIGNED_INT_ACCESS"); DirectoryReference NdkDir = new DirectoryReference(NDKPath); CompileEnvironment.IncludePaths.SystemIncludePaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/include")); // the toolchain will actually filter these out CompileEnvironment.IncludePaths.SystemIncludePaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/armeabi-v7a/include")); CompileEnvironment.IncludePaths.SystemIncludePaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/arm64-v8a/include")); CompileEnvironment.IncludePaths.SystemIncludePaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86/include")); CompileEnvironment.IncludePaths.SystemIncludePaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86_64/include")); LinkEnvironment.LibraryPaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/armeabi-v7a")); LinkEnvironment.LibraryPaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/arm64-v8a")); LinkEnvironment.LibraryPaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86")); LinkEnvironment.LibraryPaths.Add(DirectoryReference.Combine(NdkDir, "sources/cxx-stl/gnu-libstdc++/" + GccVersion + "/libs/x86_64")); CompileEnvironment.IncludePaths.SystemIncludePaths.Add(DirectoryReference.Combine(NdkDir, "sources/android/native_app_glue")); CompileEnvironment.IncludePaths.SystemIncludePaths.Add(DirectoryReference.Combine(NdkDir, "sources/android/cpufeatures")); //@TODO: Tegra Gfx Debugger - standardize locations - for now, change the hardcoded paths and force this to return true to test if (UseTegraGraphicsDebugger(Target)) { //LinkEnvironment.LibraryPaths.Add("ThirdParty/NVIDIA/TegraGfxDebugger"); //LinkEnvironment.LibraryPaths.Add("F:/NVPACK/android-kk-egl-t124-a32/stub"); //LinkEnvironment.AdditionalLibraries.Add("Nvidia_gfx_debugger_stub"); } SetupGraphicsDebugger(Target, CompileEnvironment, LinkEnvironment); LinkEnvironment.AdditionalLibraries.Add("gnustl_shared"); LinkEnvironment.AdditionalLibraries.Add("gcc"); LinkEnvironment.AdditionalLibraries.Add("z"); LinkEnvironment.AdditionalLibraries.Add("c"); LinkEnvironment.AdditionalLibraries.Add("m"); LinkEnvironment.AdditionalLibraries.Add("log"); LinkEnvironment.AdditionalLibraries.Add("dl"); if (!UseTegraGraphicsDebugger(Target)) { LinkEnvironment.AdditionalLibraries.Add("GLESv2"); LinkEnvironment.AdditionalLibraries.Add("EGL"); } LinkEnvironment.AdditionalLibraries.Add("OpenSLES"); LinkEnvironment.AdditionalLibraries.Add("android"); }
private string GenerateManifest(AndroidToolChain ToolChain, string ProjectName, bool bIsForDistribution, bool bPackageDataInsideApk, string GameBuildFilesPath, bool bHasOBBFiles, bool bDisableVerifyOBBOnStartUp, string UE4Arch, string GPUArch, string CookFlavor) { string Arch = GetNDKArch(UE4Arch); int NDKLevelInt = ToolChain.GetNdkApiLevelInt(); // 64-bit targets must be android-21 or higher if (NDKLevelInt < 21) { if (UE4Arch == "-arm64" || UE4Arch == "-x64") { NDKLevelInt = 21; } } // ini file to get settings from ConfigCacheIni Ini = GetConfigCacheIni("Engine"); string PackageName = GetPackageName(ProjectName); bool bEnableGooglePlaySupport; Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bEnableGooglePlaySupport", out bEnableGooglePlaySupport); string DepthBufferPreference; Ini.GetString("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "DepthBufferPreference", out DepthBufferPreference); int MinSDKVersion; Ini.GetInt32("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "MinSDKVersion", out MinSDKVersion); int TargetSDKVersion = MinSDKVersion; Ini.GetInt32("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "TargetSDKVersion", out TargetSDKVersion); int StoreVersion; Ini.GetInt32("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "StoreVersion", out StoreVersion); string VersionDisplayName; Ini.GetString("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "VersionDisplayName", out VersionDisplayName); string Orientation; Ini.GetString("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "Orientation", out Orientation); bool EnableFullScreen; Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bFullScreen", out EnableFullScreen); List<string> ExtraManifestNodeTags; Ini.GetArray("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "ExtraManifestNodeTags", out ExtraManifestNodeTags); List<string> ExtraApplicationNodeTags; Ini.GetArray("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "ExtraApplicationNodeTags", out ExtraApplicationNodeTags); List<string> ExtraActivityNodeTags; Ini.GetArray("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "ExtraActivityNodeTags", out ExtraActivityNodeTags); string ExtraActivitySettings; Ini.GetString("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "ExtraActivitySettings", out ExtraActivitySettings); string ExtraApplicationSettings; Ini.GetString("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "ExtraApplicationSettings", out ExtraApplicationSettings); List<string> ExtraPermissions; Ini.GetArray("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "ExtraPermissions", out ExtraPermissions); bool bPackageForGearVR; Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bPackageForGearVR", out bPackageForGearVR); bool bSupportsVulkan; Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bSupportsVulkan", out bSupportsVulkan); if (bSupportsVulkan) { bSupportsVulkan = IsVulkanSDKAvailable(); } bool bEnableIAP = false; Ini.GetBool("OnlineSubsystemGooglePlay.Store", "bSupportsInAppPurchasing", out bEnableIAP); bool bShowLaunchImage = false; Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bShowLaunchImage", out bShowLaunchImage); string InstallLocation; Ini.GetString("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "InstallLocation", out InstallLocation); switch(InstallLocation.ToLower()) { case "preferexternal": InstallLocation = "preferExternal"; break; case "auto": InstallLocation = "auto"; break; default: InstallLocation = "internalOnly"; break; } // fix up the MinSdkVersion if (NDKLevelInt > 19) { if (MinSDKVersion < 21) { MinSDKVersion = 21; Log.TraceInformation("Fixing minSdkVersion; NDK level above 19 requires minSdkVersion of 21 (arch={0})", UE4Arch.Substring(1)); } } // disable GearVR if not supported platform (in this case only armv7 for now) if (UE4Arch != "-armv7") { if (bPackageForGearVR) { Log.TraceInformation("Disabling Package For GearVR for unsupported architecture {0}", UE4Arch); bPackageForGearVR = false; } } // disable splash screen for GearVR (for now) if (bPackageForGearVR) { if (bShowLaunchImage) { Log.TraceInformation("Disabling Show Launch Image for GearVR enabled application"); bShowLaunchImage = false; } } //figure out which texture compressions are supported bool bETC1Enabled, bETC2Enabled, bDXTEnabled, bATCEnabled, bPVRTCEnabled, bASTCEnabled; bETC1Enabled = bETC2Enabled = bDXTEnabled = bATCEnabled = bPVRTCEnabled = bASTCEnabled = false; if (CookFlavor.Length < 1) { //All values supproted bETC1Enabled = bETC2Enabled = bDXTEnabled = bATCEnabled = bPVRTCEnabled = bASTCEnabled = true; } else { switch(CookFlavor) { case "_Multi": //need to check ini to determine which are supported Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bMultiTargetFormat_ETC1", out bETC1Enabled); Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bMultiTargetFormat_ETC2", out bETC2Enabled); Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bMultiTargetFormat_DXT", out bDXTEnabled); Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bMultiTargetFormat_ATC", out bATCEnabled); Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bMultiTargetFormat_PVRTC", out bPVRTCEnabled); Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bMultiTargetFormat_ASTC", out bASTCEnabled); break; case "_ETC1": bETC1Enabled = true; break; case "_ETC2": bETC2Enabled = true; break; case "_DXT": bDXTEnabled = true; break; case "_ATC": bATCEnabled = true; break; case "_PVRTC": bPVRTCEnabled = true; break; case "_ASTC": bASTCEnabled = true; break; default: Log.TraceWarning("Invalid or unknown CookFlavor used in GenerateManifest: {0}", CookFlavor); break; } } StringBuilder Text = new StringBuilder(); Text.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); Text.AppendLine("<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\""); Text.AppendLine(string.Format(" package=\"{0}\"", PackageName)); if (ExtraManifestNodeTags != null) { foreach (string Line in ExtraManifestNodeTags) { Text.AppendLine(" " + Line); } } Text.AppendLine(string.Format(" android:installLocation=\"{0}\"", InstallLocation)); Text.AppendLine(string.Format(" android:versionCode=\"{0}\"", StoreVersion)); Text.AppendLine(string.Format(" android:versionName=\"{0}\">", VersionDisplayName)); Text.AppendLine(""); Text.AppendLine("\t<!-- Application Definition -->"); Text.AppendLine("\t<application android:label=\"@string/app_name\""); Text.AppendLine("\t android:icon=\"@drawable/icon\""); if (ExtraApplicationNodeTags != null) { foreach (string Line in ExtraApplicationNodeTags) { Text.AppendLine("\t " + Line); } } Text.AppendLine("\t android:hasCode=\"true\">"); if (bShowLaunchImage) { // normal application settings Text.AppendLine("\t\t<activity android:name=\"com.epicgames.ue4.SplashActivity\""); Text.AppendLine("\t\t android:label=\"@string/app_name\""); Text.AppendLine("\t\t android:theme=\"@style/UE4SplashTheme\""); Text.AppendLine("\t\t android:launchMode=\"singleTask\""); Text.AppendLine(string.Format("\t\t android:screenOrientation=\"{0}\"", ConvertOrientationIniValue(Orientation))); Text.AppendLine(string.Format("\t\t android:debuggable=\"{0}\">", bIsForDistribution ? "false" : "true")); Text.AppendLine("\t\t\t<intent-filter>"); Text.AppendLine("\t\t\t\t<action android:name=\"android.intent.action.MAIN\" />"); Text.AppendLine(string.Format("\t\t\t\t<category android:name=\"android.intent.category.LAUNCHER\" />")); Text.AppendLine("\t\t\t</intent-filter>"); Text.AppendLine("\t\t</activity>"); Text.AppendLine("\t\t<activity android:name=\"com.epicgames.ue4.GameActivity\""); Text.AppendLine("\t\t android:label=\"@string/app_name\""); Text.AppendLine("\t\t android:theme=\"@style/UE4SplashTheme\""); Text.AppendLine("\t\t android:configChanges=\"screenSize|orientation|keyboardHidden|keyboard\""); } else { Text.AppendLine("\t\t<activity android:name=\"com.epicgames.ue4.GameActivity\""); Text.AppendLine("\t\t android:label=\"@string/app_name\""); Text.AppendLine("\t\t android:theme=\"@android:style/Theme.Black.NoTitleBar.Fullscreen\""); Text.AppendLine("\t\t android:configChanges=\"screenSize|orientation|keyboardHidden|keyboard\""); } Text.AppendLine("\t\t android:launchMode=\"singleTask\""); Text.AppendLine(string.Format("\t\t android:screenOrientation=\"{0}\"", ConvertOrientationIniValue(Orientation))); if (ExtraActivityNodeTags != null) { foreach (string Line in ExtraActivityNodeTags) { Text.AppendLine("\t\t " + Line); } } Text.AppendLine(string.Format("\t\t android:debuggable=\"{0}\">", bIsForDistribution ? "false" : "true")); Text.AppendLine("\t\t\t<meta-data android:name=\"android.app.lib_name\" android:value=\"UE4\"/>"); if (!bShowLaunchImage) { Text.AppendLine("\t\t\t<intent-filter>"); Text.AppendLine("\t\t\t\t<action android:name=\"android.intent.action.MAIN\" />"); Text.AppendLine(string.Format("\t\t\t\t<category android:name=\"android.intent.category.LAUNCHER\" />")); Text.AppendLine("\t\t\t</intent-filter>"); } if (!string.IsNullOrEmpty(ExtraActivitySettings)) { ExtraActivitySettings = ExtraActivitySettings.Replace("\\n", "\n"); foreach (string Line in ExtraActivitySettings.Split("\r\n".ToCharArray())) { Text.AppendLine("\t\t\t" + Line); } } string ActivityAdditionsFile = Path.Combine(GameBuildFilesPath, "ManifestActivityAdditions.txt"); if (File.Exists(ActivityAdditionsFile)) { foreach (string Line in File.ReadAllLines(ActivityAdditionsFile)) { Text.AppendLine("\t\t\t" + Line); } } Text.AppendLine("\t\t</activity>"); // For OBB download support if (bShowLaunchImage) { Text.AppendLine("\t\t<activity android:name=\".DownloaderActivity\""); Text.AppendLine(string.Format("\t\t android:screenOrientation=\"{0}\"", ConvertOrientationIniValue(Orientation))); Text.AppendLine("\t\t android:configChanges=\"screenSize|orientation|keyboardHidden|keyboard\""); Text.AppendLine("\t\t android:theme=\"@style/UE4SplashTheme\" />"); } else { Text.AppendLine("\t\t<activity android:name=\".DownloaderActivity\" />"); } Text.AppendLine(string.Format("\t\t<meta-data android:name=\"com.epicgames.ue4.GameActivity.DepthBufferPreference\" android:value=\"{0}\"/>", ConvertDepthBufferIniValue(DepthBufferPreference))); Text.AppendLine(string.Format("\t\t<meta-data android:name=\"com.epicgames.ue4.GameActivity.bPackageDataInsideApk\" android:value=\"{0}\"/>", bPackageDataInsideApk ? "true" : "false")); Text.AppendLine(string.Format("\t\t<meta-data android:name=\"com.epicgames.ue4.GameActivity.bVerifyOBBOnStartUp\" android:value=\"{0}\"/>", (bIsForDistribution && !bDisableVerifyOBBOnStartUp) ? "true" : "false")); Text.AppendLine(string.Format("\t\t<meta-data android:name=\"com.epicgames.ue4.GameActivity.bShouldHideUI\" android:value=\"{0}\"/>", EnableFullScreen ? "true" : "false")); Text.AppendLine(string.Format("\t\t<meta-data android:name=\"com.epicgames.ue4.GameActivity.ProjectName\" android:value=\"{0}\"/>", ProjectName)); Text.AppendLine(string.Format("\t\t<meta-data android:name=\"com.epicgames.ue4.GameActivity.bHasOBBFiles\" android:value=\"{0}\"/>", bHasOBBFiles ? "true" : "false")); Text.AppendLine(string.Format("\t\t<meta-data android:name=\"com.epicgames.ue4.GameActivity.bSupportsVulkan\" android:value=\"{0}\"/>", bSupportsVulkan ? "true" : "false")); Text.AppendLine("\t\t<meta-data android:name=\"com.google.android.gms.games.APP_ID\""); Text.AppendLine("\t\t android:value=\"@string/app_id\" />"); Text.AppendLine("\t\t<meta-data android:name=\"com.google.android.gms.version\""); Text.AppendLine("\t\t android:value=\"@integer/google_play_services_version\" />"); Text.AppendLine("\t\t<activity android:name=\"com.google.android.gms.ads.AdActivity\""); Text.AppendLine("\t\t android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize\"/>"); if (!string.IsNullOrEmpty(ExtraApplicationSettings)) { ExtraApplicationSettings = ExtraApplicationSettings.Replace("\\n", "\n"); foreach (string Line in ExtraApplicationSettings.Split("\r\n".ToCharArray())) { Text.AppendLine("\t\t" + Line); } } string ApplicationAdditionsFile = Path.Combine(GameBuildFilesPath, "ManifestApplicationAdditions.txt"); if (File.Exists(ApplicationAdditionsFile)) { foreach (string Line in File.ReadAllLines(ApplicationAdditionsFile)) { Text.AppendLine("\t\t" + Line); } } // Required for OBB download support Text.AppendLine("\t\t<service android:name=\"OBBDownloaderService\" />"); Text.AppendLine("\t\t<receiver android:name=\"AlarmReceiver\" />"); Text.AppendLine("\t\t<receiver android:name=\"com.epicgames.ue4.LocalNotificationReceiver\" />"); Text.AppendLine("\t</application>"); Text.AppendLine(""); Text.AppendLine("\t<!-- Requirements -->"); // check for an override for the requirements section of the manifest string RequirementsOverrideFile = Path.Combine(GameBuildFilesPath, "ManifestRequirementsOverride.txt"); if (File.Exists(RequirementsOverrideFile)) { foreach (string Line in File.ReadAllLines(RequirementsOverrideFile)) { Text.AppendLine("\t" + Line); } } else { // need just the number part of the sdk Text.AppendLine(string.Format("\t<uses-sdk android:minSdkVersion=\"{0}\" android:targetSdkVersion=\"{1}\"/>", MinSDKVersion, TargetSDKVersion)); Text.AppendLine("\t<uses-feature android:glEsVersion=\"" + AndroidToolChain.GetGLESVersionFromGPUArch(GPUArch) + "\" android:required=\"true\" />"); Text.AppendLine("\t<uses-permission android:name=\"android.permission.INTERNET\"/>"); Text.AppendLine("\t<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>"); Text.AppendLine("\t<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>"); Text.AppendLine("\t<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>"); Text.AppendLine("\t<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>"); Text.AppendLine("\t<uses-permission android:name=\"com.android.vending.CHECK_LICENSE\"/>"); Text.AppendLine("\t<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>"); Text.AppendLine("\t<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>"); Text.AppendLine("\t<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>"); Text.AppendLine("\t<uses-permission android:name=\"android.permission.VIBRATE\"/>"); // Text.AppendLine("\t<uses-permission android:name=\"android.permission.DISABLE_KEYGUARD\"/>"); if (bEnableIAP) { Text.AppendLine("\t<uses-permission android:name=\"com.android.vending.BILLING\"/>"); } if (ExtraPermissions != null) { foreach (string Permission in ExtraPermissions) { Text.AppendLine(string.Format("\t<uses-permission android:name=\"{0}\"/>", Permission)); } } string RequirementsAdditionsFile = Path.Combine(GameBuildFilesPath, "ManifestRequirementsAdditions.txt"); if (File.Exists(RequirementsAdditionsFile)) { foreach (string Line in File.ReadAllLines(RequirementsAdditionsFile)) { Text.AppendLine("\t" + Line); } } Text.AppendLine("\t<!-- Supported texture compression formats (cooked) -->"); if (bETC1Enabled) { Text.AppendLine("\t<supports-gl-texture android:name=\"GL_OES_compressed_ETC1_RGB8_texture\" />"); } if (bETC2Enabled) { Text.AppendLine("\t<supports-gl-texture android:name=\"GL_COMPRESSED_RGB8_ETC2\" />"); Text.AppendLine("\t<supports-gl-texture android:name=\"GL_COMPRESSED_RGBA8_ETC2_EAC\" />"); } if (bATCEnabled) { Text.AppendLine("\t<supports-gl-texture android:name=\"GL_AMD_compressed_ATC_texture\" />"); Text.AppendLine("\t<supports-gl-texture android:name=\"GL_ATI_texture_compression_atitc\" />"); } if (bDXTEnabled) { Text.AppendLine("\t<supports-gl-texture android:name=\"GL_EXT_texture_compression_dxt1\" />"); Text.AppendLine("\t<supports-gl-texture android:name=\"GL_EXT_texture_compression_s3tc\" />"); Text.AppendLine("\t<supports-gl-texture android:name=\"GL_NV_texture_compression_s3tc\" />"); } if (bPVRTCEnabled) { Text.AppendLine("\t<supports-gl-texture android:name=\"GL_IMG_texture_compression_pvrtc\" />"); } if (bASTCEnabled) { Text.AppendLine("\t<supports-gl-texture android:name=\"GL_KHR_texture_compression_astc_ldr\" />"); } } Text.AppendLine("</manifest>"); // allow plugins to modify final manifest HERE XDocument XDoc; try { XDoc = XDocument.Parse(Text.ToString()); } catch (Exception e) { throw new BuildException("AndroidManifest.xml is invalid {0}\n{1}", e, Text.ToString()); } UPL.ProcessPluginNode(Arch, "androidManifestUpdates", "", ref XDoc); return XDoc.ToString(); }