예제 #1
0
        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);
        }
예제 #2
0
 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");
 }
예제 #3
0
        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));
            }
        }
예제 #4
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.");
            }
        }
예제 #5
0
        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);
            }
        }