static Version GetJdkVersion() { var jdkPath = AndroidSdkResolver.GetJavaSdkPath(); var releasePath = Path.Combine(jdkPath, "release"); if (!File.Exists(releasePath)) { return(null); } foreach (var line in File.ReadLines(releasePath)) { const string JavaVersionStart = "JAVA_VERSION=\""; if (!line.StartsWith(JavaVersionStart, StringComparison.OrdinalIgnoreCase)) { continue; } var value = line.Substring(JavaVersionStart.Length, line.Length - JavaVersionStart.Length - 1); int last = 0; for (last = 0; last < value.Length; ++last) { if (char.IsDigit(value, last) || value [last] == '.') { continue; } break; } return(Version.Parse(last == value.Length ? value : value.Substring(0, last))); } return(null); }
public void Setup() { engine = new MockBuildEngine(TestContext.Out, errors = new List <BuildErrorEventArgs> (), warnings = new List <BuildWarningEventArgs> (), messages = new List <BuildMessageEventArgs> ()); temp = Path.GetTempFileName(); keyToolPath = Path.Combine(AndroidSdkResolver.GetJavaSdkPath(), "bin"); }
public static void AssertValidEnvironmentSharedLibrary(string outputDirectoryRoot, string sdkDirectory, string ndkDirectory, string supportedAbis) { NdkUtil.Init(ndkDirectory); MonoAndroidHelper.AndroidSdk = new AndroidSdkInfo((arg1, arg2) => {}, sdkDirectory, ndkDirectory, AndroidSdkResolver.GetJavaSdkPath()); AndroidTargetArch arch; foreach (string abi in supportedAbis.Split(';')) { switch (abi) { case "armeabi-v7a": arch = AndroidTargetArch.Arm; break; case "arm64": case "arm64-v8a": case "aarch64": arch = AndroidTargetArch.Arm64; break; case "x86": arch = AndroidTargetArch.X86; break; case "x86_64": arch = AndroidTargetArch.X86_64; break; default: throw new Exception("Unsupported Android target architecture ABI: " + abi); } string envSharedLibrary = Path.Combine(outputDirectoryRoot, "app_shared_libraries", abi, "libxamarin-app.so"); Assert.IsTrue(File.Exists(envSharedLibrary), $"Application environment SharedLibrary '{envSharedLibrary}' must exist"); // API level doesn't matter in this case AssertSharedLibraryHasRequiredSymbols(envSharedLibrary, NdkUtil.GetNdkTool(ndkDirectory, arch, "readelf", 0)); } }
public void TestNdkUtil() { var log = new TaskLoggingHelper(engine, TestName); using (var builder = new Builder()) { var ndkDir = AndroidNdkPath; var sdkDir = AndroidSdkPath; MonoAndroidHelper.AndroidSdk = new AndroidSdkInfo((arg1, arg2) => { }, sdkDir, ndkDir, AndroidSdkResolver.GetJavaSdkPath()); NdkUtil.Init(log, ndkDir); var platforms = NdkUtil.GetSupportedPlatforms(log, ndkDir); Assert.AreNotEqual(0, platforms.Count(), "No platforms found"); var arch = AndroidTargetArch.X86; Assert.IsTrue(NdkUtil.ValidateNdkPlatform(log, ndkDir, arch, enableLLVM: false)); Assert.AreEqual(0, errors.Count, "NdkUtil.ValidateNdkPlatform should not have returned false."); int level = NdkUtil.GetMinimumApiLevelFor(arch, ndkDir); int expected = 16; Assert.AreEqual(expected, level, $"Min Api Level for {arch} should be {expected}."); var compilerNoQuotes = NdkUtil.GetNdkTool(ndkDir, arch, "gcc", level); Assert.AreEqual(0, errors.Count, "NdkUtil.GetNdkTool should not have errored."); Assert.NotNull(compilerNoQuotes, "NdkUtil.GetNdkTool returned null."); var gas = NdkUtil.GetNdkTool(ndkDir, arch, "as", level); Assert.AreEqual(0, errors.Count, "NdkUtil.GetNdkTool should not have errored."); Assert.NotNull(gas, "NdkUtil.GetNdkTool returned null."); var inc = NdkUtil.GetNdkPlatformIncludePath(ndkDir, arch, level); Assert.NotNull(inc, " NdkUtil.GetNdkPlatformIncludePath should not return null"); var libPath = NdkUtil.GetNdkPlatformLibPath(ndkDir, arch, level); Assert.NotNull(libPath, "NdkUtil.GetNdkPlatformLibPath should not return null"); string ld = NdkUtil.GetNdkTool(ndkDir, arch, "ld", level); Assert.AreEqual(0, errors.Count, "NdkUtil.GetNdkTool should not have errored."); Assert.NotNull(ld, "NdkUtil.GetNdkTool returned null."); } }
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); } string keyToolPath = Path.Combine(AndroidSdkResolver.GetJavaSdkPath(), "bin"); var engine = new MockBuildEngine(Console.Out); string pass = "******"; string alias = "release store"; var task = new AndroidCreateDebugKey { BuildEngine = engine, KeyStore = keyfile, StorePass = pass, KeyAlias = alias, 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, }; proj.SetProperty(proj.ReleaseProperties, "AndroidUseApkSigner", useApkSigner); proj.SetProperty(proj.ReleaseProperties, "AndroidKeyStore", "True"); proj.SetProperty(proj.ReleaseProperties, "AndroidSigningKeyStore", keyfile); proj.SetProperty(proj.ReleaseProperties, "AndroidSigningKeyAlias", alias); proj.SetProperty(proj.ReleaseProperties, "AndroidSigningKeyPass", Uri.EscapeDataString(pass)); proj.SetProperty(proj.ReleaseProperties, "AndroidSigningStorePass", Uri.EscapeDataString(pass)); proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidCreatePackagePerAbi, perAbiApk); if (perAbiApk) { proj.SetAndroidSupportedAbis("armeabi-v7a", "x86", "arm64-v8a", "x86_64"); } else { 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"); b.AssertHasNoWarnings(); //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`."); } } // Make sure the APKs have unique version codes if (perAbiApk) { int armManifestCode = GetVersionCodeFromIntermediateManifest(Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "armeabi-v7a", "AndroidManifest.xml")); int x86ManifestCode = GetVersionCodeFromIntermediateManifest(Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "x86", "AndroidManifest.xml")); int arm64ManifestCode = GetVersionCodeFromIntermediateManifest(Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "arm64-v8a", "AndroidManifest.xml")); int x86_64ManifestCode = GetVersionCodeFromIntermediateManifest(Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "x86_64", "AndroidManifest.xml")); var versionList = new List <int> { armManifestCode, x86ManifestCode, arm64ManifestCode, x86_64ManifestCode }; Assert.True(versionList.Distinct().Count() == versionList.Count, $"APK version codes were not unique - armeabi-v7a: {armManifestCode}, x86: {x86ManifestCode}, arm64-v8a: {arm64ManifestCode}, x86_64: {x86_64ManifestCode}"); } 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"); b.AssertHasNoWarnings(); //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`."); } } } int GetVersionCodeFromIntermediateManifest(string manifestFilePath) { var doc = XDocument.Load(manifestFilePath); var versionCode = doc.Descendants() .Where(e => e.Name == "manifest") .Select(m => m.Attribute("{http://schemas.android.com/apk/res/android}versionCode")).FirstOrDefault(); if (!int.TryParse(versionCode?.Value, out int parsedCode)) { Assert.Fail($"Unable to parse 'versionCode' value from manifest content: {File.ReadAllText (manifestFilePath)}."); } return(parsedCode); } }