// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; using EpicGames.Core; using Microsoft.Extensions.Logging; using UnrealBuildBase; namespace UnrealBuildTool { /// /// Base class for platform-specific project generators /// class AndroidProjectGenerator : PlatformProjectGenerator { /// /// Whether Android Game Development Extension is installed in the system. See https://developer.android.com/games/agde for more details. /// May be disabled by using -noagde on commandline /// private bool AGDEInstalled = false; public AndroidProjectGenerator(CommandLineArguments Arguments, ILogger Logger) : base(Arguments, Logger) { AGDEInstalled = false; if (OperatingSystem.IsWindows() && !Arguments.HasOption("-noagde")) { AGDEInstalled = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\Google\AndroidGameDevelopmentExtension")?.ValueCount > 0; if (!AGDEInstalled) { try { string? programFiles86 = Environment.GetEnvironmentVariable("ProgramFiles(x86)"); if (programFiles86 != null) { string vswhereExe = Path.Join(programFiles86, @"Microsoft Visual Studio\Installer\vswhere.exe"); if (File.Exists(vswhereExe)) { using (Process p = new Process()) { ProcessStartInfo info = new ProcessStartInfo { FileName = vswhereExe, Arguments = @"-find Common7\IDE\Extensions\*\Google.VisualStudio.Android.dll", RedirectStandardOutput = true, UseShellExecute = false }; p.StartInfo = info; p.Start(); AGDEInstalled = p.StandardOutput.ReadToEnd().Contains("Google.VisualStudio.Android.dll"); } } } } catch (Exception ex) { Logger.LogInformation("Failed to identify AGDE installation status: {Message}", ex.Message); } } } } /// /// Enumerate all the platforms that this generator supports /// public override IEnumerable GetPlatforms() { yield return UnrealTargetPlatform.Android; } /// public override bool HasVisualStudioSupport(VSSettings InVSSettings) { // Debugging, etc. are dependent on the TADP being installed return AGDEInstalled; } /// public override string GetVisualStudioPlatformName(VSSettings InVSSettings) { string PlatformName = InVSSettings.Platform.ToString(); if (InVSSettings.Platform == UnrealTargetPlatform.Android && AGDEInstalled) { PlatformName = "Android-arm64-v8a"; } return PlatformName; } /// public override void GetAdditionalVisualStudioPropertyGroups(VSSettings InVSSettings, StringBuilder ProjectFileBuilder) { if (AGDEInstalled) { base.GetAdditionalVisualStudioPropertyGroups(InVSSettings, ProjectFileBuilder); } } /// public override void GetVisualStudioPathsEntries(VSSettings InVSSettings, TargetType TargetType, FileReference TargetRulesPath, FileReference ProjectFilePath, FileReference NMakeOutputPath, StringBuilder ProjectFileBuilder) { if (AGDEInstalled) { string apkLocation = Path.Combine( Path.GetDirectoryName(NMakeOutputPath.FullName)!, Path.GetFileNameWithoutExtension(NMakeOutputPath.FullName) + "-arm64.apk"); ProjectFileBuilder.AppendLine($" {apkLocation}"); string intermediatePath = Path.GetFullPath(Path.GetDirectoryName(NMakeOutputPath.FullName) + @"\..\..\Intermediate\Android\arm64\"); string symbolLocations = $@"{intermediatePath}jni\arm64-v8a;{intermediatePath}libs\arm64-v8a"; ProjectFileBuilder.AppendLine($" {symbolLocations}"); } else { base.GetVisualStudioPathsEntries(InVSSettings, TargetType, TargetRulesPath, ProjectFilePath, NMakeOutputPath, ProjectFileBuilder); } } public override string GetExtraBuildArguments(VSSettings InVSSettings) { // do not need to check InPlatform since it will always be UnrealTargetPlatform.Android return (AGDEInstalled ? " -Architectures=arm64 -ForceAPKGeneration" : "") + base.GetExtraBuildArguments(InVSSettings); } public override string GetVisualStudioUserFileStrings(VSSettings InVSSettings, string InConditionString, TargetRules InTargetRules, FileReference TargetRulesPath, FileReference ProjectFilePath) { if (AGDEInstalled && (InVSSettings.Platform == UnrealTargetPlatform.Android) && ((InTargetRules.Type == TargetRules.TargetType.Client) || (InTargetRules.Type == TargetRules.TargetType.Game))) { string UserFileEntry = "\n"; UserFileEntry += " " + "command script import \"" + Path.Combine(Unreal.EngineDirectory.FullName, "Extras", "LLDBDataFormatters", "UEDataFormatters_2ByteChars.py") + "\";" + "$(AndroidLldbStartupCommands)" + "\n"; UserFileEntry += "\n"; return UserFileEntry; } return base.GetVisualStudioUserFileStrings(InVSSettings, InConditionString, InTargetRules, TargetRulesPath, ProjectFilePath); } } }