private NPath PackageApp(NPath buildPath, NPath mainLibPath) { var deployedPath = buildPath.Combine(m_gameName + ".apk"); if (m_apkToolchain == null) { Console.WriteLine($"Error: not Android APK toolchain"); return(deployedPath); } var gradleProjectPath = mainLibPath.Parent.Parent.Parent.Parent.Parent; var pathToRoot = new NPath(string.Concat(Enumerable.Repeat("../", gradleProjectPath.Depth))); var apkSrcPath = AsmDefConfigFile.AsmDefDescriptionFor("Unity.Platforms.Android").Path.Parent.Combine("AndroidProjectTemplate~/"); var javaLaunchPath = m_apkToolchain.JavaPath.Combine("bin").Combine("java"); var gradleLaunchPath = m_apkToolchain.GetGradleLaunchJarPath(); var releaseApk = m_codeGen == CodeGen.Release; var gradleCommand = releaseApk ? "assembleRelease" : "assembleDebug"; var deleteCommand = Unity.BuildTools.HostPlatform.IsWindows ? $"del /f /q {deployedPath.InQuotes(SlashMode.Native)} 2> nul" : $"rm -f {deployedPath.InQuotes(SlashMode.Native)}"; var gradleExecutableString = $"{deleteCommand} && cd {gradleProjectPath.InQuotes()} && {javaLaunchPath.InQuotes()} -classpath {gradleLaunchPath.InQuotes()} org.gradle.launcher.GradleMain {gradleCommand} && cd {pathToRoot.InQuotes()}"; var apkPath = gradleProjectPath.Combine("build/outputs/apk").Combine(releaseApk ? "release/gradle-release.apk" : "debug/gradle-debug.apk"); Backend.Current.AddAction( actionName: "Build Gradle project", targetFiles: new[] { apkPath }, inputs: m_apkToolchain.RequiredArtifacts.Append(mainLibPath).Concat(m_supportFiles.Select(d => d.Path)).ToArray(), executableStringFor: gradleExecutableString, commandLineArguments: Array.Empty <string>(), allowUnexpectedOutput: false, allowedOutputSubstrings: new[] { ":*", "BUILD SUCCESSFUL in *" } ); var templateStrings = new Dictionary <string, string> { { "**TINYNAME**", m_gameName.Replace("-", "").ToLower() }, { "**GAMENAME**", m_gameName }, }; // copy and patch project files foreach (var r in apkSrcPath.Files(true)) { var destPath = gradleProjectPath.Combine(r.RelativeTo(apkSrcPath)); if (r.Extension == "template") { destPath = destPath.ChangeExtension(""); var code = r.ReadAllText(); foreach (var t in templateStrings) { if (code.IndexOf(t.Key) != -1) { code = code.Replace(t.Key, t.Value); } } Backend.Current.AddWriteTextAction(destPath, code); } else { destPath = CopyTool.Instance().Setup(destPath, r); } Backend.Current.AddDependency(apkPath, destPath); } var localProperties = new StringBuilder(); localProperties.AppendLine($"sdk.dir={m_apkToolchain.SdkPath}"); localProperties.AppendLine($"ndk.dir={m_apkToolchain.Sdk.Path.MakeAbsolute()}"); var localPropertiesPath = gradleProjectPath.Combine("local.properties"); Backend.Current.AddWriteTextAction(localPropertiesPath, localProperties.ToString()); Backend.Current.AddDependency(apkPath, localPropertiesPath); // copy additional resources and Data files // TODO: better to use move from main lib directory foreach (var r in m_supportFiles) { var targetAssetPath = gradleProjectPath.Combine("src/main/assets"); if (r.Path.FileName == "testconfig.json") { targetAssetPath = buildPath.Combine(r.Path.FileName); } else if (r is DeployableFile && (r as DeployableFile).RelativeDeployPath != null) { targetAssetPath = targetAssetPath.Combine((r as DeployableFile).RelativeDeployPath); } else { targetAssetPath = targetAssetPath.Combine(r.Path.FileName); } Backend.Current.AddDependency(apkPath, CopyTool.Instance().Setup(targetAssetPath, r.Path)); } return(CopyTool.Instance().Setup(deployedPath, apkPath)); }
private NPath PackageApp(NPath buildPath, BuiltNativeProgram mainProgram) { var mainLibPath = mainProgram.Path; m_projectFiles.Add(mainLibPath); m_projectFiles.AddRange(mainProgram.Deployables.Select(d => d.Path)); if (m_apkToolchain == null) { Console.WriteLine($"Error: not Android APK toolchain"); return(buildPath); } if (AndroidApkToolchain.ExportProject) { var deployedPath = buildPath.Combine(m_gameName); GenerateGradleProject(deployedPath); // stub action to have deployedPath in build tree and set correct dependencies Backend.Current.AddAction( actionName: "Gradle project folder", targetFiles: new[] { deployedPath }, inputs: m_projectFiles.ToArray(), executableStringFor: $"echo created", commandLineArguments: Array.Empty <string>(), allowUnexpectedOutput: true, allowUnwrittenOutputFiles: true ); return(deployedPath); } else { var deployedPath = buildPath.Combine(m_gameName + "." + m_apkToolchain.ExecutableFormat.Extension); var gradleProjectPath = mainLibPath.Parent.Parent.Parent.Parent.Parent; GenerateGradleProject(gradleProjectPath); var pathToRoot = new NPath(string.Concat(Enumerable.Repeat("../", gradleProjectPath.Depth))); var javaLaunchPath = new NPath(AndroidApkToolchain.Config.ExternalTools.JavaPath).Combine("bin").Combine("java"); var gradleLaunchPath = AndroidApkToolchain.GetGradleLaunchJarPath(); var releaseBuild = m_config == DotsConfiguration.Release; var gradleCommand = AndroidApkToolchain.BuildAppBundle ? (releaseBuild ? "bundleRelease" : "bundleDebug") : (releaseBuild ? "assembleRelease" : "assembleDebug"); var gradleExecutableString = $"cd {gradleProjectPath.InQuotes()} && {javaLaunchPath.InQuotes()} -classpath {gradleLaunchPath.InQuotes()} org.gradle.launcher.GradleMain {gradleCommand} && cd {pathToRoot.InQuotes()}"; var config = releaseBuild ? "release" : "debug"; var gradleBuildPath = gradleProjectPath.Combine("build/outputs"). Combine(AndroidApkToolchain.BuildAppBundle ? "bundle" : "apk"). Combine($"{config}/gradle-{config}.{(AndroidApkToolchain.BuildAppBundle ? "aab" : "apk")}"); Backend.Current.AddAction( actionName: "Build Gradle project", targetFiles: new[] { gradleBuildPath }, inputs: m_projectFiles.ToArray(), executableStringFor: gradleExecutableString, commandLineArguments: Array.Empty <string>(), allowUnexpectedOutput: false, allowedOutputSubstrings: new[] { ":*", "BUILD SUCCESSFUL in *" } ); return(CopyTool.Instance().Setup(deployedPath, gradleBuildPath)); } }