public void GetDependencyWhenBuildToolsAreMissingTest() { var apis = new ApiInfo [] { }; var path = Path.Combine("temp", TestName); var androidSdkPath = CreateFauxAndroidSdkDirectory(Path.Combine(path, "android-sdk"), null, apis); var referencesPath = CreateFauxReferencesDirectory(Path.Combine(path, "xbuild-frameworks"), apis); var proj = new XamarinAndroidApplicationProject() { IsRelease = true, TargetFrameworkVersion = "v8.0", TargetSdkVersion = "26", UseLatestPlatformSdk = false, }; var parameters = new string [] { $"TargetFrameworkRootPath={referencesPath}", $"AndroidSdkDirectory={androidSdkPath}", }; string buildToolsVersion = GetExpectedBuildToolsVersion(); using (var builder = CreateApkBuilder(Path.Combine(path, proj.ProjectName), cleanupAfterSuccessfulBuild: false, cleanupOnDispose: false)) { builder.ThrowOnBuildFailure = false; builder.Target = "GetAndroidDependencies"; Assert.True(builder.Build(proj, parameters: parameters), string.Format("First Build should have succeeded")); int apiLevel = Builder.UseDotNet ? AndroidSdkResolver.GetMaxInstalledPlatform() : 26; StringAssertEx.Contains($"platforms/android-{apiLevel}", builder.LastBuildOutput, $"platforms/android-{apiLevel} should be a dependency."); StringAssertEx.Contains($"build-tools/{buildToolsVersion}", builder.LastBuildOutput, $"build-tools/{buildToolsVersion} should be a dependency."); StringAssertEx.Contains("platform-tools", builder.LastBuildOutput, "platform-tools should be a dependency."); } }
public void BuildBasicBindingLibrary(string classParser) { var proj = new XamarinAndroidBindingProject() { IsRelease = true, }; proj.Jars.Add(new AndroidItem.EmbeddedJar("Jars\\svg-android.jar") { WebContent = "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/svg-android/svg-android.jar" }); proj.AndroidClassParser = classParser; using (var b = CreateDllBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); //A list of properties we check exist in binding projects var properties = new [] { "AndroidSdkBuildToolsVersion", "AndroidSdkPlatformToolsVersion", "AndroidSdkToolsVersion", "AndroidNdkVersion", }; foreach (var property in properties) { Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, property + " = "), $"$({property}) should be set!"); } } }
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."); } var proj = new XamarinAndroidApplicationProject() { IsRelease = true, }; if (useApkSigner) { proj.SetProperty("AndroidUseApkSigner", "true"); } else { proj.RemoveProperty("AndroidUseApkSigner"); } proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidCreatePackagePerAbi, perAbiApk); proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidSupportedAbis, "armeabi-v7a;x86"); using (var b = CreateApkBuilder(Path.Combine("temp", TestContext.CurrentContext.Test.Name))) { b.Verbosity = Microsoft.Build.Framework.LoggerVerbosity.Diagnostic; Assert.IsTrue(b.Build(proj), "build failed"); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, " 0 Warning(s)")); proj.AndroidResources.First().Timestamp = null; Assert.IsTrue(b.Build(proj), "Second build failed"); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, " 0 Warning(s)")); } }
public void CheckClassesDexIsIncluded([Values("dx", "d8", "invalid")] string dexTool) { var proj = new XamarinAndroidApplicationProject() { IsRelease = true, DexTool = dexTool, }; using (var b = CreateApkBuilder()) { b.ThrowOnBuildFailure = false; if (Builder.UseDotNet && dexTool == "dx") { Assert.IsFalse(b.Build(proj), "build failed"); StringAssertEx.Contains("XA1023", b.LastBuildOutput, "Output should contain XA1023 errors"); return; } Assert.IsTrue(b.Build(proj), "build failed"); var apk = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "bin", "UnnamedProject.UnnamedProject.apk"); using (var zip = ZipHelper.OpenZip(apk)) { Assert.IsTrue(zip.ContainsEntry("classes.dex"), "Apk should contain classes.dex"); } } }
public void BuildBasicBindingLibrary(string classParser) { var targets = new List <string> { "_ExportJarToXml", "GenerateBindings", "_ResolveLibraryProjectImports", "CoreCompile", }; if (Builder.UseDotNet) { targets.Add("_CreateAar"); } else { targets.Add("_CreateBindingResourceArchive"); //TODO: .NET 5+ cannot support javadoc yet, due to missing mdoc targets.Add("_ExtractJavaDocJars"); targets.Add("BuildDocumentation"); } var proj = new XamarinAndroidBindingProject() { IsRelease = true, }; proj.Jars.Add(new AndroidItem.AndroidLibrary("Jars\\svg-android.jar") { WebContent = "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/svg-android/svg-android.jar" }); proj.AndroidClassParser = classParser; using (var b = CreateDllBuilder()) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); var assemblyPath = Path.Combine(Root, b.ProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.dll"); using (var assembly = AssemblyDefinition.ReadAssembly(assemblyPath)) { var typeName = "Com.Larvalabs.Svgandroid.SVG"; var type = assembly.MainModule.GetType(typeName); Assert.IsNotNull(type, $"{assemblyPath} should contain {typeName}"); } //A list of properties we check exist in binding projects var properties = new [] { "AndroidSdkBuildToolsVersion", "AndroidSdkPlatformToolsVersion", "AndroidSdkToolsVersion", "AndroidNdkVersion", }; foreach (var property in properties) { Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, property + " = "), $"$({property}) should be set!"); } Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true, saveProject: false), "second build should succeed"); foreach (var target in targets) { Assert.IsTrue(b.Output.IsTargetSkipped(target), $"`{target}` should be skipped on second build!"); } } }
public void BuildBasicApplicationReleaseWithCustomAotProfile() { var proj = new XamarinAndroidApplicationProject() { IsRelease = true, AndroidEnableProfiledAot = true, }; proj.SetProperty(proj.ActiveConfigurationProperties, "AndroidExtraAotOptions", "--verbose"); byte [] custom_aot_profile; using (var stream = typeof(XamarinAndroidApplicationProject).Assembly.GetManifestResourceStream("Xamarin.ProjectTools.Resources.Base.custom.aotprofile")) { custom_aot_profile = new byte [stream.Length]; stream.Read(custom_aot_profile, 0, (int)stream.Length); } proj.OtherBuildItems.Add(new BuildItem("AndroidAotProfile", "custom.aotprofile") { BinaryContent = () => custom_aot_profile }); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); StringAssertEx.ContainsRegex(@"\[aot-compiler stdout\] Using profile data file.*custom\.aotprofile", b.LastBuildOutput, "Should use custom AOT profile", RegexOptions.IgnoreCase); StringAssertEx.ContainsRegex(@"\[aot-compiler stdout\] Method.*emitted at", b.LastBuildOutput, "Should contain verbose AOT compiler output", RegexOptions.IgnoreCase); } }
public void LibraryProjectZipWithLint() { var path = Path.Combine("temp", TestName); var lib = new XamarinAndroidBindingProject() { ProjectName = "BindingsProject", AndroidClassParser = "class-parse", Jars = { new AndroidItem.LibraryProjectZip("fragment-1.2.2.aar") { WebContent = "https://maven.google.com/androidx/fragment/fragment/1.2.2/fragment-1.2.2.aar" } }, MetadataXml = @"<metadata><remove-node path=""/api/package[@name='androidx.fragment.app']/interface[@name='FragmentManager.OpGenerator']"" /></metadata>" }; var app = new XamarinAndroidApplicationProject() { ProjectName = "App", IsRelease = true, LinkTool = "r8", References = { new BuildItem.ProjectReference($"..\\{lib.ProjectName}\\{lib.ProjectName}.csproj", lib.ProjectName, lib.ProjectGuid) } }; using (var libBuilder = CreateDllBuilder(Path.Combine(path, lib.ProjectName), cleanupAfterSuccessfulBuild: false)) using (var appBuilder = CreateApkBuilder(Path.Combine(path, app.ProjectName))) { Assert.IsTrue(libBuilder.Build(lib), "Library build should have succeeded."); Assert.IsTrue(appBuilder.Build(app), "App build should have succeeded."); StringAssertEx.DoesNotContain("warning : Missing class: com.android.tools.lint.detector.api.Detector", appBuilder.LastBuildOutput, "Build output should contain no warnings about com.android.tools.lint.detector.api.Detector"); var libraryProjects = Path.Combine(Root, appBuilder.ProjectDirectory, app.IntermediateOutputPath, "lp"); Assert.IsFalse(Directory.EnumerateFiles(libraryProjects, "lint.jar", SearchOption.AllDirectories).Any(), "`lint.jar` should not be extracted!"); } }
public void InstallErrorCode() { if (!CommercialBuildAvailable) { Assert.Ignore("Not required on Open Source Builds"); } if (!HasDevices) { Assert.Ignore("Test Skipped no devices or emulators found."); } //Setup a situation where we get INSTALL_FAILED_NO_MATCHING_ABIS var abi = "armeabi-v7a"; var proj = new XamarinAndroidApplicationProject { AndroidUseSharedRuntime = false, EmbedAssembliesIntoApk = true, }; proj.SetProperty(proj.DebugProperties, KnownProperties.AndroidSupportedAbis, abi); using (var builder = CreateApkBuilder(Path.Combine("temp", TestContext.CurrentContext.Test.Name))) { builder.ThrowOnBuildFailure = false; if (!builder.Install(proj)) { Assert.IsTrue(StringAssertEx.ContainsText(builder.LastBuildOutput, "ADB0020"), "Should receive ADB0020 error code."); } else { Assert.Ignore($"Install should have failed, but we might have an {abi} emulator attached."); } } }
public void InstallErrorCode() { AssertCommercialBuild(); AssertHasDevices(); //Setup a situation where we get INSTALL_FAILED_NO_MATCHING_ABIS var abi = "armeabi-v7a"; var proj = new XamarinAndroidApplicationProject { EmbedAssembliesIntoApk = true, }; proj.SetAndroidSupportedAbis(abi); using (var builder = CreateApkBuilder(Path.Combine("temp", TestContext.CurrentContext.Test.Name))) { builder.ThrowOnBuildFailure = false; if (!builder.Install(proj)) { Assert.IsTrue(StringAssertEx.ContainsText(builder.LastBuildOutput, "ADB0020"), "Should receive ADB0020 error code."); } else { Assert.Ignore($"Install should have failed, but we might have an {abi} emulator attached."); } } }
public void Queries_API30([Values(true, false)] bool useAapt2) { if (!CommercialBuildAvailable) { Assert.Ignore("$(AndroidUseSharedRuntime) is required for this test."); return; } var proj = new XamarinAndroidApplicationProject { AndroidUseSharedRuntime = true, EmbedAssembliesIntoApk = false, }; proj.SetProperty("AndroidUseAapt2", useAapt2.ToString()); proj.AndroidManifest = proj.AndroidManifest.Replace("<uses-sdk />", "<uses-sdk android:targetSdkVersion=\"30\" />"); using (var b = CreateApkBuilder()) { Assert.IsTrue(b.Build(proj), "Build should have succeeded"); string manifest = b.Output.GetIntermediaryAsText(Path.Combine("android", "AndroidManifest.xml")); var doc = XDocument.Parse(manifest); var ns = XNamespace.Get("http://schemas.android.com/apk/res/android"); var names = doc.Element("manifest")? .Element("queries")? .Elements("package")? .Select(e => e.Attribute(ns + "name")?.Value); StringAssertEx.Contains("Mono.Android.DebugRuntime", names); StringAssertEx.Contains("Mono.Android.Platform.ApiLevel_30", names); } }
public void Bug12935([Values(true, false)] bool useAapt2) { AssertAaptSupported(useAapt2); var proj = new XamarinAndroidApplicationProject() { IsRelease = true, }; proj.MainActivity = ScreenOrientationActivity; proj.AndroidUseAapt2 = useAapt2; var directory = $"temp/Bug12935_{useAapt2}"; using (var builder = CreateApkBuilder(directory)) { proj.TargetFrameworkVersion = "v4.2"; proj.AndroidManifest = string.Format(TargetSdkManifest, "17"); Assert.IsTrue(builder.Build(proj), "Build for TargetFrameworkVersion 17 should have succeeded"); var manifestFile = Path.Combine(Root, builder.ProjectDirectory, proj.IntermediateOutputPath, "android", "AndroidManifest.xml"); XDocument doc = XDocument.Load(manifestFile); var ns = doc.Root.GetNamespaceOfPrefix("android"); var screenOrientationXName = XName.Get("screenOrientation", ns.NamespaceName); var targetSdkXName = XName.Get("targetSdkVersion", ns.NamespaceName); var usesSdk = doc.XPathSelectElement("/manifest/uses-sdk"); Assert.IsNotNull(usesSdk, "Failed to read the uses-sdk element"); var targetSdk = usesSdk.Attribute(targetSdkXName); Assert.AreEqual("17", targetSdk.Value, "targetSdkVersion should have been 17"); var activityElement = doc.XPathSelectElement("/manifest/application/activity"); Assert.IsNotNull(activityElement, "Failed to read the activity element"); var screenOrientation = activityElement.Attribute(screenOrientationXName); Assert.IsNotNull(screenOrientation, "activity element did not contain a android:screenOrientation attribute"); Assert.AreEqual("sensorPortrait", screenOrientation.Value, "screenOrientation should have been sensorPortrait"); builder.Cleanup(); proj.TargetFrameworkVersion = "v4.1"; proj.AndroidManifest = string.Format(TargetSdkManifest, "16"); Assert.IsTrue(builder.Build(proj), "Build for TargetFrameworkVersion 16 should have succeeded"); doc = XDocument.Load(manifestFile); usesSdk = doc.XPathSelectElement("/manifest/uses-sdk"); Assert.IsNotNull(usesSdk, "Failed to read the uses-sdk element"); targetSdk = usesSdk.Attribute(targetSdkXName); Assert.AreEqual("16", targetSdk.Value, "targetSdkVersion should have been 16"); activityElement = doc.XPathSelectElement("/manifest/application/activity"); Assert.IsNotNull(activityElement, "Failed to read the activity element"); screenOrientation = activityElement.Attribute(screenOrientationXName); Assert.AreEqual("sensorPortrait", screenOrientation.Value, "screenOrientation for targetSdkVersion 16 should have been sensorPortrait"); builder.Cleanup(); builder.ThrowOnBuildFailure = false; proj.TargetFrameworkVersion = "v4.0.3"; proj.AndroidManifest = string.Format(TargetSdkManifest, "15"); Assert.IsFalse(builder.Build(proj), "Build for TargetFrameworkVersion 15 should have failed"); StringAssertEx.Contains(useAapt2 ? "APT2259: " : "APT1134: ", builder.LastBuildOutput); StringAssertEx.Contains(useAapt2 ? "APT2067" : "", builder.LastBuildOutput); StringAssertEx.Contains(Path.Combine("Properties", "AndroidManifest.xml"), builder.LastBuildOutput); StringAssertEx.Contains($"{(useAapt2 ? "2" : "1")} Error(s)", builder.LastBuildOutput); } }
public void AppBundleSigned () { var aab = Path.Combine (bin, "UnnamedProject.UnnamedProject-Signed.aab"); FileAssert.Exists (aab); var contents = ListArchiveContents (aab); Assert.IsTrue (StringAssertEx.ContainsText (contents, "META-INF/MANIFEST.MF"), $"{aab} is not signed!"); }
public void DotNetBuildXamarinForms() { var proj = new XamarinFormsXASdkProject(); var dotnet = CreateDotNetBuilder(proj); Assert.IsTrue(dotnet.Build(), "`dotnet build` should succeed"); Assert.IsTrue(StringAssertEx.ContainsText(dotnet.LastBuildOutput, " 0 Warning(s)"), "Should have no MSBuild warnings."); }
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."); } var proj = new XamarinAndroidApplicationProject() { IsRelease = true, }; if (useApkSigner) { proj.SetProperty("AndroidUseApkSigner", "true"); } else { proj.RemoveProperty("AndroidUseApkSigner"); } proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidCreatePackagePerAbi, perAbiApk); proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidSupportedAbis, "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`."); } } } }
void WarnAboutAppDomains(XamarinAndroidApplicationProject proj, string testName) { proj.MainActivity = proj.DefaultMainActivity.Replace("base.OnCreate (bundle);", "base.OnCreate (bundle);\nvar appDomain = System.AppDomain.CreateDomain (\"myDomain\");"); var projDirectory = Path.Combine("temp", testName); using (var b = CreateApkBuilder(projDirectory)) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "Warning: Use of AppDomain::CreateDomain"), "Should warn about creating AppDomain."); } }
public void Aapt2Disabled() { var proj = new XamarinAndroidApplicationProject(); proj.SetProperty("AndroidUseAapt2", "False"); using (var b = CreateApkBuilder("temp/Aapt2Disabled")) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "Task \"Aapt2Link\" skipped"), "Aapt2Link task should be skipped!"); Assert.IsTrue(b.Output.IsTargetSkipped("_CreateAapt2VersionCache"), "_CreateAapt2VersionCache target should be skipped!"); } }
void WarnAboutAppDomains(XamarinAndroidApplicationProject proj, string testName) { proj.MainActivity = proj.DefaultMainActivity.Replace("base.OnCreate (bundle);", "base.OnCreate (bundle);\nvar appDomain = System.AppDomain.CreateDomain (\"myDomain\");"); var projDirectory = Path.Combine("temp", testName); using (var b = CreateApkBuilder(projDirectory)) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "2 Warning(s)"), "MSBuild should count 2 warnings."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "warning CS0618: 'AppDomain.CreateDomain(string)' is obsolete: 'AppDomain.CreateDomain will no longer be supported in .NET 5 and later."), "Should warn CS0618 about creating AppDomain."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "warning XA2000: Use of AppDomain.CreateDomain()"), "Should warn XA2000 about creating AppDomain."); } }
public void Edge(int limit, bool xamarinForms) { var testName = $"{nameof (Edge)}{xamarinForms}" .PadRight(Files.MaxPath - BaseLength - limit, 'N'); var proj = CreateProject(xamarinForms); using (var b = CreateApkBuilder(Path.Combine("temp", testName))) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); Assert.IsTrue(b.Clean(proj), "Clean should have succeeded."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, $"Trying long path: {Files.LongPathPrefix}"), "A long path should be encountered."); } }
public void BundledWearApp() { var target = "_UpdateAndroidResgen"; var path = Path.Combine("temp", TestName); var app = new XamarinAndroidApplicationProject { ProjectName = "MyApp", AndroidUseSharedRuntime = false, EmbedAssembliesIntoApk = true, }; var wear = new XamarinAndroidWearApplicationProject { AndroidUseSharedRuntime = false, EmbedAssembliesIntoApk = true, }; app.References.Add(new BuildItem.ProjectReference($"..\\{wear.ProjectName}\\{wear.ProjectName}.csproj", wear.ProjectName, wear.ProjectGuid) { MetadataValues = "IsAppExtension=True" }); using (var wearBuilder = CreateDllBuilder(Path.Combine(path, wear.ProjectName))) using (var appBuilder = CreateApkBuilder(Path.Combine(path, app.ProjectName))) { Assert.IsTrue(wearBuilder.Build(wear), "first wear build should have succeeded."); // In .NET 5+, just check for a build error if (Builder.UseDotNet) { appBuilder.ThrowOnBuildFailure = false; Assert.IsFalse(appBuilder.Build(app), "'dotnet' app build should have failed."); StringAssertEx.Contains($"error XA4312", appBuilder.LastBuildOutput, "Error should be XA4312"); return; } Assert.IsTrue(appBuilder.Build(app), "first app build should have succeeded."); StringAssertEx.Contains($"warning XA4312", appBuilder.LastBuildOutput, "Warning should be XA4312"); // Build with no changes Assert.IsTrue(wearBuilder.Build(wear, doNotCleanupOnUpdate: true), "second wear build should have succeeded."); Assert.IsTrue(wearBuilder.Output.IsTargetSkipped(target), $"`{target}` in wear build should be skipped!"); Assert.IsTrue(appBuilder.Build(app, doNotCleanupOnUpdate: true), "second app build should have succeeded."); Assert.IsTrue(appBuilder.LastBuildOutput.ContainsOccurances($"Skipping target \"{target}\"", 2), $"`{target}` in app build should be skipped!"); // Check the APK for the special Android Wear files var files = new [] { "res/raw/wearable_app.apk", "res/xml/wearable_app_desc.xml" }; var apk = Path.Combine(Root, appBuilder.ProjectDirectory, app.OutputPath, $"{app.PackageName}.apk"); FileAssert.Exists(apk); using (var zipFile = ZipHelper.OpenZip(apk)) { foreach (var file in files) { Assert.IsTrue(zipFile.ContainsEntry(file, caseSensitive: true), $"{file} should be in the apk!"); } } } }
public void Aapt2Disabled() { AssertAaptSupported(useAapt2: false); var proj = new XamarinAndroidApplicationProject(); proj.AndroidUseAapt2 = false; using (var b = CreateApkBuilder()) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); Assert.IsFalse(StringAssertEx.ContainsText(b.LastBuildOutput, "Aapt2Link"), "Aapt2Link task should not run!"); Assert.IsFalse(StringAssertEx.ContainsText(b.LastBuildOutput, "Aapt2Compile"), "Aapt2Compile task should not run!"); Assert.IsFalse(StringAssertEx.ContainsText(b.LastBuildOutput, "_CreateAapt2VersionCache"), "_CreateAapt2VersionCache target should not run!"); } }
public void LongPath() { if (LongPathsSupported) { Assert.Ignore("This environment supports long paths"); } var file = NewFile(fileName: "foo".PadRight(MaxFileName, 'N')); var task = CreateTask(); Assert.IsTrue(task.Execute(), "task.Execute() should have succeeded."); Assert.AreEqual(1, task.RemovedDirectories.Length, "Changes should have been made."); DirectoryAssert.DoesNotExist(tempDirectory); Assert.IsTrue(StringAssertEx.ContainsText(messages.Select(m => m.Message), $"Trying long path: {Files.LongPathPrefix}"), "A long path should be encountered."); }
public void OverTheEdge(int limit, bool xamarinForms) { var testName = $"{nameof (Edge)}{xamarinForms}" .PadRight(Files.MaxPath - BaseLength - limit, 'N'); var proj = CreateProject(xamarinForms); using (var b = CreateApkBuilder(Path.Combine("temp", testName))) { b.ThrowOnBuildFailure = false; Assert.IsFalse(b.Build(proj), "Build should have failed."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "XA5301"), "Should get MAX_PATH warning"); b.ThrowOnBuildFailure = true; Assert.IsTrue(b.Clean(proj), "Clean should have succeeded."); } }
public void LongPath() { if (!IsWindows) { Assert.Ignore("MAX_PATH only applies on Windows"); } var file = NewFile(fileName: "foo".PadRight(250, 'N')); var task = CreateTask(); Assert.IsTrue(task.Execute(), "task.Execute() should have succeeded."); Assert.AreEqual(1, task.RemovedDirectories.Length, "Changes should have been made."); DirectoryAssert.DoesNotExist(tempDirectory); Assert.IsTrue(StringAssertEx.ContainsText(messages.Select(m => m.Message), $"Trying long path: {Files.LongPathPrefix}"), "A long path should be encountered."); }
public void BuildBasicApplicationReleaseProfiledAotWithoutDefaultProfile() { var proj = new XamarinAndroidApplicationProject() { IsRelease = true, AndroidEnableProfiledAot = true, }; proj.SetProperty(proj.ActiveConfigurationProperties, "AndroidUseDefaultAotProfile", "false"); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); StringAssertEx.DoesNotContainRegex(@"\[aot-compiler stdout\] Using profile data file.*build.Xamarin.Android.startup.*\.aotprofile", b.LastBuildOutput, "Should not use default AOT profile", RegexOptions.IgnoreCase); } }
public void BuildBasicBindingLibrary(string classParser) { var targets = new List <string> { "_ExportJarToXml", "GenerateBindings", "_CreateBindingResourceArchive", "_ResolveLibraryProjectImports", "CoreCompile", }; if (!Builder.UseDotNet) { //TODO: .NET 5+ cannot support javadoc yet, due to missing mdoc targets.Add("_ExtractJavaDocJars"); targets.Add("BuildDocumentation"); } var proj = new XamarinAndroidBindingProject() { IsRelease = true, }; proj.Jars.Add(new AndroidItem.EmbeddedJar("Jars\\svg-android.jar") { WebContent = "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/svg-android/svg-android.jar" }); proj.AndroidClassParser = classParser; using (var b = CreateDllBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); //A list of properties we check exist in binding projects var properties = new [] { "AndroidSdkBuildToolsVersion", "AndroidSdkPlatformToolsVersion", "AndroidSdkToolsVersion", "AndroidNdkVersion", }; foreach (var property in properties) { Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, property + " = "), $"$({property}) should be set!"); } Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true, saveProject: false), "second build should succeed"); foreach (var target in targets) { Assert.IsTrue(b.Output.IsTargetSkipped(target), $"`{target}` should be skipped on second build!"); } } }
public void BuildBasicApplicationReleaseProfiledAot() { var proj = new XamarinAndroidApplicationProject() { IsRelease = true, AndroidEnableProfiledAot = true, }; proj.SetProperty(proj.ActiveConfigurationProperties, "AndroidExtraAotOptions", "--verbose"); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); StringAssertEx.ContainsRegex(@"\[aot-compiler stdout\] Using profile data file.*build.Xamarin.Android.startup\.aotprofile", b.LastBuildOutput, "Should use default AOT profile", RegexOptions.IgnoreCase); StringAssertEx.ContainsRegex(@"\[aot-compiler stdout\] Method.*emitted at", b.LastBuildOutput, "Should contain verbose AOT compiler output", RegexOptions.IgnoreCase); } }
[Category("DotNetIgnore")] // n/a on .NET 5+ public void WarnAboutAppDomains([Values(true, false)] bool isRelease) { var proj = new XamarinAndroidApplicationProject() { IsRelease = isRelease }; proj.MainActivity = proj.DefaultMainActivity.Replace("base.OnCreate (bundle);", "base.OnCreate (bundle);\nvar appDomain = System.AppDomain.CreateDomain (\"myDomain\");"); using (var b = CreateApkBuilder()) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "2 Warning(s)"), "MSBuild should count 2 warnings."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "warning CS0618: 'AppDomain.CreateDomain(string)' is obsolete: 'AppDomain.CreateDomain will no longer be supported in .NET 5 and later."), "Should warn CS0618 about creating AppDomain."); Assert.IsTrue(StringAssertEx.ContainsText(b.LastBuildOutput, "warning XA2000: Use of AppDomain.CreateDomain()"), "Should warn XA2000 about creating AppDomain."); } }
public void DotNetBuild(string runtimeIdentifier, bool isRelease) { var abi = MonoAndroidHelper.RuntimeIdentifierToAbi(runtimeIdentifier); var proj = new XASdkProject { IsRelease = isRelease }; proj.OtherBuildItems.Add(new AndroidItem.InputJar("javaclasses.jar") { BinaryContent = () => Convert.FromBase64String(InlineData.JavaClassesJarBase64) }); // TODO: bring back when Xamarin.Android.Bindings.Documentation.targets is working //proj.OtherBuildItems.Add (new BuildItem ("JavaSourceJar", "javasources.jar") { // BinaryContent = () => Convert.FromBase64String (InlineData.JavaSourcesJarBase64) //}); proj.SetProperty(KnownProperties.RuntimeIdentifier, runtimeIdentifier); var dotnet = CreateDotNetBuilder(proj); Assert.IsTrue(dotnet.Build(), "`dotnet build` should succeed"); // TODO: run for release once illink warnings are gone // context: https://github.com/xamarin/xamarin-android/issues/4708 if (!isRelease) { Assert.IsTrue(StringAssertEx.ContainsText(dotnet.LastBuildOutput, " 0 Warning(s)"), "Should have no MSBuild warnings."); } var outputPath = Path.Combine(Root, dotnet.ProjectDirectory, proj.OutputPath, runtimeIdentifier); var assemblyPath = Path.Combine(outputPath, "UnnamedProject.dll"); FileAssert.Exists(assemblyPath); using (var assembly = AssemblyDefinition.ReadAssembly(assemblyPath)) { var typeName = "Com.Xamarin.Android.Test.Msbuildtest.JavaSourceJarTest"; var type = assembly.MainModule.GetType(typeName); Assert.IsNotNull(type, $"{assemblyPath} should contain {typeName}"); } var apk = Path.Combine(outputPath, "UnnamedProject.UnnamedProject.apk"); FileAssert.Exists(apk); using (var zip = ZipHelper.OpenZip(apk)) { Assert.IsTrue(zip.ContainsEntry($"lib/{abi}/libmonodroid.so"), "libmonodroid.so should exist."); Assert.IsTrue(zip.ContainsEntry($"lib/{abi}/libmonosgen-2.0.so"), "libmonosgen-2.0.so should exist."); } }
public void GetDependencyNdkRequiredConditions(string property, bool ndkRequired) { var proj = new XamarinAndroidApplicationProject(); proj.AotAssemblies = true; proj.SetProperty(property, "true"); using (var builder = CreateApkBuilder()) { builder.Target = "GetAndroidDependencies"; Assert.IsTrue(builder.Build(proj), "Build should have succeeded."); IEnumerable <string> taskOutput = builder.LastBuildOutput .Select(x => x.Trim()) .SkipWhile(x => !x.StartsWith("Task \"CalculateProjectDependencies\"")) .SkipWhile(x => !x.StartsWith("Output Item(s):")) .TakeWhile(x => !x.StartsWith("Done executing task \"CalculateProjectDependencies\"")); if (ndkRequired) { StringAssertEx.Contains("ndk-bundle", taskOutput, "ndk-bundle should be a dependency."); } else { StringAssertEx.DoesNotContain("ndk-bundle", taskOutput, "ndk-bundle should not be a dependency."); } } }
public void TestAndroidStoreKey(bool useApkSigner, bool isRelease, string packageFormat, string androidKeyStore, string password, string expected, bool shouldInstall) { AssertHasDevices(); if (DeviceSdkVersion >= 30 && !useApkSigner && packageFormat == "apk") { Assert.Ignore($"Test Skipped. jarsigner and {packageFormat} does not work with API 30 and above"); return; } string path = Path.Combine("temp", TestName.Replace(expected, expected.Replace("-", "_"))); string storepassfile = Path.Combine(Root, path, "storepass.txt"); string keypassfile = Path.Combine(Root, path, "keypass.txt"); byte [] data = GetKeystore(); var proj = new XamarinAndroidApplicationProject() { IsRelease = isRelease }; Dictionary <string, string> envVar = new Dictionary <string, string> (); if (password.StartsWith("env:", StringComparison.Ordinal)) { envVar.Add("_MYPASSWORD", password.Replace("env:", string.Empty)); proj.SetProperty("AndroidSigningStorePass", "env:_MYPASSWORD"); proj.SetProperty("AndroidSigningKeyPass", "env:_MYPASSWORD"); } else if (password.StartsWith("file:", StringComparison.Ordinal)) { proj.SetProperty("AndroidSigningStorePass", $"file:{storepassfile}"); proj.SetProperty("AndroidSigningKeyPass", $"file:{keypassfile}"); } else { proj.SetProperty("AndroidSigningStorePass", password); proj.SetProperty("AndroidSigningKeyPass", password); } proj.SetAndroidSupportedAbis("armeabi-v7a", "x86"); proj.SetProperty("AndroidKeyStore", androidKeyStore); proj.SetProperty("AndroidSigningKeyStore", "test.keystore"); proj.SetProperty("AndroidSigningKeyAlias", "mykey"); proj.SetProperty("AndroidPackageFormat", packageFormat); proj.SetProperty("AndroidUseApkSigner", useApkSigner.ToString()); proj.OtherBuildItems.Add(new BuildItem(BuildActions.None, "test.keystore") { BinaryContent = () => data }); proj.OtherBuildItems.Add(new BuildItem(BuildActions.None, "storepass.txt") { TextContent = () => password.Replace("file:", string.Empty), Encoding = Encoding.ASCII, }); proj.OtherBuildItems.Add(new BuildItem(BuildActions.None, "keypass.txt") { TextContent = () => password.Replace("file:", string.Empty), Encoding = Encoding.ASCII, }); using (var b = CreateApkBuilder(path, false, false)) { b.ThrowOnBuildFailure = false; Assert.IsTrue(b.Build(proj, environmentVariables: envVar), "Build should have succeeded."); if (packageFormat == "apk") { StringAssertEx.Contains(expected, b.LastBuildOutput, "The Wrong keystore was used to sign the apk"); } b.BuildLogFile = "install.log"; Assert.AreEqual(shouldInstall, b.Install(proj, doNotCleanupOnUpdate: true), $"Install should have {(shouldInstall ? "succeeded" : "failed")}."); if (packageFormat == "aab") { StringAssertEx.Contains(expected, b.LastBuildOutput, "The Wrong keystore was used to sign the apk"); } if (!shouldInstall) { return; } b.BuildLogFile = "uninstall.log"; Assert.IsTrue(b.Uninstall(proj, doNotCleanupOnUpdate: true), "Uninstall should have succeeded."); } }