public override bool Execute() { var sdk = new AndroidSdkInfo(this.CreateTaskLogger(), AndroidSdkPath, AndroidNdkPath, JavaSdkPath); AndroidSdkPath = sdk.AndroidSdkPath; AndroidNdkPath = sdk.AndroidNdkPath; JavaSdkPath = sdk.JavaSdkPath; foreach (var dir in sdk.GetBuildToolsPaths()) { var zipAlign = Path.Combine(dir, ZipAlign); if (File.Exists(zipAlign)) { ZipAlignPath = dir; } var apkSigner = Path.Combine(dir, "lib", ApkSigner); if (File.Exists(apkSigner)) { ApkSignerJar = apkSigner; } AndroidSdkBuildToolsPath = dir; break; } return(!Log.HasLoggedErrors); }
public void JdkDirectory_JavaHome([Values("JI_JAVA_HOME", "JAVA_HOME")] string envVar) { if (envVar.Equals("JAVA_HOME", StringComparison.OrdinalIgnoreCase)) { Assert.Ignore("This test will only work locally if you rename/remove your Open JDK directory."); return; } CreateSdks(out string root, out string jdk, out string ndk, out string sdk); JdkInfoTests.CreateFauxJdk(jdk, releaseVersion: "1.8.999", releaseBuildNumber: "9", javaVersion: "1.8.999-9"); var logs = new StringWriter(); Action <TraceLevel, string> logger = (level, message) => { logs.WriteLine($"[{level}] {message}"); }; string java_home = null; try { // We only set via JAVA_HOME java_home = Environment.GetEnvironmentVariable(envVar, EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable(envVar, jdk, EnvironmentVariableTarget.Process); var info = new AndroidSdkInfo(logger, androidSdkPath: sdk, androidNdkPath: ndk, javaSdkPath: ""); Assert.AreEqual(ndk, info.AndroidNdkPath, "AndroidNdkPath not preserved!"); Assert.AreEqual(sdk, info.AndroidSdkPath, "AndroidSdkPath not preserved!"); Assert.AreEqual(jdk, info.JavaSdkPath, "JavaSdkPath not preserved!"); } finally { Environment.SetEnvironmentVariable(envVar, java_home, EnvironmentVariableTarget.Process); Directory.Delete(root, recursive: true); } }
public void Ndk_PathInSdk() { CreateSdks(out string root, out string jdk, out string ndk, out string sdk); Action <TraceLevel, string> logger = (level, message) => { Console.WriteLine($"[{level}] {message}"); }; try { var extension = OS.IsWindows ? ".cmd" : ""; var ndkPath = Path.Combine(sdk, "ndk-bundle"); Directory.CreateDirectory(ndkPath); File.WriteAllText(Path.Combine(ndkPath, "source.properties"), $"Pkg.Revision = {NdkVersion}"); Directory.CreateDirectory(Path.Combine(ndkPath, "toolchains")); File.WriteAllText(Path.Combine(ndkPath, $"ndk-stack{extension}"), ""); var info = new AndroidSdkInfo(logger, androidSdkPath: sdk, androidNdkPath: null, javaSdkPath: jdk); Assert.AreEqual(ndkPath, info.AndroidNdkPath, "AndroidNdkPath not found inside sdk!"); } finally { Directory.Delete(root, recursive: true); } }
public void JdkDirectory_JavaHome() { CreateSdks(out string root, out string jdk, out string ndk, out string sdk); JdkInfoTests.CreateFauxJdk(jdk, releaseVersion: "1.8.999", releaseBuildNumber: "9", javaVersion: "1.8.999-9"); var logs = new StringWriter(); Action <TraceLevel, string> logger = (level, message) => { logs.WriteLine($"[{level}] {message}"); }; string java_home = null; try { // We only set via JAVA_HOME java_home = Environment.GetEnvironmentVariable("JAVA_HOME", EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable("JAVA_HOME", jdk); var info = new AndroidSdkInfo(logger, androidSdkPath: sdk, androidNdkPath: ndk, javaSdkPath: ""); Assert.AreEqual(ndk, info.AndroidNdkPath, "AndroidNdkPath not preserved!"); Assert.AreEqual(sdk, info.AndroidSdkPath, "AndroidSdkPath not preserved!"); Assert.AreEqual(jdk, info.JavaSdkPath, "JavaSdkPath not preserved!"); } finally { if (java_home != null) { Environment.SetEnvironmentVariable("JAVA_HOME", java_home, EnvironmentVariableTarget.Process); } Directory.Delete(root, recursive: true); } }
public void DetectAndSetPreferredJavaSdkPathToLatest() { Action <TraceLevel, string> logger = (level, message) => { Console.WriteLine($"[{level}] {message}"); }; var backupConfig = UnixConfigPath + "." + Path.GetRandomFileName(); try { if (OS.IsWindows) { Assert.Throws <NotImplementedException>(() => AndroidSdkInfo.DetectAndSetPreferredJavaSdkPathToLatest(logger)); return; } Assert.Throws <NotSupportedException>(() => AndroidSdkInfo.DetectAndSetPreferredJavaSdkPathToLatest(logger)); var newJdkPath = Path.Combine(PreferredJdksOverridePath, "microsoft_dist_openjdk_1.8.999.9"); JdkInfoTests.CreateFauxJdk(newJdkPath, releaseVersion: "1.8.999", releaseBuildNumber: "9", javaVersion: "1.8.999-9"); if (File.Exists(UnixConfigPath)) { File.Move(UnixConfigPath, backupConfig); } AndroidSdkInfo.DetectAndSetPreferredJavaSdkPathToLatest(logger); AssertJdkPath(newJdkPath); } finally { if (File.Exists(backupConfig)) { File.Delete(UnixConfigPath); File.Move(backupConfig, UnixConfigPath); } } }
public void Ndk_PathInSdk() { if (!OS.IsWindows) { Assert.Ignore("This only works in Windows"); } CreateSdks(out string root, out string jdk, out string ndk, out string sdk); var logs = new StringWriter(); Action <TraceLevel, string> logger = (level, message) => { logs.WriteLine($"[{level}] {message}"); }; try { var ndkPath = Path.Combine(sdk, "ndk-bundle"); Directory.CreateDirectory(ndkPath); Directory.CreateDirectory(Path.Combine(ndkPath, "toolchains")); File.WriteAllText(Path.Combine(ndkPath, "ndk-stack.cmd"), ""); var info = new AndroidSdkInfo(logger, androidSdkPath: sdk, androidNdkPath: null, javaSdkPath: jdk); Assert.AreEqual(ndkPath, info.AndroidNdkPath, "AndroidNdkPath not found inside sdk!"); } finally { Directory.Delete(root, recursive: true); } }
public override Task <DiagnosticResult> Examine(SharedState history) { var xamJdks = new List <OpenJdkInfo>(); try { var xamSdkInfo = new AndroidSdkInfo((traceLevel, msg) => Util.Log(msg), null, null, null); if (!string.IsNullOrEmpty(xamSdkInfo.JavaSdkPath)) { SearchDirectoryForJdks(xamJdks, xamSdkInfo.JavaSdkPath); } } catch (Exception ex) { Util.Exception(ex); } var jdks = xamJdks.Concat(FindJdks()) .GroupBy(j => j.Directory.FullName) .Select(g => g.First()); var ok = false; foreach (var jdk in jdks) { if ((jdk.JavaC.FullName.Contains("microsoft", StringComparison.OrdinalIgnoreCase) || jdk.JavaC.FullName.Contains("openjdk", StringComparison.OrdinalIgnoreCase)) && jdk.Version.IsCompatible(Version, RequireExact ? Version : null)) { ok = true; ReportStatus($"{jdk.Version} ({jdk.Directory})", Status.Ok); history.SetEnvironmentVariable("JAVA_HOME", jdk.Directory.FullName); // Try and set the global env var on windows if it's not set if (Util.IsWindows && string.IsNullOrEmpty(Environment.GetEnvironmentVariable("JAVA_HOME"))) { try { Environment.SetEnvironmentVariable("JAVA_HOME", jdk.Directory.FullName, EnvironmentVariableTarget.Machine); ReportStatus($"Set Environment Variable: JAVA_HOME={jdk.Directory.FullName}", Status.Ok); } catch { } } } else { ReportStatus($"{jdk.Version} ({jdk.Directory.FullName})", null); } } if (ok) { return(Task.FromResult(DiagnosticResult.Ok(this))); } return(Task.FromResult(new DiagnosticResult(Status.Error, this, new Suggestion("Install OpenJDK11", new BootsSolution(Manifest?.Check?.OpenJdk?.Url, "Download and Install Microsoft OpenJDK 11"))))); }
public override Task <DiagnosticResult> Examine(SharedState history) { var xamJdks = new List <OpenJdkInfo>(); try { var xamSdkInfo = new AndroidSdkInfo((traceLevel, msg) => Util.Log(msg), null, null, null); if (!string.IsNullOrEmpty(xamSdkInfo.JavaSdkPath)) { SearchDirectoryForJdks(xamJdks, xamSdkInfo.JavaSdkPath); } } catch (Exception ex) { Util.Exception(ex); } var jdks = xamJdks.Concat(FindJdks()); var ok = false; foreach (var jdk in jdks) { if ((jdk.JavaC.FullName.Contains("microsoft") || jdk.JavaC.FullName.Contains("openjdk")) && jdk.Version.IsCompatible(MinimumVersion, ExactVersion)) { ok = true; ReportStatus($"{jdk.Version} ({jdk.Directory})", Status.Ok); history.SetEnvironmentVariable("JAVA_HOME", jdk.Directory.FullName); // Try and set the global env var on windows if it's not set if (Util.IsWindows && string.IsNullOrEmpty(Environment.GetEnvironmentVariable("JAVA_HOME"))) { try { Environment.SetEnvironmentVariable("JAVA_HOME", jdk.Directory.FullName, EnvironmentVariableTarget.Machine); ReportStatus($"Set Environemnt Variable: JAVA_HOME={jdk.Directory.FullName}", Status.Ok); } catch { } } } else { ReportStatus($"{jdk.Version} ({jdk.Directory})", null); } } if (ok) { return(Task.FromResult(DiagnosticResult.Ok(this))); } return(Task.FromResult(new DiagnosticResult(Status.Error, this))); }
public void Sdk_GetCommandLineToolsPaths() { CreateSdks(out string root, out string jdk, out string ndk, out string sdk); var cmdlineTools = Path.Combine(sdk, "cmdline-tools"); var latestToolsVersion = "latest"; var toolsVersion = "2.1"; var higherToolsVersion = "11.2"; void recreateCmdlineToolsDirectory() { Directory.Delete(cmdlineTools, recursive: true); Directory.CreateDirectory(cmdlineTools); } try { var info = new AndroidSdkInfo(androidSdkPath: sdk); // Test cmdline-tools path recreateCmdlineToolsDirectory(); CreateFauxAndroidSdkToolsDirectory(sdk, createToolsDir: true, toolsVersion: toolsVersion, createOldToolsDir: false); var toolsPaths = info.GetCommandLineToolsPaths(); Assert.AreEqual(toolsPaths.Count(), 1, "Incorrect number of elements"); Assert.AreEqual(toolsPaths.First(), Path.Combine(sdk, "cmdline-tools", toolsVersion), "Incorrect command line tools path"); // Test that cmdline-tools is preferred over tools recreateCmdlineToolsDirectory(); CreateFauxAndroidSdkToolsDirectory(sdk, createToolsDir: true, toolsVersion: latestToolsVersion, createOldToolsDir: true); toolsPaths = info.GetCommandLineToolsPaths(); Assert.AreEqual(toolsPaths.Count(), 2, "Incorrect number of elements"); Assert.AreEqual(toolsPaths.First(), Path.Combine(sdk, "cmdline-tools", latestToolsVersion), "Incorrect command line tools path"); Assert.AreEqual(toolsPaths.Last(), Path.Combine(sdk, "tools"), "Incorrect tools path"); // Test sorting recreateCmdlineToolsDirectory(); CreateFauxAndroidSdkToolsDirectory(sdk, createToolsDir: true, toolsVersion: latestToolsVersion, createOldToolsDir: false); CreateFauxAndroidSdkToolsDirectory(sdk, createToolsDir: true, toolsVersion: toolsVersion, createOldToolsDir: false); CreateFauxAndroidSdkToolsDirectory(sdk, createToolsDir: true, toolsVersion: higherToolsVersion, createOldToolsDir: true); toolsPaths = info.GetCommandLineToolsPaths(); var toolsPathsList = toolsPaths.ToList(); Assert.AreEqual(toolsPaths.Count(), 4, "Incorrect number of elements"); bool isOrderCorrect = toolsPathsList [0].Equals(Path.Combine(sdk, "cmdline-tools", latestToolsVersion), StringComparison.Ordinal) && toolsPathsList [1].Equals(Path.Combine(sdk, "cmdline-tools", higherToolsVersion), StringComparison.Ordinal) && toolsPathsList [2].Equals(Path.Combine(sdk, "cmdline-tools", toolsVersion), StringComparison.Ordinal) && toolsPathsList [3].Equals(Path.Combine(sdk, "tools"), StringComparison.Ordinal); Assert.IsTrue(isOrderCorrect, "Tools order is not descending"); } finally { Directory.Delete(root, recursive: true); } }
public void Ndk_MultipleNdkVersionsInSdk() { // Must match like-named constants in AndroidSdkBase const int MinimumCompatibleNDKMajorVersion = 16; const int MaximumCompatibleNDKMajorVersion = 21; CreateSdks(out string root, out string jdk, out string ndk, out string sdk); Action <TraceLevel, string> logger = (level, message) => { Console.WriteLine($"[{level}] {message}"); }; var ndkVersions = new List <string> { "16.1.4479499", "17.2.4988734", "18.1.5063045", "19.2.5345600", "20.0.5594570", "20.1.5948944", "21.0.6113669", "21.1.6352462", "21.2.6472646", "21.3.6528147", "22.0.7026061", }; string expectedVersion = "21.3.6528147"; string expectedNdkPath = Path.Combine(sdk, "ndk", expectedVersion); try { MakeNdkDir(Path.Combine(sdk, "ndk-bundle"), NdkVersion); foreach (string ndkVer in ndkVersions) { MakeNdkDir(Path.Combine(sdk, "ndk", ndkVer), ndkVer); } var info = new AndroidSdkInfo(logger, androidSdkPath: sdk, androidNdkPath: null, javaSdkPath: jdk); Assert.AreEqual(expectedNdkPath, info.AndroidNdkPath, "AndroidNdkPath not found inside sdk!"); string ndkVersion = Path.GetFileName(info.AndroidNdkPath); if (!Version.TryParse(ndkVersion, out Version ver)) { Assert.Fail($"Unable to parse '{ndkVersion}' as a valid version."); } Assert.True(ver.Major >= MinimumCompatibleNDKMajorVersion, $"NDK version must be at least {MinimumCompatibleNDKMajorVersion}"); Assert.True(ver.Major <= MaximumCompatibleNDKMajorVersion, $"NDK version must be at most {MinimumCompatibleNDKMajorVersion}"); } finally { Directory.Delete(root, recursive: true); } }
public void Setup() { engine = new MockBuildEngine(TestContext.Out, errors = new List <BuildErrorEventArgs> (), warnings = new List <BuildWarningEventArgs> (), messages = new List <BuildMessageEventArgs> ()); temp = Path.GetTempFileName(); var androidSdk = new AndroidSdkInfo((level, message) => { if (level == TraceLevel.Error) { Assert.Fail(message); } }, AndroidSdkPath, AndroidNdkPath); keyToolPath = Path.Combine(androidSdk.JavaSdkPath, "bin"); }
/// <summary> /// Runs the dexdump command to see if a class exists in a dex file /// dexdump returns data of the form: /// Class descriptor : 'Landroid/app/ActivityTracker;' /// </summary> /// <param name="className">A Java class name of the form 'Landroid/app/ActivityTracker;'</param> public static bool ContainsClass(string className, string dexFile, string androidSdkDirectory) { bool containsClass = false; DataReceivedEventHandler handler = (s, e) => { if (e.Data != null && e.Data.Contains("Class descriptor") && e.Data.Contains(className)) { containsClass = true; } }; var androidSdk = new AndroidSdkInfo((l, m) => { Console.WriteLine($"{l}: {m}"); if (l == TraceLevel.Error) { throw new Exception(m); } }, androidSdkDirectory); var buildToolsPath = androidSdk.GetBuildToolsPaths().FirstOrDefault(); if (string.IsNullOrEmpty(buildToolsPath)) { throw new Exception($"Unable to find build-tools in `{androidSdkDirectory}`!"); } var psi = new ProcessStartInfo { FileName = Path.Combine(buildToolsPath, "dexdump"), Arguments = $"\"{dexFile}\"", CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = false, RedirectStandardError = true, RedirectStandardOutput = true, }; var builder = new StringBuilder(); using (var p = new Process { StartInfo = psi }) { p.ErrorDataReceived += handler; p.OutputDataReceived += handler; p.Start(); p.BeginErrorReadLine(); p.BeginOutputReadLine(); p.WaitForExit(); } return(containsClass); }
public void Constructor_SetValuesFromPath() { if (OS.IsWindows) { Assert.Ignore("Windows does not look for values in %PATH%"); } CreateSdks(out string root, out string jdk, out string ndk, out string sdk); JdkInfoTests.CreateFauxJdk(jdk, releaseVersion: "1.8.0", releaseBuildNumber: "42", javaVersion: "100.100.100_100"); Action <TraceLevel, string> logger = (level, message) => { Console.WriteLine($"[{level}] {message}"); }; var oldPath = Environment.GetEnvironmentVariable("PATH"); var oldJavaHome = Environment.GetEnvironmentVariable("JAVA_HOME"); try { var paths = new List <string> () { Path.Combine(jdk, "bin"), ndk, Path.Combine(sdk, "platform-tools"), }; paths.AddRange(oldPath.Split(new[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries)); Environment.SetEnvironmentVariable("PATH", string.Join(Path.PathSeparator.ToString(), paths)); if (!string.IsNullOrEmpty(oldJavaHome)) { Environment.SetEnvironmentVariable("JAVA_HOME", string.Empty); } var info = new AndroidSdkInfo(logger); Assert.AreEqual(ndk, info.AndroidNdkPath, "AndroidNdkPath not set from $PATH!"); Assert.AreEqual(sdk, info.AndroidSdkPath, "AndroidSdkPath not set from $PATH!"); Assert.AreEqual(jdk, info.JavaSdkPath, "JavaSdkPath not set from $PATH!"); } finally { Environment.SetEnvironmentVariable("PATH", oldPath); if (!string.IsNullOrEmpty(oldJavaHome)) { Environment.SetEnvironmentVariable("JAVA_HOME", oldJavaHome); } Directory.Delete(root, recursive: true); } }
static void DexDump(DataReceivedEventHandler handler, string dexFile, string androidSdkDirectory) { var androidSdk = new AndroidSdkInfo((l, m) => { Console.WriteLine($"{l}: {m}"); if (l == TraceLevel.Error) { throw new Exception(m); } }, androidSdkDirectory); var buildToolsPath = androidSdk.GetBuildToolsPaths().FirstOrDefault(); if (string.IsNullOrEmpty(buildToolsPath)) { throw new Exception($"Unable to find build-tools in `{androidSdkDirectory}`!"); } var psi = new ProcessStartInfo { FileName = Path.Combine(buildToolsPath, "dexdump"), Arguments = Path.GetFileName(dexFile), CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = false, RedirectStandardError = true, RedirectStandardOutput = true, WorkingDirectory = Path.GetDirectoryName(dexFile), }; using (var p = new Process { StartInfo = psi }) { p.ErrorDataReceived += handler; p.OutputDataReceived += handler; p.Start(); p.BeginErrorReadLine(); p.BeginOutputReadLine(); p.WaitForExit(); if (p.ExitCode != 0) { throw new Exception($"'{psi.FileName} {psi.Arguments}' exited with code: {p.ExitCode}"); } } }
public static void RefreshAndroidSdk(string sdkPath, string ndkPath, string javaPath) { Action <TraceLevel, string> logger = (level, value) => { var log = androidSdkLogger; switch (level) { case TraceLevel.Error: if (log == null) { Console.Error.Write(value); } else { log.LogError("{0}", value); } break; case TraceLevel.Warning: if (log == null) { Console.WriteLine(value); } else { log.LogWarning("{0}", value); } break; default: if (log == null) { Console.WriteLine(value); } else { log.LogDebugMessage("{0}", value); } break; } }; AndroidSdk = new AndroidSdkInfo(logger, sdkPath, ndkPath, javaPath); }
public JarContentBuilder() { Action <TraceLevel, string> logger = (level, value) => { switch (level) { case TraceLevel.Error: throw new Exception($"AndroidSdkInfo {level}: {value}"); default: Console.WriteLine($"AndroidSdkInfo {level}: {value}"); break; } }; var androidSdk = new AndroidSdkInfo(logger); JavacFullPath = Path.Combine(androidSdk.JavaSdkPath, "bin", "javac"); JarFullPath = Path.Combine(androidSdk.JavaSdkPath, "bin", "jar"); }
public void Constructor_Paths() { CreateSdks(out string root, out string jdk, out string ndk, out string sdk); var logs = new StringWriter(); Action <TraceLevel, string> logger = (level, message) => { logs.WriteLine($"[{level}] {message}"); }; try { var info = new AndroidSdkInfo(logger, androidSdkPath: sdk, androidNdkPath: ndk, javaSdkPath: jdk); Assert.AreEqual(ndk, info.AndroidNdkPath, "AndroidNdkPath not preserved!"); Assert.AreEqual(sdk, info.AndroidSdkPath, "AndroidSdkPath not preserved!"); Assert.AreEqual(jdk, info.JavaSdkPath, "JavaSdkPath not preserved!"); } finally { Directory.Delete(root, recursive: true); } }
public JarContentBuilder() { Action <TraceLevel, string> logger = (level, value) => { switch (level) { case TraceLevel.Error: throw new Exception($"AndroidSdkInfo {level}: {value}"); default: Console.WriteLine($"AndroidSdkInfo {level}: {value}"); break; } }; var homeDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal); var androidSdkToolPath = Path.Combine(homeDirectory, "android-toolchain"); var sdkPath = Environment.GetEnvironmentVariable("ANDROID_SDK_PATH"); if (String.IsNullOrEmpty(sdkPath)) { sdkPath = GetPathFromRegistry("AndroidSdkDirectory"); } if (String.IsNullOrEmpty(sdkPath)) { sdkPath = Path.GetFullPath(Path.Combine(androidSdkToolPath, "sdk")); } var ndkPath = Environment.GetEnvironmentVariable("ANDROID_NDK_PATH"); if (String.IsNullOrEmpty(ndkPath)) { ndkPath = GetPathFromRegistry("AndroidNdkDirectory"); } if (String.IsNullOrEmpty(ndkPath)) { ndkPath = Path.GetFullPath(Path.Combine(androidSdkToolPath, "ndk")); } var androidSdk = new AndroidSdkInfo(logger, androidSdkPath: sdkPath, androidNdkPath: ndkPath); JavacFullPath = Path.Combine(androidSdk.JavaSdkPath, "bin", "javac"); JarFullPath = Path.Combine(androidSdk.JavaSdkPath, "bin", "jar"); }
public void GetBuildToolsPaths_StableVersionsFirst() { CreateSdks(out string root, out string jdk, out string ndk, out string sdk); CreateFauxAndroidSdkDirectory(sdk, "27.0.0-rc4"); var logs = new StringWriter(); Action <TraceLevel, string> logger = (level, message) => { logs.WriteLine($"[{level}] {message}"); }; try { var info = new AndroidSdkInfo(logger, androidSdkPath: sdk, androidNdkPath: ndk, javaSdkPath: jdk); var buildToolsPaths = info.GetBuildToolsPaths().ToList(); Assert.AreEqual(3, buildToolsPaths.Count); Assert.AreEqual(Path.Combine(sdk, "build-tools", "26.0.0"), buildToolsPaths [0]); Assert.AreEqual(Path.Combine(sdk, "build-tools", "27.0.0-rc4"), buildToolsPaths [1]); Assert.AreEqual(Path.Combine(sdk, "platform-tools"), buildToolsPaths [2]); } finally { Directory.Delete(root, recursive: true); } }
public void CheckSignApk([Values(true, false)] bool useApkSigner, [Values(true, false)] bool perAbiApk) { string ext = Environment.OSVersion.Platform != PlatformID.Unix ? ".bat" : ""; var foundApkSigner = Directory.EnumerateDirectories(Path.Combine(AndroidSdkPath, "build-tools")).Any(dir => Directory.EnumerateFiles(dir, "apksigner" + ext).Any()); if (useApkSigner && !foundApkSigner) { Assert.Ignore("Skipping test. Required build-tools verison which contains apksigner is not installed."); } string keyfile = Path.Combine(Root, "temp", TestName, "release.keystore"); if (File.Exists(keyfile)) { File.Delete(keyfile); } var androidSdk = new AndroidSdkInfo((level, message) => { }, AndroidSdkPath, AndroidNdkPath); string keyToolPath = Path.Combine(androidSdk.JavaSdkPath, "bin"); var engine = new MockBuildEngine(Console.Out); string pass = "******"; var task = new AndroidCreateDebugKey { BuildEngine = engine, KeyStore = keyfile, StorePass = pass, KeyAlias = "releasestore", KeyPass = pass, KeyAlgorithm = "RSA", Validity = 30, StoreType = "pkcs12", Command = "-genkeypair", ToolPath = keyToolPath, }; Assert.IsTrue(task.Execute(), "Task should have succeeded."); var proj = new XamarinAndroidApplicationProject() { IsRelease = true, }; if (useApkSigner) { proj.SetProperty("AndroidUseApkSigner", "true"); } else { proj.RemoveProperty("AndroidUseApkSigner"); } proj.SetProperty(proj.ReleaseProperties, "AndroidKeyStore", "True"); proj.SetProperty(proj.ReleaseProperties, "AndroidSigningKeyStore", keyfile); proj.SetProperty(proj.ReleaseProperties, "AndroidSigningKeyAlias", "releasestore"); proj.SetProperty(proj.ReleaseProperties, "AndroidSigningKeyPass", pass); proj.SetProperty(proj.ReleaseProperties, "AndroidSigningStorePass", pass); proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidCreatePackagePerAbi, perAbiApk); proj.SetAndroidSupportedAbis("armeabi-v7a", "x86"); using (var b = CreateApkBuilder(Path.Combine("temp", TestContext.CurrentContext.Test.Name))) { var bin = Path.Combine(Root, b.ProjectDirectory, proj.OutputPath); Assert.IsTrue(b.Build(proj), "First build failed"); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, " 0 Warning(s)"), "First build should not contain warnings! Contains\n" + string.Join("\n", b.LastBuildOutput.Where(line => line.Contains("warning")))); //Make sure the APKs are signed foreach (var apk in Directory.GetFiles(bin, "*-Signed.apk")) { using (var zip = ZipHelper.OpenZip(apk)) { Assert.IsTrue(zip.Any(e => e.FullName == "META-INF/MANIFEST.MF"), $"APK file `{apk}` is not signed! It is missing `META-INF/MANIFEST.MF`."); } } var item = proj.AndroidResources.First(x => x.Include() == "Resources\\values\\Strings.xml"); item.TextContent = () => proj.StringsXml.Replace("${PROJECT_NAME}", "Foo"); item.Timestamp = null; Assert.IsTrue(b.Build(proj), "Second build failed"); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, " 0 Warning(s)"), "Second build should not contain warnings! Contains\n" + string.Join("\n", b.LastBuildOutput.Where(line => line.Contains("warning")))); //Make sure the APKs are signed foreach (var apk in Directory.GetFiles(bin, "*-Signed.apk")) { using (var zip = ZipHelper.OpenZip(apk)) { Assert.IsTrue(zip.Any(e => e.FullName == "META-INF/MANIFEST.MF"), $"APK file `{apk}` is not signed! It is missing `META-INF/MANIFEST.MF`."); } } } }
public override bool Execute() { var logger = CreateTaskLogger(this); var androidSdk = new AndroidSdkInfo(logger, AndroidSdkPath, AndroidNdkPath, JavaSdkPath); try { Log.LogMessage(MessageImportance.Low, $" {nameof (androidSdk.JavaSdkPath)}: {androidSdk.JavaSdkPath}"); Version maxVersion; if (string.IsNullOrEmpty(MaxJdkVersion)) { maxVersion = new Version("8.0"); } else { maxVersion = new Version(MaxJdkVersion); } var defaultJdk = new [] { new Tools.JdkInfo(androidSdk.JavaSdkPath) }; var jdk = defaultJdk.Concat(Tools.JdkInfo.GetKnownSystemJdkInfos(logger)) .Where(j => maxVersion != null ? j.Version <= maxVersion : true) .Where(j => j.IncludePath.Any()) .FirstOrDefault(); if (jdk == null) { Log.LogError($"Could not determine a valid JavaSdkPath, `{androidSdk.JavaSdkPath}` was not compatible with the Xamarin.Android build."); return(false); } else { Log.LogMessage(MessageImportance.Low, $" {nameof (jdk.HomePath)}: {jdk.HomePath}"); } var includes = new List <string> (jdk.IncludePath); var includeXmlTags = new StringBuilder(); foreach (var include in includes) { includeXmlTags.AppendLine($"<JdkIncludePath Include=\"{include}\" />"); } Directory.CreateDirectory(Path.GetDirectoryName(Output.ItemSpec)); File.WriteAllText(Output.ItemSpec, $@"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003""> <Choose> <When Condition="" '$(JdkJvmPath)' == '' ""> <PropertyGroup> <JdkJvmPath>{jdk.JdkJvmPath}</JdkJvmPath> </PropertyGroup> <ItemGroup> {includeXmlTags} </ItemGroup> </When> </Choose> <PropertyGroup> <JavaCPath Condition="" '$(JavaCPath)' == '' "">{jdk.JavacPath}</JavaCPath> <JarPath Condition="" '$(JarPath)' == '' "">{jdk.JarPath}</JarPath> </PropertyGroup> </Project>"); JavaSdkDirectory = jdk.HomePath; Log.LogMessage(MessageImportance.Low, $" [Output] {nameof (JavaSdkDirectory)}: {JavaSdkDirectory}"); return(!Log.HasLoggedErrors); } finally { } }
public override Task <DiagnosticResult> Examine(SharedState history) { var jdkPath = history.GetEnvironmentVariable("JAVA_HOME") ?? Environment.GetEnvironmentVariable("JAVA_HOME"); string androidSdkPath = null; try { // Set the logger to override the default one that is set in this library // So we can catch output from failed path lookups that are otherwise swallowed var _ = new AndroidSdkInfo((traceLevel, msg) => { if (Util.Verbose || traceLevel == System.Diagnostics.TraceLevel.Error) { Util.LogAlways(msg); } }, androidSdkPath, null, jdkPath); } catch (Exception ex) { Util.Exception(ex); } if (string.IsNullOrEmpty(androidSdkPath)) { androidSdkPath = FindBestSdkLocation(); } var missingPackages = new List <IAndroidComponent>(); var installer = new AndroidSDKInstaller(new Helper(), AndroidManifestType.GoogleV2); installer.Discover(new List <string> { androidSdkPath }); var sdkInstance = installer.FindInstance(androidSdkPath); if (string.IsNullOrEmpty(sdkInstance?.Path)) { return(Task.FromResult( new DiagnosticResult( Status.Error, this, "Failed to find Android SDK.", new Suggestion("Install the Android SDK", "For more information see: [underline]https://aka.ms/dotnet-androidsdk-help[/]")))); } history.SetEnvironmentVariable("ANDROID_SDK_ROOT", sdkInstance.Path); history.SetEnvironmentVariable("ANDROID_HOME", sdkInstance.Path); var installed = sdkInstance?.Components?.AllInstalled(true); foreach (var package in RequiredPackages) { var v = !string.IsNullOrWhiteSpace(package.Version) ? new AndroidRevision(package.Version) : null; var installedPkg = FindInstalledPackage(installed, package) ?? FindInstalledPackage(installed, package.Alternatives?.ToArray()); if (installedPkg == null) { var pkgToInstall = sdkInstance?.Components?.AllNotInstalled()? .FirstOrDefault(p => p.Path.Equals(package.Path.Trim(), StringComparison.OrdinalIgnoreCase) && p.Revision >= (v ?? p.Revision)); ReportStatus($"{package.Path} ({package.Version}) missing.", Status.Error); if (pkgToInstall != null) { missingPackages.Add(pkgToInstall); } } else { if (!package.Path.Equals(installedPkg.Path) || v != (installedPkg.Revision ?? installedPkg.InstalledRevision)) { ReportStatus($"{installedPkg.Path} ({installedPkg.InstalledRevision ?? installedPkg.Revision})", Status.Ok); } else { ReportStatus($"{package.Path} ({package.Version})", Status.Ok); } } } if (!missingPackages.Any()) { return(Task.FromResult(DiagnosticResult.Ok(this))); } var installationSet = installer.GetInstallationSet(sdkInstance, missingPackages); var desc = @$ "Your Android SDK has missing or outdated packages. You can use the Android SDK Manager to install / update them. For more information see: [underline]https://aka.ms/dotnet-androidsdk-help[/]";
public override bool Execute() { Log.LogMessage(MessageImportance.Low, $"Task {nameof (JdkInfo)}"); Log.LogMessage(MessageImportance.Low, $" {nameof (Output)}: {Output}"); Log.LogMessage(MessageImportance.Low, $" {nameof (AndroidNdkPath)}: {AndroidNdkPath}"); Log.LogMessage(MessageImportance.Low, $" {nameof (AndroidSdkPath)}: {AndroidSdkPath}"); Log.LogMessage(MessageImportance.Low, $" {nameof (JavaSdkPath)}: {JavaSdkPath}"); var androidSdk = new AndroidSdkInfo(CreateTaskLogger(this), AndroidSdkPath, AndroidNdkPath, JavaSdkPath); try { var javaSdkPath = androidSdk.JavaSdkPath; if (string.IsNullOrEmpty(javaSdkPath)) { Log.LogError("JavaSdkPath is blank"); return(false); } Log.LogMessage(MessageImportance.Low, $" {nameof (androidSdk.JavaSdkPath)}: {javaSdkPath}"); var jvmPath = Path.Combine(javaSdkPath, "jre", "bin", "server", "jvm.dll"); if (!File.Exists(jvmPath)) { Log.LogError($"JdkJvmPath not found at {jvmPath}"); return(false); } var javaIncludePath = Path.Combine(javaSdkPath, "include"); var includes = new List <string> { javaIncludePath }; includes.AddRange(Directory.GetDirectories(javaIncludePath)); //Include dirs such as "win32" var includeXmlTags = new StringBuilder(); foreach (var include in includes) { includeXmlTags.AppendLine($"<JdkIncludePath Include=\"{include}\" />"); } Directory.CreateDirectory(Path.GetDirectoryName(Output.ItemSpec)); File.WriteAllText(Output.ItemSpec, $@"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003""> <Choose> <When Condition="" '$(JdkJvmPath)' == '' ""> <PropertyGroup> <JdkJvmPath>{jvmPath}</JdkJvmPath> </PropertyGroup> <ItemGroup> {includeXmlTags} </ItemGroup> </When> </Choose> <PropertyGroup> <JavaCPath Condition="" '$(JavaCPath)' == '' "">{Path.Combine (javaSdkPath, "bin", "javac.exe")}</JavaCPath> <JarPath Condition="" '$(JarPath)' == '' "">{Path.Combine (javaSdkPath, "bin", "jar.exe")}</JarPath> </PropertyGroup> </Project>"); JavaSdkDirectory = javaSdkPath; Log.LogMessage(MessageImportance.Low, $" [Output] {nameof (JavaSdkDirectory)}: {JavaSdkDirectory}"); return(!Log.HasLoggedErrors); } finally { } }