public void MonoSymbolicateNetStandardStackTrace() { AssertHasDevices(); var lib = new DotNetStandard { ProjectName = "Library1", Sdk = "Microsoft.NET.Sdk", TargetFramework = "netstandard2.0", Sources = { new BuildItem.Source("Class1.cs") { TextContent = () => @" using System; namespace Library1 { public class Class1 { string Data { get; set; } public Class1(string data) { Data = data; } public string GetData() { if (Data == null) throw new NullReferenceException(); return Data; } } }", }, } }; proj = new XamarinFormsAndroidApplicationProject() { IsRelease = true, References = { new BuildItem("ProjectReference", "..\\Library1\\Library1.csproj"), }, }; proj.SetAndroidSupportedAbis("armeabi-v7a", "arm64-v8a", "x86", "x86_64"); proj.SetProperty(proj.ReleaseProperties, "MonoSymbolArchive", "True"); proj.MainActivity = proj.DefaultMainActivity.Replace("//${AFTER_ONCREATE}", @" var cl = new Library1.Class1(null); cl.GetData(); "); var rootPath = Path.Combine(Root, "temp", TestName); using (var lb = CreateDllBuilder(Path.Combine(Path.Combine(Root, "temp", TestName), lib.ProjectName))) { Assert.IsTrue(lb.Build(lib), "Library build should have succeeded."); builder = CreateApkBuilder(Path.Combine(rootPath, proj.ProjectName)); Assert.IsTrue(builder.Install(proj), "Install should have succeeded."); var archivePath = Path.Combine(Root, builder.ProjectDirectory, proj.OutputPath, $"{proj.PackageName}.apk.mSYM"); Assert.IsTrue(Directory.Exists(archivePath), $"Symbol archive path {archivePath} should exist."); ClearAdbLogcat(); if (CommercialBuildAvailable) { Assert.True(builder.RunTarget(proj, "_Run"), "Project should have run."); } else { AdbStartActivity($"{proj.PackageName}/{proj.JavaPackageName}.MainActivity"); } var logcatPath = Path.Combine(Root, builder.ProjectDirectory, "crash-logcat.log"); MonitorAdbLogcat((line) => { return(line.Contains($"Force finishing activity {proj.PackageName}")); }, logcatPath, 30); var didParse = int.TryParse(proj.TargetSdkVersion, out int apiLevel); Assert.IsTrue(didParse, $"Unable to parse {proj.TargetSdkVersion} as an int."); SymbolicateAndAssert(archivePath, logcatPath, new string [] { Path.Combine(Root, lb.ProjectDirectory, "Class1.cs:12"), Path.Combine(Root, builder.ProjectDirectory, "MainActivity.cs:33"), Directory.Exists(builder.BuildOutputDirectory) ? Path.Combine("src", "Mono.Android", "obj", XABuildPaths.Configuration, "monoandroid10", $"android-{apiLevel}", "mcw", "Android.App.Activity.cs:") : $"src/Mono.Android/obj/Release/monoandroid10/android-{apiLevel}/mcw/Android.App.Activity.cs:", }); } }
public void VersionCodeTests(bool seperateApk, string abis, string versionCode, bool useLegacy, string versionCodePattern, string versionCodeProperties, bool shouldBuild, string expectedVersionCode) { var proj = new XamarinAndroidApplicationProject() { IsRelease = true, }; proj.SetProperty("Foo", "1"); proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidCreatePackagePerAbi, seperateApk); if (!string.IsNullOrEmpty(abis)) { proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidSupportedAbis, abis); } if (!string.IsNullOrEmpty(versionCodePattern)) { proj.SetProperty(proj.ReleaseProperties, "AndroidVersionCodePattern", versionCodePattern); } else { proj.RemoveProperty(proj.ReleaseProperties, "AndroidVersionCodePattern"); } if (!string.IsNullOrEmpty(versionCodeProperties)) { proj.SetProperty(proj.ReleaseProperties, "AndroidVersionCodeProperties", versionCodeProperties); } else { proj.RemoveProperty(proj.ReleaseProperties, "AndroidVersionCodeProperties"); } if (useLegacy) { proj.SetProperty(proj.ReleaseProperties, "AndroidUseLegacyVersionCode", true); } proj.AndroidManifest = proj.AndroidManifest.Replace("android:versionCode=\"1\"", $"android:versionCode=\"{versionCode}\""); using (var builder = CreateApkBuilder(Path.Combine("temp", TestName), false, false)) { builder.ThrowOnBuildFailure = false; Assert.AreEqual(shouldBuild, builder.Build(proj), shouldBuild ? "Build should have succeeded." : "Build should have failed."); if (!shouldBuild) { return; } var abiItems = seperateApk ? abis.Split(';') : new string[1]; var expectedItems = expectedVersionCode.Split(';'); XNamespace aNS = "http://schemas.android.com/apk/res/android"; Assert.AreEqual(abiItems.Length, expectedItems.Length, "abis parameter should have matching elements for expected"); for (int i = 0; i < abiItems.Length; i++) { var path = seperateApk ? Path.Combine("android", abiItems[i], "AndroidManifest.xml") : Path.Combine("android", "manifest", "AndroidManifest.xml"); var manifest = builder.Output.GetIntermediaryAsText(Root, path); var doc = XDocument.Parse(manifest); var nsResolver = new XmlNamespaceManager(new NameTable()); nsResolver.AddNamespace("android", "http://schemas.android.com/apk/res/android"); var m = doc.XPathSelectElement("/manifest") as XElement; Assert.IsNotNull(m, "no manifest element found"); var vc = m.Attribute(aNS + "versionCode"); Assert.IsNotNull(vc, "no versionCode attribute found"); StringAssert.AreEqualIgnoringCase(expectedItems[i], vc.Value, $"Version Code is incorrect. Found {vc.Value} expect {expectedItems[i]}"); } } }
public void AllActivityAttributeProperties([Values("legacy", "manifestmerger.jar")] string manifestMerger) { string expectedOutput = manifestMerger == "legacy" ? "android:allowEmbedded=\"true\" android:allowTaskReparenting=\"true\" android:alwaysRetainTaskState=\"true\" android:autoRemoveFromRecents=\"true\" android:banner=\"@drawable/icon\" android:clearTaskOnLaunch=\"true\" android:colorMode=\"hdr\" android:configChanges=\"mcc\" android:description=\"@string/app_name\" android:directBootAware=\"true\" android:documentLaunchMode=\"never\" android:enabled=\"true\" android:enableVrMode=\"foo\" android:excludeFromRecents=\"true\" android:exported=\"true\" android:finishOnCloseSystemDialogs=\"true\" android:finishOnTaskLaunch=\"true\" android:hardwareAccelerated=\"true\" android:icon=\"@drawable/icon\" android:immersive=\"true\" android:label=\"TestActivity\" android:launchMode=\"singleTop\" android:lockTaskMode=\"normal\" android:logo=\"@drawable/icon\" android:maxAspectRatio=\"1.2\" android:maxRecents=\"1\" android:multiprocess=\"true\" android:name=\"com.contoso.TestActivity\" android:noHistory=\"true\" android:parentActivityName=\"unnamedproject.unnamedproject.MainActivity\" android:permission=\"com.contoso.permission.TEST_ACTIVITY\" android:persistableMode=\"persistNever\" android:process=\"com.contoso.process.testactivity_process\" android:recreateOnConfigChanges=\"mcc\" android:relinquishTaskIdentity=\"true\" android:resizeableActivity=\"true\" android:resumeWhilePausing=\"true\" android:rotationAnimation=\"crossfade\" android:roundIcon=\"@drawable/icon\" android:screenOrientation=\"portrait\" android:showForAllUsers=\"true\" android:showOnLockScreen=\"true\" android:showWhenLocked=\"true\" android:singleUser=\"true\" android:stateNotNeeded=\"true\" android:supportsPictureInPicture=\"true\" android:taskAffinity=\"com.contoso\" android:theme=\"@android:style/Theme.Light\" android:turnScreenOn=\"true\" android:uiOptions=\"splitActionBarWhenNarrow\" android:visibleToInstantApps=\"true\" android:windowSoftInputMode=\"stateUnchanged|adjustUnspecified\"" : "android:name=\"com.contoso.TestActivity\" android:allowEmbedded=\"true\" android:allowTaskReparenting=\"true\" android:alwaysRetainTaskState=\"true\" android:autoRemoveFromRecents=\"true\" android:banner=\"@drawable/icon\" android:clearTaskOnLaunch=\"true\" android:colorMode=\"hdr\" android:configChanges=\"mcc\" android:description=\"@string/app_name\" android:directBootAware=\"true\" android:documentLaunchMode=\"never\" android:enableVrMode=\"foo\" android:enabled=\"true\" android:excludeFromRecents=\"true\" android:exported=\"true\" android:finishOnCloseSystemDialogs=\"true\" android:finishOnTaskLaunch=\"true\" android:hardwareAccelerated=\"true\" android:icon=\"@drawable/icon\" android:immersive=\"true\" android:label=\"TestActivity\" android:launchMode=\"singleTop\" android:lockTaskMode=\"normal\" android:logo=\"@drawable/icon\" android:maxAspectRatio=\"1.2\" android:maxRecents=\"1\" android:multiprocess=\"true\" android:noHistory=\"true\" android:parentActivityName=\"unnamedproject.unnamedproject.MainActivity\" android:permission=\"com.contoso.permission.TEST_ACTIVITY\" android:persistableMode=\"persistNever\" android:process=\"com.contoso.process.testactivity_process\" android:recreateOnConfigChanges=\"mcc\" android:relinquishTaskIdentity=\"true\" android:resizeableActivity=\"true\" android:resumeWhilePausing=\"true\" android:rotationAnimation=\"crossfade\" android:roundIcon=\"@drawable/icon\" android:screenOrientation=\"portrait\" android:showForAllUsers=\"true\" android:showOnLockScreen=\"true\" android:showWhenLocked=\"true\" android:singleUser=\"true\" android:stateNotNeeded=\"true\" android:supportsPictureInPicture=\"true\" android:taskAffinity=\"com.contoso\" android:theme=\"@android:style/Theme.Light\" android:turnScreenOn=\"true\" android:uiOptions=\"splitActionBarWhenNarrow\" android:visibleToInstantApps=\"true\" android:windowSoftInputMode=\"stateUnchanged|adjustUnspecified\""; var proj = new XamarinAndroidApplicationProject { ManifestMerger = manifestMerger, }; proj.Sources.Add(new BuildItem.Source("TestActivity.cs") { TextContent = () => @"using Android.App; using Android.Content.PM; using Android.Views; [Activity ( AllowEmbedded = true, AllowTaskReparenting = true, AlwaysRetainTaskState = true, AutoRemoveFromRecents = true, Banner = ""@drawable/icon"", ClearTaskOnLaunch = true, ColorMode = ""hdr"", ConfigurationChanges = ConfigChanges.Mcc, Description = ""@string/app_name"", DirectBootAware = true, DocumentLaunchMode = DocumentLaunchMode.Never, Enabled = true, EnableVrMode = ""foo"", ExcludeFromRecents = true, Exported = true, FinishOnCloseSystemDialogs = true, FinishOnTaskLaunch = true, HardwareAccelerated = true, Icon = ""@drawable/icon"", Immersive = true, Label = ""TestActivity"", LaunchMode = LaunchMode.SingleTop, LockTaskMode = ""normal"", Logo = ""@drawable/icon"", MaxAspectRatio = 1.2F, MaxRecents = 1, MultiProcess = true, Name = ""com.contoso.TestActivity"", NoHistory = true, ParentActivity = typeof (UnnamedProject.MainActivity), Permission = ""com.contoso.permission.TEST_ACTIVITY"", PersistableMode = ActivityPersistableMode.Never, Process = ""com.contoso.process.testactivity_process"", RecreateOnConfigChanges = ConfigChanges.Mcc, RelinquishTaskIdentity = true, ResizeableActivity = true, ResumeWhilePausing = true, RotationAnimation = WindowRotationAnimation.Crossfade, RoundIcon = ""@drawable/icon"", ScreenOrientation = ScreenOrientation.Portrait, ShowForAllUsers = true, ShowOnLockScreen = true, ShowWhenLocked = true, SingleUser = true, StateNotNeeded = true, SupportsPictureInPicture = true, TaskAffinity = ""com.contoso"", Theme = ""@android:style/Theme.Light"", TurnScreenOn = true, UiOptions = UiOptions.SplitActionBarWhenNarrow, VisibleToInstantApps = true, WindowSoftInputMode = Android.Views.SoftInput.StateUnchanged)] class TestActivity : Activity { }" }); using (ProjectBuilder builder = CreateDllBuilder(Path.Combine("temp", TestName))) { Assert.IsTrue(builder.Build(proj), "Build should have succeeded"); string manifest = builder.Output.GetIntermediaryAsText(Path.Combine("android", "AndroidManifest.xml")); var doc = XDocument.Parse(manifest); var ns = XNamespace.Get("http://schemas.android.com/apk/res/android"); IEnumerable <XElement> activities = doc.Element("manifest")?.Element("application")?.Elements("activity"); XElement e = activities.FirstOrDefault(x => x.Attribute(ns.GetName("label"))?.Value == "TestActivity"); Assert.IsNotNull(e, "Manifest should contain an activity labeled TestActivity"); Assert.AreEqual(expectedOutput, string.Join(" ", e.Attributes())); } }
public void BuildBasicApplicationCheckPdb() { var proj = new XamarinAndroidApplicationProject(); using (var b = CreateApkBuilder("temp/BuildBasicApplicationCheckPdb", false, false)) { b.Verbosity = LoggerVerbosity.Diagnostic; var reference = new BuildItem.Reference("PdbTestLibrary.dll") { WebContent = "https://dl.dropboxusercontent.com/u/18881050/Xamarin/PdbTestLibrary.dll" }; proj.References.Add(reference); var pdb = new BuildItem.NoActionResource("PdbTestLibrary.pdb") { WebContent = "https://dl.dropboxusercontent.com/u/18881050/Xamarin/PdbTestLibrary.pdb" }; proj.References.Add(pdb); var netStandardRef = new BuildItem.Reference("NetStandard16.dll") { WebContent = "https://dl.dropboxusercontent.com/u/18881050/Xamarin/NetStandard16.dll" }; proj.References.Add(netStandardRef); var netStandardpdb = new BuildItem.NoActionResource("NetStandard16.pdb") { WebContent = "https://dl.dropboxusercontent.com/u/18881050/Xamarin/NetStandard16.pdb" }; proj.References.Add(netStandardpdb); Assert.IsTrue(b.Build(proj), "Build should have succeeded."); var pdbToMdbPath = Path.Combine(Root, b.ProjectDirectory, "PdbTestLibrary.dll.mdb"); Assert.IsTrue( File.Exists(pdbToMdbPath), "PdbTestLibrary.dll.mdb must be generated next to the .pdb"); Assert.IsTrue( File.Exists(Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "assets", "UnnamedProject.dll.mdb")), "UnnamedProject.dll.mdb must be copied to the Intermediate directory"); Assert.IsFalse( File.Exists(Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "assets", "PdbTestLibrary.pdb")), "PdbTestLibrary.pdb must not be copied to Intermediate directory"); Assert.IsTrue( File.Exists(Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "assets", "PdbTestLibrary.dll.mdb")), "PdbTestLibrary.dll.mdb must be copied to Intermediate directory"); FileAssert.AreNotEqual(pdbToMdbPath, Path.Combine(Root, b.ProjectDirectory, "PdbTestLibrary.pdb"), "The .pdb should NOT match the .mdb"); Assert.IsTrue( File.Exists(Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "assets", "NetStandard16.pdb")), "NetStandard16.pdb must be copied to Intermediate directory"); var apk = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "bin", "UnnamedProject.UnnamedProject.apk"); using (var zipFile = ZipHelper.OpenZip(apk)) { Assert.IsNotNull(ZipHelper.ReadFileFromZip(zipFile, "assemblies/NetStandard16.pdb"), "assemblies/NetStandard16.pdb should exist in the apk."); Assert.IsNotNull(ZipHelper.ReadFileFromZip(zipFile, "assemblies/PdbTestLibrary.dll.mdb"), "assemblies/PdbTestLibrary.dll.mdb should exist in the apk."); Assert.IsNull(ZipHelper.ReadFileFromZip(zipFile, "assemblies/PdbTestLibrary.pdb"), "assemblies/PdbTestLibrary.pdb should not exist in the apk."); } Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true), "second build failed"); Assert.IsTrue( b.LastBuildOutput.Contains("Skipping target \"_CopyMdbFiles\" because"), "the _CopyMdbFiles target should be skipped"); var lastTime = File.GetLastAccessTimeUtc(pdbToMdbPath); pdb.Timestamp = DateTime.UtcNow; Assert.IsTrue(b.Build(proj, doNotCleanupOnUpdate: true), "third build failed"); Assert.IsFalse( b.LastBuildOutput.Contains("Skipping target \"_CopyMdbFiles\" because"), "the _CopyMdbFiles target should not be skipped"); Assert.Less(lastTime, File.GetLastAccessTimeUtc(pdbToMdbPath), "{0} should have been updated", pdbToMdbPath); } }
public void WarnAboutAppDomainsDebug() { var proj = new XamarinAndroidApplicationProject(); WarnAboutAppDomains(proj, TestName); }
public void CheckTheCorrectRuntimeAssemblyIsUsedFromNuget() { string monoandroidFramework; using (var builder = new Builder()) { monoandroidFramework = builder.LatestMultiTargetFrameworkVersion(); } string path = Path.Combine(Root, "temp", TestName); var ns = new DotNetStandard() { ProjectName = "Dummy", Sdk = "MSBuild.Sdk.Extras/2.0.54", Sources = { new BuildItem.Source("Class1.cs") { TextContent = () => @"public class Class1 { #if __ANDROID__ public static string Library => ""Android""; #else public static string Library => "".NET Standard""; #endif }", }, }, OtherBuildItems = { new BuildItem.NoActionResource("$(OutputPath)netstandard2.0\\$(AssemblyName).dll") { TextContent = null, BinaryContent = null, Metadata = { { "PackagePath", "ref\\netstandard2.0" }, { "Pack", "True" } }, }, new BuildItem.NoActionResource($"$(OutputPath){monoandroidFramework}\\$(AssemblyName).dll") { TextContent = null, BinaryContent = null, Metadata = { { "PackagePath", $"lib\\{monoandroidFramework}" }, { "Pack", "True" } }, }, }, }; ns.SetProperty("TargetFrameworks", $"netstandard2.0;{monoandroidFramework}"); ns.SetProperty("PackageId", "dummy.package.foo"); ns.SetProperty("PackageVersion", "1.0.0"); ns.SetProperty("GeneratePackageOnBuild", "True"); ns.SetProperty("IncludeBuildOutput", "False"); ns.SetProperty("Summary", "Test"); ns.SetProperty("Description", "Test"); ns.SetProperty("PackageOutputPath", path); var xa = new XamarinAndroidApplicationProject() { ProjectName = "App", PackageReferences = { new Package() { Id = "dummy.package.foo", Version = "1.0.0", }, }, OtherBuildItems = { new BuildItem.NoActionResource("NuGet.config") { }, }, }; xa.SetProperty("RestoreNoCache", "true"); xa.SetProperty("RestorePackagesPath", "$(MSBuildThisFileDirectory)packages"); using (var nsb = CreateDllBuilder(Path.Combine(path, ns.ProjectName), cleanupAfterSuccessfulBuild: false, cleanupOnDispose: false)) using (var xab = CreateApkBuilder(Path.Combine(path, xa.ProjectName), cleanupAfterSuccessfulBuild: false, cleanupOnDispose: false)) { nsb.ThrowOnBuildFailure = xab.ThrowOnBuildFailure = false; Assert.IsTrue(nsb.Build(ns), "Build of NetStandard Library should have succeeded."); Assert.IsFalse(xab.Build(xa, doNotCleanupOnUpdate: true), "Build of App Library should have failed."); File.WriteAllText(Path.Combine(Root, xab.ProjectDirectory, "NuGet.config"), @"<?xml version='1.0' encoding='utf-8'?> <configuration> <packageSources> <add key='nuget.org' value='https://api.nuget.org/v3/index.json' protocolVersion='3' /> <add key='bug-testing' value='..' /> </packageSources> </configuration>"); Assert.IsTrue(xab.Build(xa, doNotCleanupOnUpdate: true), "Build of App Library should have succeeded."); string expected = Path.Combine("dummy.package.foo", "1.0.0", "lib", monoandroidFramework, "Dummy.dll"); Assert.IsTrue(xab.LastBuildOutput.ContainsText(expected), $"Build should be using {expected}"); } }
public void NetStandardReferenceTest() { var netStandardProject = new DotNetStandard() { Language = XamarinAndroidProjectLanguage.CSharp, ProjectName = "XamFormsSample", ProjectGuid = Guid.NewGuid().ToString(), Sdk = "Microsoft.NET.Sdk", TargetFramework = "netstandard1.4", IsRelease = true, PackageTargetFallback = "portable-net45+win8+wpa81+wp8", PackageReferences = { KnownPackages.XamarinFormsPCL_2_3_4_231, new Package() { Id = "System.IO.Packaging", Version = "4.4.0", }, new Package() { Id = "Newtonsoft.Json", Version = "10.0.3" }, }, OtherBuildItems = { new BuildItem("None") { Remove = () => "**\\*.xaml", }, new BuildItem("Compile") { Update = () => "**\\*.xaml.cs", DependentUpon = () => "%(Filename)" }, new BuildItem("EmbeddedResource") { Include = () => "**\\*.xaml", SubType = () => "Designer", Generator = () => "MSBuild:UpdateDesignTimeXaml", }, }, Sources = { new BuildItem.Source("App.xaml.cs") { TextContent = () => @"using System; using System.Collections.Generic; using System.Linq; using System.Text; using Newtonsoft.Json; using System.IO.Packaging; using Xamarin.Forms; namespace XamFormsSample { public partial class App : Application { Package package; public App() { JsonConvert.DeserializeObject<string>(""test""); package = Package.Open (""""); InitializeComponent(); } protected override void OnStart() { // Handle when your app starts } protected override void OnSleep() { // Handle when your app sleeps } protected override void OnResume() { // Handle when your app resumes } } }", }, new BuildItem.Source("App.xaml") { TextContent = () => @"<?xml version=""1.0"" encoding=""utf-8"" ?> <Application xmlns=""http://xamarin.com/schemas/2014/forms"" xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml"" x:Class=""XamFormsSample.App""> <Application.Resources> <!-- Application resource dictionary --> </Application.Resources> </Application>", }, }, }; var app = new XamarinAndroidApplicationProject() { ProjectName = "App1", IsRelease = true, UseLatestPlatformSdk = true, References = { new BuildItem.Reference("Mono.Android.Export"), new BuildItem.ProjectReference($"..\\{netStandardProject.ProjectName}\\{netStandardProject.ProjectName}.csproj", netStandardProject.ProjectName, netStandardProject.ProjectGuid), }, PackageReferences = { KnownPackages.SupportDesign_25_4_0_1, KnownPackages.SupportV7CardView_24_2_1, KnownPackages.AndroidSupportV4_25_4_0_1, KnownPackages.SupportCoreUtils_25_4_0_1, KnownPackages.SupportMediaCompat_25_4_0_1, KnownPackages.SupportFragment_25_4_0_1, KnownPackages.SupportCoreUI_25_4_0_1, KnownPackages.SupportCompat_25_4_0_1, KnownPackages.SupportV7AppCompat_25_4_0_1, KnownPackages.XamarinForms_2_3_4_231, } }; app.SetProperty(KnownProperties.AndroidSupportedAbis, "x86;armeabi-v7a"); var expectedFiles = new string [] { "Java.Interop.dll", "Mono.Android.dll", "mscorlib.dll", "System.Core.dll", "System.dll", "System.Runtime.Serialization.dll", "System.IO.Packaging.dll", "Mono.Android.Export.dll", "App1.dll", "FormsViewGroup.dll", "Xamarin.Android.Support.Compat.dll", "Xamarin.Android.Support.Core.UI.dll", "Xamarin.Android.Support.Core.Utils.dll", "Xamarin.Android.Support.Design.dll", "Xamarin.Android.Support.Fragment.dll", "Xamarin.Android.Support.Media.Compat.dll", "Xamarin.Android.Support.v4.dll", "Xamarin.Android.Support.v7.AppCompat.dll", "Xamarin.Android.Support.Animated.Vector.Drawable.dll", "Xamarin.Android.Support.Vector.Drawable.dll", "Xamarin.Android.Support.Transition.dll", "Xamarin.Android.Support.v7.MediaRouter.dll", "Xamarin.Android.Support.v7.RecyclerView.dll", "Xamarin.Android.Support.Annotations.dll", "Xamarin.Android.Support.v7.CardView.dll", "Xamarin.Forms.Core.dll", "Xamarin.Forms.Platform.Android.dll", "Xamarin.Forms.Platform.dll", "Xamarin.Forms.Xaml.dll", "XamFormsSample.dll", "Mono.Security.dll", "System.Xml.dll", "System.Net.Http.dll", "System.ServiceModel.Internals.dll", "Newtonsoft.Json.dll", "Microsoft.CSharp.dll", "System.Numerics.dll", "System.Xml.Linq.dll", }; var path = Path.Combine("temp", TestContext.CurrentContext.Test.Name); using (var builder = CreateDllBuilder(Path.Combine(path, netStandardProject.ProjectName), cleanupOnDispose: false)) { if (!Directory.Exists(builder.MicrosoftNetSdkDirectory)) { Assert.Ignore("Microsoft.NET.Sdk not found."); } using (var ab = CreateApkBuilder(Path.Combine(path, app.ProjectName), cleanupOnDispose: false)) { builder.RequiresMSBuild = true; builder.Target = "Restore"; Assert.IsTrue(builder.Build(netStandardProject), "XamFormsSample Nuget packages should have been restored."); builder.Target = "Build"; Assert.IsTrue(builder.Build(netStandardProject), "XamFormsSample should have built."); ab.RequiresMSBuild = true; ab.Target = "Restore"; Assert.IsTrue(ab.Build(app), "App should have built."); ab.Target = "SignAndroidPackage"; Assert.IsTrue(ab.Build(app), "App should have built."); var apk = Path.Combine(Root, ab.ProjectDirectory, app.IntermediateOutputPath, "android", "bin", "UnnamedProject.UnnamedProject.apk"); using (var zip = ZipHelper.OpenZip(apk)) { var existingFiles = zip.Where(a => a.FullName.StartsWith("assemblies/", StringComparison.InvariantCultureIgnoreCase)); var missingFiles = expectedFiles.Where(x => !zip.ContainsEntry("assemblies/" + Path.GetFileName(x))); Assert.IsFalse(missingFiles.Any(), string.Format("The following Expected files are missing. {0}", string.Join(Environment.NewLine, missingFiles))); var additionalFiles = existingFiles.Where(x => !expectedFiles.Contains(Path.GetFileName(x.FullName))); Assert.IsTrue(!additionalFiles.Any(), string.Format("Unexpected Files found! {0}", string.Join(Environment.NewLine, additionalFiles.Select(x => x.FullName)))); } if (!HasDevices) { Assert.Ignore("Skipping Installation. No devices available."); } ab.Target = "Install"; Assert.IsTrue(ab.Build(app), "App should have installed."); } } }
public void GetExtraLibraryLocationsForDesigner() { var target = "GetExtraLibraryLocationsForDesigner"; var proj = new XamarinAndroidApplicationProject() { PackageReferences = { KnownPackages.SupportMediaCompat_27_0_2_1, KnownPackages.SupportFragment_27_0_2_1, KnownPackages.SupportCoreUtils_27_0_2_1, KnownPackages.SupportCoreUI_27_0_2_1, KnownPackages.SupportCompat_27_0_2_1, KnownPackages.AndroidSupportV4_27_0_2_1, KnownPackages.SupportV7AppCompat_27_0_2_1, }, }; string jar = "gson-2.7.jar"; proj.OtherBuildItems.Add(new BuildItem("AndroidJavaLibrary", jar) { WebContent = $"https://repo1.maven.org/maven2/com/google/code/gson/gson/2.7/{jar}" }); proj.OtherBuildItems.Add(new AndroidItem.AndroidAarLibrary("android-crop-1.0.1.aar") { WebContent = "https://jcenter.bintray.com/com/soundcloud/android/android-crop/1.0.1/android-crop-1.0.1.aar" }); // Each NuGet package and AAR file are in libraryprojectimports.cache, AndroidJavaSource is not int libraryProjectImportsJars = 14; using (var b = CreateApkBuilder(Path.Combine("temp", TestName), false, false)) { // GetExtraLibraryLocationsForDesigner on new project Assert.IsTrue(b.RunTarget(proj, target, parameters: DesignerParameters), $"build should have succeeded for target `{target}` 1"); // GetExtraLibraryLocationsForDesigner after DTB Assert.IsTrue(b.DesignTimeBuild(proj), "design-time build should have succeeded"); var resourcepathscache = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "designtime", "libraryprojectimports.cache"); FileAssert.Exists(resourcepathscache); var expected = XDocument.Load(resourcepathscache); Assert.AreEqual(libraryProjectImportsJars, expected.Root.Element("Jars").Elements("Jar").Count()); Assert.IsTrue(b.RunTarget(proj, target, parameters: DesignerParameters), $"build should have succeeded for target `{target}` 2"); AssertJarInBuildOutput(b, "ExtraJarLocation", jar); // GetExtraLibraryLocationsForDesigner after SetupDependenciesForDesigner var setup = "SetupDependenciesForDesigner"; Assert.IsTrue(b.RunTarget(proj, setup, parameters: DesignerParameters), $"build should have succeeded for target `{setup}`"); Assert.IsTrue(b.RunTarget(proj, target, parameters: DesignerParameters), $"build should have succeeded for target `{target}` 3"); AssertJarInBuildOutput(b, "ExtraJarLocation", jar); FileAssert.Exists(resourcepathscache); var actual = XDocument.Load(resourcepathscache); Assert.AreEqual(libraryProjectImportsJars, actual.Root.Element("Jars").Elements("Jar").Count()); Assert.AreEqual(expected.ToString(), actual.ToString(), "libraryprojectimports.cache should not change!"); // GetExtraLibraryLocationsForDesigner after Build Assert.IsTrue(b.Build(proj), "build should have succeeded"); Assert.IsTrue(b.RunTarget(proj, target, parameters: DesignerParameters), $"build should have succeeded for target `{target}` 4"); AssertJarInBuildOutput(b, "ExtraJarLocation", jar); FileAssert.Exists(resourcepathscache); actual = XDocument.Load(resourcepathscache); Assert.AreEqual(libraryProjectImportsJars, actual.Root.Element("Jars").Elements("Jar").Count()); Assert.AreEqual(expected.ToString(), actual.ToString(), "libraryprojectimports.cache should not change!"); } }
public void BindingCheckHiddenFiles([Values(true, false)] bool useShortFileNames) { var binding = new XamarinAndroidBindingProject() { UseLatestPlatformSdk = true, IsRelease = true, }; binding.AndroidClassParser = "class-parse"; binding.Jars.Add(new AndroidItem.LibraryProjectZip("Jars\\mylibrary.aar") { WebContentFileNameFromAzure = "mylibrary.aar" }); binding.Jars.Add(new AndroidItem.EmbeddedJar("Jars\\svg-android.jar") { WebContentFileNameFromAzure = "javaBindingIssue.jar" }); var path = Path.Combine("temp", TestContext.CurrentContext.Test.Name); binding.SetProperty(binding.ActiveConfigurationProperties, "UseShortFileNames", useShortFileNames); using (var bindingBuilder = CreateDllBuilder(Path.Combine(path, "Binding"))) { bindingBuilder.Verbosity = Microsoft.Build.Framework.LoggerVerbosity.Diagnostic; Assert.IsTrue(bindingBuilder.Build(binding), "binding build should have succeeded"); var proj = new XamarinAndroidApplicationProject(); proj.OtherBuildItems.Add(new BuildItem("ProjectReference", "..\\Binding\\UnnamedProject.csproj")); proj.SetProperty(proj.ActiveConfigurationProperties, "UseShortFileNames", useShortFileNames); proj.AndroidManifest = $@"<?xml version=""1.0"" encoding=""utf-8""?> <manifest xmlns:android=""http://schemas.android.com/apk/res/android"" xmlns:tools=""http://schemas.android.com/tools"" android:versionCode=""1"" android:versionName=""1.0"" package=""{proj.PackageName}""> <uses-sdk /> <application android:label=""{proj.ProjectName}"" tools:replace=""android:label""> </application> </manifest>"; using (var b = CreateApkBuilder(Path.Combine(path, "App"))) { Assert.IsTrue(b.Build(proj), "Build should have succeeded."); var assemblyMap = b.Output.GetIntermediaryPath(Path.Combine("lp", "map.cache")); if (useShortFileNames) { Assert.IsTrue(File.Exists(assemblyMap), $"{assemblyMap} should exist."); } else { Assert.IsFalse(File.Exists(assemblyMap), $"{assemblyMap} should not exist."); } var assemblyIdentityMap = new List <string> (); if (useShortFileNames) { foreach (var s in File.ReadLines(assemblyMap)) { assemblyIdentityMap.Add(s); } } var assmeblyIdentity = useShortFileNames ? assemblyIdentityMap.IndexOf("UnnamedProject").ToString() : "UnnamedProject"; var libaryImportsFolder = useShortFileNames ? "lp" : "__library_projects__"; var jlibs = useShortFileNames ? "jl" : "library_project_imports"; var dsStorePath = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, libaryImportsFolder, assmeblyIdentity, jlibs); Assert.IsTrue(Directory.Exists(dsStorePath), "{0} should exist.", dsStorePath); Assert.IsFalse(File.Exists(Path.Combine(dsStorePath, ".DS_Store")), "{0} should NOT exist.", Path.Combine(dsStorePath, ".DS_Store")); var _macOSStorePath = Path.Combine(dsStorePath, "_MACOSX"); Assert.IsFalse(Directory.Exists(_macOSStorePath), "{0} should NOT exist.", _macOSStorePath); var svgJar = Path.Combine(dsStorePath, "svg-android.jar"); Assert.IsTrue(File.Exists(svgJar), $"{svgJar} should exist."); } } }
public void ClassLibraryMainLauncherRuns([Values(true, false)] bool preloadAssemblies) { AssertHasDevices(); var path = Path.Combine("temp", TestName); var app = new XamarinAndroidApplicationProject { ProjectName = "MyApp", }; if (!CommercialBuildAvailable) { app.SetAndroidSupportedAbis("armeabi-v7a", "x86"); } app.SetDefaultTargetDevice(); app.SetProperty("AndroidEnablePreloadAssemblies", preloadAssemblies.ToString()); var lib = new XamarinAndroidLibraryProject { ProjectName = "MyLibrary" }; lib.Sources.Add(new BuildItem.Source("MainActivity.cs") { TextContent = () => lib.ProcessSourceTemplate(app.DefaultMainActivity).Replace("${JAVA_PACKAGENAME}", app.JavaPackageName), }); lib.AndroidResources.Clear(); foreach (var resource in app.AndroidResources) { lib.AndroidResources.Add(resource); } var reference = $"..\\{lib.ProjectName}\\{lib.ProjectName}.csproj"; app.References.Add(new BuildItem.ProjectReference(reference, lib.ProjectName, lib.ProjectGuid)); // Remove the default MainActivity.cs & AndroidResources app.AndroidResources.Clear(); app.AndroidResources.Add(new AndroidItem.AndroidResource("Resources\\layout\\foo.xml") { TextContent = () => @"<?xml version=""1.0"" encoding=""utf-8""?> <LinearLayout xmlns:android=""http://schemas.android.com/apk/res/android"" android:layout_width=""fill_parent"" android:layout_height=""wrap_content"" />" }); app.Sources.Remove(app.GetItem("MainActivity.cs")); using (var libBuilder = CreateDllBuilder(Path.Combine(path, lib.ProjectName))) using (var appBuilder = CreateApkBuilder(Path.Combine(path, app.ProjectName))) { SetTargetFrameworkAndManifest(app, appBuilder); Assert.IsTrue(libBuilder.Build(lib), "library build should have succeeded."); Assert.True(appBuilder.Install(app), "app should have installed."); ClearAdbLogcat(); appBuilder.BuildLogFile = "run.log"; if (CommercialBuildAvailable) { Assert.True(appBuilder.RunTarget(app, "_Run"), "Project should have run."); } else { AdbStartActivity($"{app.PackageName}/{app.JavaPackageName}.MainActivity"); } Assert.True(WaitForActivityToStart(app.PackageName, "MainActivity", Path.Combine(Root, appBuilder.ProjectDirectory, "logcat.log"), 30), "Activity should have started."); } }
public void CustomDesignerTargetSetupDependenciesForDesigner() { var target = "SetupDependenciesForDesigner"; var path = Path.Combine("temp", "SetupDependenciesForDesigner"); var lib = new XamarinAndroidLibraryProject() { ProjectName = "Library1", OtherBuildItems = { new AndroidItem.AndroidAsset("Assets\\foo.txt") { TextContent = () => "bar", }, }, }; var proj = new XamarinAndroidApplicationProject() { PackageReferences = { KnownPackages.SupportMediaCompat_27_0_2_1, KnownPackages.SupportFragment_27_0_2_1, KnownPackages.SupportCoreUtils_27_0_2_1, KnownPackages.SupportCoreUI_27_0_2_1, KnownPackages.SupportCompat_27_0_2_1, KnownPackages.AndroidSupportV4_27_0_2_1, KnownPackages.SupportV7AppCompat_27_0_2_1, }, References = { new BuildItem("ProjectReference", "..\\Library1\\Library1.csproj") }, Imports = { new Import("foo.targets") { TextContent = () => @"<?xml version=""1.0"" encoding=""utf-16""?> <Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003""> <PropertyGroup> <BeforeGenerateAndroidManifest> $(BeforeGenerateAndroidManifest); _Foo; </BeforeGenerateAndroidManifest> </PropertyGroup> <Target Name=""_Foo""> </Target> </Project> " }, }, }; proj.Sources.Add(new BuildItem.Source("CustomTextView.cs") { TextContent = () => @"using Android.Widget; using Android.Content; using Android.Util; namespace UnnamedProject { public class CustomTextView : TextView { public CustomTextView(Context context, IAttributeSet attributes) : base(context, attributes) { } } }" }); proj.AndroidResources.Add(new AndroidItem.AndroidResource("Resources\\layout\\custom_text.xml") { TextContent = () => @"<?xml version=""1.0"" encoding=""utf-8"" ?> <LinearLayout xmlns:android=""http://schemas.android.com/apk/res/android"" android:orientation = ""vertical"" android:layout_width = ""fill_parent"" android:layout_height = ""fill_parent""> <UnnamedProject.CustomTextView android:id = ""@+id/myText1"" android:layout_width = ""fill_parent"" android:layout_height = ""wrap_content"" android:text = ""namespace_lower"" /> <unnamedproject.CustomTextView android:id = ""@+id/myText2"" android:layout_width = ""fill_parent"" android:layout_height = ""wrap_content"" android:text = ""namespace_proper"" /> </LinearLayout>" }); using (var libb = CreateDllBuilder(Path.Combine(path, lib.ProjectName), false, false)) using (var appb = CreateApkBuilder(Path.Combine(path, proj.ProjectName), false, false)) { // Save the library project, but don't build it yet libb.Save(lib); appb.Target = target; Assert.IsTrue(appb.Build(proj, parameters: DesignerParameters), $"build should have succeeded for target `{target}`"); Assert.IsTrue(appb.Output.AreTargetsAllBuilt("_UpdateAndroidResgen"), "_UpdateAndroidResgen should have run completely."); Assert.IsTrue(appb.Output.AreTargetsAllBuilt("_Foo"), "_Foo should have run completely"); var customViewPath = Path.Combine(Root, appb.ProjectDirectory, proj.IntermediateOutputPath, "res", "layout", "custom_text.xml"); Assert.IsTrue(File.Exists(customViewPath), $"custom_text.xml should exist at {customViewPath}"); var doc = XDocument.Load(customViewPath); Assert.IsNotNull(doc.Element("LinearLayout").Element("UnnamedProject.CustomTextView"), "UnnamedProject.CustomTextView should have not been replaced with a $(Hash).CustomTextView"); Assert.IsNotNull(doc.Element("LinearLayout").Element("unnamedproject.CustomTextView"), "unnamedproject.CustomTextView should have not been replaced with a $(Hash).CustomTextView"); // Build the library project now Assert.IsTrue(libb.Build(lib), "library build should have succeeded."); appb.Target = "Build"; Assert.IsTrue(appb.Build(proj), "app build should have succeeded."); Assert.IsTrue(appb.Output.AreTargetsAllBuilt("_UpdateAndroidResgen"), "_UpdateAndroidResgen should have run completely."); Assert.IsTrue(appb.Output.AreTargetsAllBuilt("_Foo"), "_Foo should have run completely"); doc = XDocument.Load(customViewPath); Assert.IsNull(doc.Element("LinearLayout").Element("UnnamedProject.CustomTextView"), "UnnamedProject.CustomTextView should have been replaced with a $(Hash).CustomTextView"); Assert.IsNull(doc.Element("LinearLayout").Element("unnamedproject.CustomTextView"), "unnamedproject.CustomTextView should have been replaced with a $(Hash).CustomTextView"); appb.Target = target; Assert.IsTrue(appb.Build(proj, parameters: DesignerParameters), $"build should have succeeded for target `{target}`"); Assert.IsTrue(appb.Output.AreTargetsAllSkipped("_UpdateAndroidResgen"), "_UpdateAndroidResgen should have been skipped."); Assert.IsTrue(appb.Output.AreTargetsAllBuilt("_Foo"), "_Foo should have run completely"); doc = XDocument.Load(customViewPath); Assert.IsNull(doc.Element("LinearLayout").Element("UnnamedProject.CustomTextView"), "UnnamedProject.CustomTextView should have been replaced with a $(Hash).CustomTextView"); Assert.IsNull(doc.Element("LinearLayout").Element("unnamedproject.CustomTextView"), "unnamedproject.CustomTextView should have been replaced with a $(Hash).CustomTextView"); } }
public void CustomApplicationRunsWithDebuggerAndBreaks(bool embedAssemblies, string fastDevType, bool activityStarts) { AssertCommercialBuild(); AssertHasDevices(); var proj = new XamarinAndroidApplicationProject() { IsRelease = false, AndroidFastDeploymentType = fastDevType, }; proj.SetAndroidSupportedAbis("armeabi-v7a", "x86"); proj.SetProperty("EmbedAssembliesIntoApk", embedAssemblies.ToString()); proj.SetDefaultTargetDevice(); proj.Sources.Add(new BuildItem.Source("MyApplication.cs") { TextContent = () => proj.ProcessSourceTemplate(@"using System; using Android.App; using Android.OS; using Android.Runtime; using Android.Widget; namespace ${ROOT_NAMESPACE} { [Application] public class MyApplication : Application { public MyApplication (IntPtr handle, JniHandleOwnership jniHandle) : base (handle, jniHandle) { } public override void OnCreate () { base.OnCreate (); } } } "), }); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { SetTargetFrameworkAndManifest(proj, b); Assert.True(b.Install(proj), "Project should have installed."); int breakcountHitCount = 0; ManualResetEvent resetEvent = new ManualResetEvent(false); var sw = new Stopwatch(); // setup the debugger var session = new SoftDebuggerSession(); session.Breakpoints = new BreakpointStore { { Path.Combine(Root, b.ProjectDirectory, "MainActivity.cs"), 19 }, { Path.Combine(Root, b.ProjectDirectory, "MyApplication.cs"), 17 }, }; session.TargetHitBreakpoint += (sender, e) => { TestContext.WriteLine($"BREAK {e.Type}, {e.Backtrace.GetFrame (0)}"); breakcountHitCount++; session.Continue(); }; var rnd = new Random(); int port = rnd.Next(10000, 20000); TestContext.Out.WriteLine($"{port}"); var args = new SoftDebuggerConnectArgs("", IPAddress.Loopback, port) { MaxConnectionAttempts = 10, }; var startInfo = new SoftDebuggerStartInfo(args) { WorkingDirectory = Path.Combine(b.ProjectDirectory, proj.IntermediateOutputPath, "android", "assets"), }; var options = new DebuggerSessionOptions() { EvaluationOptions = EvaluationOptions.DefaultOptions, }; options.EvaluationOptions.UseExternalTypeResolver = true; ClearAdbLogcat(); b.BuildLogFile = "run.log"; Assert.True(b.RunTarget(proj, "_Run", doNotCleanupOnUpdate: true, parameters: new string [] { $"AndroidSdbTargetPort={port}", $"AndroidSdbHostPort={port}", "AndroidAttachDebugger=True", }), "Project should have run."); // do we expect the app to start? Assert.AreEqual(activityStarts, WaitForDebuggerToStart(Path.Combine(Root, b.ProjectDirectory, "logcat.log")), "Activity should have started"); if (!activityStarts) { return; } // we need to give a bit of time for the debug server to start up. WaitFor(2000); session.LogWriter += (isStderr, text) => { Console.WriteLine(text); }; session.OutputWriter += (isStderr, text) => { Console.WriteLine(text); }; session.DebugWriter += (level, category, message) => { Console.WriteLine(message); }; session.Run(startInfo, options); var expectedTime = TimeSpan.FromSeconds(1); var actualTime = ProfileFor(() => session.IsConnected); TestContext.Out.WriteLine($"Debugger connected in {actualTime}"); Assert.LessOrEqual(actualTime, expectedTime, $"Debugger should have connected within {expectedTime} but it took {actualTime}."); // we need to wait here for a while to allow the breakpoints to hit // but we need to timeout TimeSpan timeout = TimeSpan.FromSeconds(60); while (session.IsConnected && breakcountHitCount < 2 && timeout >= TimeSpan.Zero) { Thread.Sleep(10); timeout = timeout.Subtract(TimeSpan.FromMilliseconds(10)); } WaitFor(2000); int expected = 2; Assert.AreEqual(expected, breakcountHitCount, $"Should have hit {expected} breakpoints. Only hit {breakcountHitCount}"); b.BuildLogFile = "uninstall.log"; Assert.True(b.Uninstall(proj), "Project should have uninstalled."); session.Exit(); } }
public void JsonDeserializationCreatesJavaHandle([Values(false, true)] bool isRelease) { AssertHasDevices(); proj = new XamarinAndroidApplicationProject() { IsRelease = isRelease, }; if (isRelease || !CommercialBuildAvailable) { proj.SetAndroidSupportedAbis("armeabi-v7a", "arm64-v8a", "x86"); } proj.References.Add(new BuildItem.Reference("System.Runtime.Serialization")); if (Builder.UseDotNet) { // serialization is broken on net6 when the app is linked. enable again once it is fixed if (isRelease) { return; } proj.References.Add(new BuildItem.Reference("System.Runtime.Serialization.Json")); proj.References.Add(new BuildItem.Reference("System.Runtime.Serialization.Formatters")); } proj.MainActivity = proj.DefaultMainActivity.Replace("//${AFTER_ONCREATE}", @"TestJsonDeserializationCreatesJavaHandle(); } void TestJsonDeserialization (Person p) { var stream = new MemoryStream (); var serializer = new DataContractJsonSerializer (typeof (Person)); serializer.WriteObject (stream, p); stream.Position = 0; StreamReader sr = new StreamReader (stream); Console.WriteLine ($""JSON Person representation: {sr.ReadToEnd ()}""); stream.Position = 0; Person p2 = (Person) serializer.ReadObject (stream); Console.WriteLine ($""JSON Person parsed: Name '{p2.Name}' Age '{p2.Age}' Handle '0x{p2.Handle:X}'""); if (p2.Name != ""John Smith"") throw new InvalidOperationException (""JSON deserialization of Name""); if (p2.Age != 900) throw new InvalidOperationException (""JSON deserialization of Age""); if (p2.Handle == IntPtr.Zero) throw new InvalidOperationException (""Failed to instantiate new Java instance for Person!""); Console.WriteLine ($""JSON Person deserialized OK""); } void TestBinaryDeserialization (Person p) { var stream = new MemoryStream (); var serializer = new BinaryFormatter(); serializer.Serialize (stream, p); stream.Position = 0; StreamReader sr = new StreamReader (stream); stream.Position = 0; serializer.Binder = new Person.Binder (); Person p2 = (Person) serializer.Deserialize (stream); Console.WriteLine ($""BinaryFormatter deserialzied: Name '{p2.Name}' Age '{p2.Age}' Handle '0x{p2.Handle:X}'""); if (p2.Name != ""John Smith"") throw new InvalidOperationException (""BinaryFormatter deserialization of Name""); if (p2.Age != 900) throw new InvalidOperationException (""BinaryFormatter deserialization of Age""); if (p2.Handle == IntPtr.Zero) throw new InvalidOperationException (""Failed to instantiate new Java instance for Person!""); Console.WriteLine ($""BinaryFormatter Person deserialized OK""); } void TestJsonDeserializationCreatesJavaHandle () { Person p = new Person () { Name = ""John Smith"", Age = 900, }; TestBinaryDeserialization (p); TestJsonDeserialization (p);" ).Replace("//${AFTER_MAINACTIVITY}", @" [DataContract] [Serializable] class Person : Java.Lang.Object { [DataMember] public string Name; [DataMember] public int Age; internal sealed class Binder : SerializationBinder { public override Type BindToType (string assemblyName, string typeName) { if (typeName == ""Person"") return typeof (Person); return null; } } }" ).Replace("using System;", @"using System; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Json;"); builder = CreateApkBuilder(); Assert.IsTrue(builder.Install(proj), "Install should have succeeded."); ClearAdbLogcat(); AdbStartActivity($"{proj.PackageName}/{proj.JavaPackageName}.MainActivity"); Assert.IsFalse(MonitorAdbLogcat((line) => { return(line.Contains("TestJsonDeserializationCreatesJavaHandle")); }, Path.Combine(Root, builder.ProjectDirectory, "startup-logcat.log"), 45), $"Output did contain TestJsonDeserializationCreatesJavaHandle!"); }
public void CustomLinkDescriptionPreserve([Values(AndroidLinkMode.SdkOnly, AndroidLinkMode.Full)] AndroidLinkMode linkMode) { AssertHasDevices(); var lib1 = new XamarinAndroidLibraryProject() { ProjectName = "Library1", Sources = { new BuildItem.Source("SomeClass.cs") { TextContent = () => "namespace Library1 { public class SomeClass { } }" }, new BuildItem.Source("NonPreserved.cs") { TextContent = () => "namespace Library1 { public class NonPreserved { } }" }, new BuildItem.Source("LinkerClass.cs") { TextContent = () => @" namespace Library1 { public class LinkerClass { public LinkerClass () { } public bool IsPreserved { get { return true; } } public bool ThisMethodShouldBePreserved () { return true; } public void WasThisMethodPreserved (string arg1) { } [Android.Runtime.Preserve] public void PreserveAttribMethod () { } } }", }, new BuildItem.Source("LinkModeFullClass.cs") { TextContent = () => @" namespace Library1 { public class LinkModeFullClass { public bool ThisMethodShouldNotBePreserved () { return true; } } }", }, } }; var lib2 = new DotNetStandard { ProjectName = "LinkTestLib", Sdk = "Microsoft.NET.Sdk", TargetFramework = "netstandard2.0", PackageReferences = { new Package { Id = "sqlite-net-pcl", Version = "1.7.335", } }, Sources = { new BuildItem.Source("Bug21578.cs") { TextContent = () =>{ using (var sr = new StreamReader(typeof(InstallAndRunTests).Assembly.GetManifestResourceStream("Xamarin.Android.Build.Tests.Resources.LinkDescTest.Bug21578.cs"))) return(sr.ReadToEnd()); }, }, new BuildItem.Source("Bug35195.cs") { TextContent = () =>{ using (var sr = new StreamReader(typeof(InstallAndRunTests).Assembly.GetManifestResourceStream("Xamarin.Android.Build.Tests.Resources.LinkDescTest.Bug35195.cs"))) return(sr.ReadToEnd()); }, }, }, }; if (!Builder.UseDotNet) { // DataContractSerializer is not trimming safe // https://github.com/dotnet/runtime/issues/45559 lib2.Sources.Add(new BuildItem.Source("Bug36250.cs") { TextContent = () => { using (var sr = new StreamReader(typeof(InstallAndRunTests).Assembly.GetManifestResourceStream("Xamarin.Android.Build.Tests.Resources.LinkDescTest.Bug36250.cs"))) return(sr.ReadToEnd()); }, }); } proj = new XamarinFormsAndroidApplicationProject() { IsRelease = true, AndroidLinkModeRelease = linkMode, References = { new BuildItem("ProjectReference", "..\\Library1\\Library1.csproj"), new BuildItem("ProjectReference", "..\\LinkTestLib\\LinkTestLib.csproj"), }, OtherBuildItems = { new BuildItem("LinkDescription", "linker.xml") { TextContent = () => linkMode == AndroidLinkMode.SdkOnly ? "<linker/>" : @" <linker> <assembly fullname=""Library1""> <type fullname=""Library1.LinkerClass""> <method name="".ctor"" /> <method name=""WasThisMethodPreserved"" /> <method name=""get_IsPreserved"" /> </type> </assembly> <assembly fullname=""LinkTestLib""> <type fullname=""LinkTestLib.TodoTask"" /> </assembly> </linker> ", }, }, }; if (Builder.UseDotNet) { // NOTE: workaround for netcoreapp3.1 dependency preferred over monoandroid8.0 proj.PackageReferences.Add(new Package { Id = "SQLitePCLRaw.lib.e_sqlite3.android", Version = "2.0.4", }); } proj.AndroidManifest = proj.AndroidManifest.Replace("</manifest>", "<uses-permission android:name=\"android.permission.INTERNET\" /></manifest>"); proj.SetAndroidSupportedAbis("armeabi-v7a", "arm64-v8a", "x86", "x86_64"); using (var sr = new StreamReader(typeof(InstallAndRunTests).Assembly.GetManifestResourceStream("Xamarin.Android.Build.Tests.Resources.LinkDescTest.MainActivityReplacement.cs"))) proj.MainActivity = sr.ReadToEnd(); // Set up library projects var rootPath = Path.Combine(Root, "temp", TestName); using (var lb1 = CreateDllBuilder(Path.Combine(rootPath, lib1.ProjectName))) Assert.IsTrue(lb1.Build(lib1), "First library build should have succeeded."); using (var lb2 = CreateDllBuilder(Path.Combine(rootPath, lib2.ProjectName))) Assert.IsTrue(lb2.Build(lib2), "Second library build should have succeeded."); builder = CreateApkBuilder(Path.Combine(rootPath, proj.ProjectName)); Assert.IsTrue(builder.Install(proj), "First install should have succeeded."); ClearAdbLogcat(); if (CommercialBuildAvailable) { Assert.True(builder.RunTarget(proj, "_Run"), "Project should have run."); } else { AdbStartActivity($"{proj.PackageName}/{proj.JavaPackageName}.MainActivity"); } var logcatPath = Path.Combine(Root, builder.ProjectDirectory, "logcat.log"); Assert.IsTrue(MonitorAdbLogcat((line) => { return(line.Contains("All regression tests completed.")); }, logcatPath, 90), "Linker test app did not run successfully."); var logcatOutput = File.ReadAllText(logcatPath); StringAssert.Contains("[PASS]", logcatOutput); StringAssert.DoesNotContain("[FAIL]", logcatOutput); if (linkMode == AndroidLinkMode.Full) { StringAssert.Contains("[LINKALLPASS]", logcatOutput); StringAssert.DoesNotContain("[LINKALLFAIL]", logcatOutput); } }
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.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`."); } } } }
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); } }
public void CheckMetadataSkipItemsAreProcessedCorrectly() { var packages = new List <Package> () { KnownPackages.Android_Arch_Core_Common_26_1_0, KnownPackages.Android_Arch_Lifecycle_Common_26_1_0, KnownPackages.Android_Arch_Lifecycle_Runtime_26_1_0, KnownPackages.AndroidSupportV4_27_0_2_1, KnownPackages.SupportCompat_27_0_2_1, KnownPackages.SupportCoreUI_27_0_2_1, KnownPackages.SupportCoreUtils_27_0_2_1, KnownPackages.SupportDesign_27_0_2_1, KnownPackages.SupportFragment_27_0_2_1, KnownPackages.SupportMediaCompat_27_0_2_1, KnownPackages.SupportV7AppCompat_27_0_2_1, KnownPackages.SupportV7CardView_27_0_2_1, KnownPackages.SupportV7MediaRouter_27_0_2_1, KnownPackages.SupportV7RecyclerView_27_0_2_1, KnownPackages.VectorDrawable_27_0_2_1, new Package() { Id = "Xamarin.Android.Support.Annotations", Version = "27.0.2.1" }, new Package() { Id = "Xamarin.Android.Support.Transition", Version = "27.0.2.1" }, new Package() { Id = "Xamarin.Android.Support.v7.Palette", Version = "27.0.2.1" }, new Package() { Id = "Xamarin.Android.Support.Animated.Vector.Drawable", Version = "27.0.2.1" }, }; string metaDataTemplate = @"<AndroidCustomMetaDataForReferences Include=""%""> <AndroidSkipAddToPackage>True</AndroidSkipAddToPackage> <AndroidSkipJavaStubGeneration>True</AndroidSkipJavaStubGeneration> <AndroidSkipResourceExtraction>True</AndroidSkipResourceExtraction> </AndroidCustomMetaDataForReferences>"; var proj = new XamarinAndroidApplicationProject() { Imports = { new Import(() => "CustomMetaData.target") { TextContent = () => @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003""> <ItemGroup>" + string.Join("\n", packages.Select(x => metaDataTemplate.Replace("%", x.Id))) + @"</ItemGroup> </Project>" }, } }; proj.SetProperty(proj.DebugProperties, "AndroidPackageNamingPolicy", "Lowercase"); foreach (var package in packages) { proj.PackageReferences.Add(package); } using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { b.ThrowOnBuildFailure = false; b.Verbosity = Microsoft.Build.Framework.LoggerVerbosity.Diagnostic; Assert.IsTrue(b.Build(proj), "build failed"); var bin = Path.Combine(Root, b.ProjectDirectory, proj.OutputPath); var obj = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath); var lp = Path.Combine(obj, "lp"); Assert.IsTrue(Directory.Exists(lp), $"{lp} should exists."); Assert.AreEqual(0, Directory.GetDirectories(lp).Length, $"{lp} should NOT contain any directories."); var support = Path.Combine(obj, "android", "src", "android", "support"); Assert.IsFalse(Directory.Exists(support), $"{support} should NOT exists."); Assert.IsFalse(File.Exists(lp), $" should NOT have been generated."); foreach (var apk in Directory.GetFiles(bin, "*-Signed.apk")) { using (var zip = ZipHelper.OpenZip(apk)) { foreach (var package in packages) { Assert.IsFalse(zip.Any(e => e.FullName == $"assemblies/{package.Id}.dll"), $"APK file `{apk}` should not contain {package.Id}"); } } } } }
[Category("SmokeTests"), Category("DotNetIgnore")] // Xamarin.Forms version is too old, uses net45 MSBuild tasks public void NetStandardReferenceTest() { var netStandardProject = new DotNetStandard() { ProjectName = "XamFormsSample", ProjectGuid = Guid.NewGuid().ToString(), Sdk = "Microsoft.NET.Sdk", TargetFramework = "netstandard1.4", IsRelease = true, PackageTargetFallback = "portable-net45+win8+wpa81+wp8", PackageReferences = { KnownPackages.XamarinForms_2_3_4_231, new Package() { Id = "System.IO.Packaging", Version = "4.4.0", }, new Package() { Id = "Newtonsoft.Json", Version = "10.0.3" }, }, OtherBuildItems = { new BuildItem("None") { Remove = () => "**\\*.xaml", }, new BuildItem("Compile") { Update = () => "**\\*.xaml.cs", DependentUpon = () => "%(Filename)" }, new BuildItem("EmbeddedResource") { Include = () => "**\\*.xaml", SubType = () => "Designer", Generator = () => "MSBuild:UpdateDesignTimeXaml", }, }, Sources = { new BuildItem.Source("App.xaml.cs") { TextContent = () => @"using System; using System.Collections.Generic; using System.Linq; using System.Text; using Newtonsoft.Json; using System.IO.Packaging; using Xamarin.Forms; namespace XamFormsSample { public partial class App : Application { Package package; public App() { try { JsonConvert.DeserializeObject<string>(""test""); package = Package.Open (""""); } catch { } InitializeComponent(); MainPage = new ContentPage (); } protected override void OnStart() { // Handle when your app starts } protected override void OnSleep() { // Handle when your app sleeps } protected override void OnResume() { // Handle when your app resumes } } }", }, new BuildItem.Source("App.xaml") { TextContent = () => @"<?xml version=""1.0"" encoding=""utf-8"" ?> <Application xmlns=""http://xamarin.com/schemas/2014/forms"" xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml"" x:Class=""XamFormsSample.App""> <Application.Resources> <!-- Application resource dictionary --> </Application.Resources> </Application>", }, }, }; var app = new XamarinAndroidApplicationProject() { ProjectName = "App1", IsRelease = true, UseLatestPlatformSdk = true, References = { new BuildItem.Reference("Mono.Android.Export"), new BuildItem.ProjectReference($"..\\{netStandardProject.ProjectName}\\{netStandardProject.ProjectName}.csproj", netStandardProject.ProjectName, netStandardProject.ProjectGuid), }, PackageReferences = { KnownPackages.SupportDesign_27_0_2_1, KnownPackages.SupportV7CardView_27_0_2_1, KnownPackages.AndroidSupportV4_27_0_2_1, KnownPackages.SupportCoreUtils_27_0_2_1, KnownPackages.SupportMediaCompat_27_0_2_1, KnownPackages.SupportFragment_27_0_2_1, KnownPackages.SupportCoreUI_27_0_2_1, KnownPackages.SupportCompat_27_0_2_1, KnownPackages.SupportV7AppCompat_27_0_2_1, KnownPackages.SupportV7MediaRouter_27_0_2_1, KnownPackages.XamarinForms_2_3_4_231, new Package() { Id = "System.Runtime.Loader", Version = "4.3.0", }, } }; app.MainActivity = @"using System; using Android.App; using Android.Content; using Android.Runtime; using Android.Views; using Android.Widget; using Android.OS; using XamFormsSample; namespace App1 { [Activity (Label = ""App1"", MainLauncher = true, Icon = ""@drawable/icon"")] public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity { protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); global::Xamarin.Forms.Forms.Init (this, bundle); LoadApplication (new App ()); } } }" ; app.SetAndroidSupportedAbis("x86", "armeabi-v7a"); var expectedFiles = new string [] { "Java.Interop.dll", "Mono.Android.dll", "mscorlib.dll", "System.Core.dll", "System.dll", "System.Runtime.Serialization.dll", "System.IO.Packaging.dll", "System.IO.Compression.dll", "Mono.Android.Export.dll", "App1.dll", "FormsViewGroup.dll", "Xamarin.Android.Arch.Lifecycle.Common.dll", "Xamarin.Android.Support.Compat.dll", "Xamarin.Android.Support.Core.UI.dll", "Xamarin.Android.Support.Core.Utils.dll", "Xamarin.Android.Support.Design.dll", "Xamarin.Android.Support.Fragment.dll", "Xamarin.Android.Support.v7.AppCompat.dll", "Xamarin.Android.Support.v7.CardView.dll", "Xamarin.Forms.Core.dll", "Xamarin.Forms.Platform.Android.dll", "Xamarin.Forms.Platform.dll", "Xamarin.Forms.Xaml.dll", "XamFormsSample.dll", "Mono.Security.dll", "System.Xml.dll", "System.Net.Http.dll", "System.ServiceModel.Internals.dll", "Newtonsoft.Json.dll", "Microsoft.CSharp.dll", "System.Numerics.dll", "System.Xml.Linq.dll", }; var path = Path.Combine("temp", TestContext.CurrentContext.Test.Name); using (var builder = CreateDllBuilder(Path.Combine(path, netStandardProject.ProjectName), cleanupOnDispose: false)) { using (var ab = CreateApkBuilder(Path.Combine(path, app.ProjectName), cleanupOnDispose: false)) { Assert.IsTrue(builder.Build(netStandardProject), "XamFormsSample should have built."); Assert.IsTrue(ab.Build(app), "App should have built."); var apk = Path.Combine(Root, ab.ProjectDirectory, app.IntermediateOutputPath, "android", "bin", $"{app.PackageName}.apk"); using (var zip = ZipHelper.OpenZip(apk)) { var existingFiles = zip.Where(a => a.FullName.StartsWith("assemblies/", StringComparison.InvariantCultureIgnoreCase)); var missingFiles = expectedFiles.Where(x => !zip.ContainsEntry("assemblies/" + Path.GetFileName(x))); Assert.IsFalse(missingFiles.Any(), string.Format("The following Expected files are missing. {0}", string.Join(Environment.NewLine, missingFiles))); var additionalFiles = existingFiles.Where(x => !expectedFiles.Contains(Path.GetFileName(x.FullName))); Assert.IsTrue(!additionalFiles.Any(), string.Format("Unexpected Files found! {0}", string.Join(Environment.NewLine, additionalFiles.Select(x => x.FullName)))); } } } }
public void TargetsSkipped([Values(false, true)] bool useManagedResourceGenerator) { if (!CommercialBuildAvailable) { Assert.Ignore("Not required on Open Source Builds"); } if (!HasDevices) { Assert.Ignore("Test needs a device attached."); return; } var proj = new XamarinAndroidApplicationProject() { AndroidFastDeploymentType = "Assemblies:Dexes", UseLatestPlatformSdk = true }; proj.SetProperty("AndroidUseManagedDesignTimeResourceGenerator", useManagedResourceGenerator.ToString()); var b = CreateApkBuilder($"temp/InstantRunTargetsSkipped_{useManagedResourceGenerator}", cleanupOnDispose: false); Assert.IsTrue(b.Build(proj), "1 build should have succeeded."); // unchanged build Assert.IsTrue(b.Build(proj, true, null, false), "2 build should have succeeded."); // _UpdateAndroidResgen should not be built. Assert.IsTrue(b.Output.IsTargetSkipped("_UpdateAndroidResgen"), "2 _UpdateAndroidResgen was not skipped"); // CoreCompile should not be built. Assert.IsTrue(b.Output.IsTargetSkipped("CoreCompile"), "2 CoreCompile was not skipped"); // _CompileToDalvikWithDx should not be built either. Assert.IsTrue(b.Output.IsTargetSkipped("_CompileToDalvikWithDx"), "2 _CompileToDalvikWithDx was not skipped"); // make insignificant changes in C# code and build proj.MainActivity = proj.DefaultMainActivity + "// extra"; proj.Touch("MainActivity.cs"); Assert.IsTrue(b.Build(proj, true, null, false), "3 build should have succeeded."); // _UpdateAndroidResgen should not be built. Assert.IsTrue(b.Output.IsTargetSkipped("_UpdateAndroidResgen"), "3 _UpdateAndroidResgen was not skipped"); // CoreCompile should be built. Assert.IsTrue(!b.Output.IsTargetSkipped("CoreCompile"), "3 CoreCompile was skipped"); // _CompileToDalvikWithDx should not be built either. Assert.IsTrue(b.Output.IsTargetSkipped("_CompileToDalvikWithDx"), "3 _CompileToDalvikWithDx was not skipped"); // make significant changes (but doesn't impact Resource.Designer.cs) in layout XML resource and build proj.LayoutMain = proj.LayoutMain.Replace("LinearLayout", "RelativeLayout"); // without this, resource designer .cs will be identical and further tasks will be skipped. proj.Touch("Resources\\layout\\Main.axml"); Assert.IsTrue(b.Build(proj, true, null, false), "4 build should have succeeded."); // _UpdateAndroidResgen should be built. Assert.IsTrue(!b.Output.IsTargetSkipped("_UpdateAndroidResgen"), "4 _UpdateAndroidResgen was skipped"); // CoreCompile should not be built. Assert.IsTrue(b.Output.IsTargetSkipped("CoreCompile"), "4 CoreCompile was not skipped"); // _CompileToDalvikWithDx should not be built either. Assert.IsTrue(b.Output.IsTargetSkipped("_CompileToDalvikWithDx"), "4 _CompileToDalvikWithDx was not skipped"); // make significant changes (but doesn't impact Resource.Designer.cs) in layout XML resource, // then call AndroidUpdateResource, then build (which is what our IDEs do). proj.LayoutMain = proj.LayoutMain.Replace("RelativeLayout", "LinearLayout"); // change it again proj.Touch("Resources\\layout\\Main.axml"); b.Target = "Compile"; var designTimeParams = new string [] { "BuildingInsideVisualStudio=true", "BuildProject=false" }; Assert.IsTrue(b.Build(proj, true, designTimeParams, false), "5 update resources should have succeeded."); // _UpdateAndroidResgen should be built. if (useManagedResourceGenerator) { Assert.IsTrue(!b.Output.IsTargetSkipped("_ManagedUpdateAndroidResgen"), $"5 first _ManagedUpdateAndroidResgen was skipped"); } else { Assert.IsTrue(!b.Output.IsTargetSkipped("_UpdateAndroidResgen"), $"5 first _UpdateAndroidResgen was skipped"); } b.Target = "Build"; Assert.IsTrue(b.Build(proj, true, null, false), "5 build should have succeeded."); // _UpdateAndroidResgen should not be built. if (useManagedResourceGenerator) { Assert.IsFalse(b.Output.IsTargetSkipped("_UpdateAndroidResgen"), "5 second _UpdateAndroidResgen was skipped"); // CoreCompile should be built. Assert.AreEqual(!b.RunningMSBuild, b.Output.IsTargetSkipped("CoreCompile"), "5 CoreCompile was skipped"); } else { Assert.IsTrue(b.Output.IsTargetSkipped("_UpdateAndroidResgen"), "5 second _UpdateAndroidResgen was not skipped"); // CoreCompile should not be built. Assert.IsTrue(b.Output.IsTargetSkipped("CoreCompile"), "5 CoreCompile was not skipped"); } // _CompileToDalvikWithDx should not be built either. Assert.IsTrue(b.Output.IsTargetSkipped("_CompileToDalvikWithDx"), "5 _CompileToDalvikWithDx should be skipped"); b.Dispose(); }
public void ProduceReferenceAssembly() { var path = Path.Combine("temp", TestName); var app = new XamarinAndroidApplicationProject { ProjectName = "MyApp", Sources = { new BuildItem.Source("Foo.cs") { TextContent = () => "public class Foo : Bar { }" }, } }; //NOTE: so _BuildApkEmbed runs in commercial tests app.SetProperty("EmbedAssembliesIntoApk", true.ToString()); app.SetProperty("AndroidUseSharedRuntime", false.ToString()); int count = 0; var lib = new DotNetStandard { ProjectName = "MyLibrary", Sdk = "Microsoft.NET.Sdk", TargetFramework = "netstandard2.0", Sources = { new BuildItem.Source("Bar.cs") { TextContent = () => "public class Bar { public Bar () { System.Console.WriteLine (" + count++ + "); } }" }, } }; lib.SetProperty("ProduceReferenceAssembly", "True"); app.References.Add(new BuildItem.ProjectReference($"..\\{lib.ProjectName}\\{lib.ProjectName}.csproj", lib.ProjectName, lib.ProjectGuid)); using (var libBuilder = CreateDllBuilder(Path.Combine(path, lib.ProjectName), false)) using (var appBuilder = CreateApkBuilder(Path.Combine(path, app.ProjectName))) { Assert.IsTrue(libBuilder.Build(lib), "first library build should have succeeded."); Assert.IsTrue(appBuilder.Build(app), "first app build should have succeeded."); lib.Touch("Bar.cs"); Assert.IsTrue(libBuilder.Build(lib, doNotCleanupOnUpdate: true, saveProject: false), "second library build should have succeeded."); Assert.IsTrue(appBuilder.Build(app, doNotCleanupOnUpdate: true, saveProject: false), "second app build should have succeeded."); var targetsShouldSkip = new [] { "CoreCompile", "_BuildLibraryImportsCache", "_ResolveLibraryProjectImports", "_GenerateJavaStubs", }; foreach (var target in targetsShouldSkip) { Assert.IsTrue(appBuilder.Output.IsTargetSkipped(target), $"`{target}` should be skipped!"); } var targetsShouldRun = new [] { "_BuildApkEmbed", "_CopyPackage", "_Sign", }; foreach (var target in targetsShouldRun) { Assert.IsFalse(appBuilder.Output.IsTargetSkipped(target), $"`{target}` should *not* be skipped!"); } } }
public void CheckResouceIsOverridden([Values(true, false)] bool useAapt2) { AssertHasDevices(); AssertAaptSupported(useAapt2); var library = new XamarinAndroidLibraryProject() { ProjectName = "Library1", AndroidResources = { new AndroidItem.AndroidResource(() => "Resources\\values\\strings2.xml") { TextContent = () => @"<?xml version=""1.0"" encoding=""utf-8""?> <resources> <string name=""hello_me"">Click Me! One</string> </resources>", }, }, }; var library2 = new XamarinAndroidLibraryProject() { ProjectName = "Library2", AndroidResources = { new AndroidItem.AndroidResource(() => "Resources\\values\\strings2.xml") { TextContent = () => @"<?xml version=""1.0"" encoding=""utf-8""?> <resources> <string name=""hello_me"">Click Me! Two</string> </resources>", }, }, }; var app = new XamarinAndroidApplicationProject() { PackageName = "Xamarin.ResourceTest", References = { new BuildItem.ProjectReference("..\\Library1\\Library1.csproj"), new BuildItem.ProjectReference("..\\Library2\\Library2.csproj"), }, }; library.AndroidUseAapt2 = library2.AndroidUseAapt2 = app.AndroidUseAapt2 = useAapt2; app.LayoutMain = app.LayoutMain.Replace("@string/hello", "@string/hello_me"); using (var l1 = CreateDllBuilder(Path.Combine("temp", TestName, library.ProjectName))) using (var l2 = CreateDllBuilder(Path.Combine("temp", TestName, library2.ProjectName))) using (var b = CreateApkBuilder(Path.Combine("temp", TestName, app.ProjectName))) { b.ThrowOnBuildFailure = false; string apiLevel; app.TargetFrameworkVersion = b.LatestTargetFrameworkVersion(out apiLevel); app.AndroidManifest = $@"<?xml version=""1.0"" encoding=""utf-8""?> <manifest xmlns:android=""http://schemas.android.com/apk/res/android"" android:versionCode=""1"" android:versionName=""1.0"" package=""{app.PackageName}""> <uses-sdk android:minSdkVersion=""24"" android:targetSdkVersion=""{apiLevel}"" /> <application android:label=""${{PROJECT_NAME}}""> </application > </manifest> "; Assert.IsTrue(l1.Build(library, doNotCleanupOnUpdate: true), $"Build of {library.ProjectName} should have suceeded."); Assert.IsTrue(l2.Build(library2, doNotCleanupOnUpdate: true), $"Build of {library2.ProjectName} should have suceeded."); b.BuildLogFile = "build1.log"; Assert.IsTrue(b.Build(app, doNotCleanupOnUpdate: true), $"Build of {app.ProjectName} should have suceeded."); b.BuildLogFile = "install1.log"; Assert.IsTrue(b.Install(app, doNotCleanupOnUpdate: true), "Install should have suceeded."); AdbStartActivity($"{app.PackageName}/{app.JavaPackageName}.MainActivity"); WaitForPermissionActivity(Path.Combine(Root, builder.ProjectDirectory, "permission-logcat.log")); WaitForActivityToStart(app.PackageName, "MainActivity", Path.Combine(Root, builder.ProjectDirectory, "startup-logcat.log"), 15); XDocument ui = GetUI(); XElement node = ui.XPathSelectElement($"//node[contains(@resource-id,'myButton')]"); StringAssert.AreEqualIgnoringCase("Click Me! One", node.Attribute("text").Value, "Text of Button myButton should have been \"Click Me! One\""); b.BuildLogFile = "clean.log"; Assert.IsTrue(b.Clean(app, doNotCleanupOnUpdate: true), "Clean should have suceeded."); app = new XamarinAndroidApplicationProject() { PackageName = "Xamarin.ResourceTest", References = { new BuildItem.ProjectReference("..\\Library1\\Library1.csproj"), new BuildItem.ProjectReference("..\\Library2\\Library2.csproj"), }, }; library2.References.Add(new BuildItem.ProjectReference("..\\Library1\\Library1.csproj")); app.AndroidUseAapt2 = useAapt2; app.LayoutMain = app.LayoutMain.Replace("@string/hello", "@string/hello_me"); app.TargetFrameworkVersion = b.LatestTargetFrameworkVersion(out apiLevel); app.AndroidManifest = $@"<?xml version=""1.0"" encoding=""utf-8""?> <manifest xmlns:android=""http://schemas.android.com/apk/res/android"" android:versionCode=""1"" android:versionName=""1.0"" package=""{app.PackageName}""> <uses-sdk android:minSdkVersion=""24"" android:targetSdkVersion=""{apiLevel}"" /> <application android:label=""${{PROJECT_NAME}}""> </application > </manifest> "; b.BuildLogFile = "build.log"; Assert.IsTrue(b.Build(app, doNotCleanupOnUpdate: true), $"Build of {app.ProjectName} should have suceeded."); b.BuildLogFile = "install.log"; Assert.IsTrue(b.Install(app, doNotCleanupOnUpdate: true), "Install should have suceeded."); AdbStartActivity($"{app.PackageName}/{app.JavaPackageName}.MainActivity"); WaitForPermissionActivity(Path.Combine(Root, builder.ProjectDirectory, "permission-logcat.log")); WaitForActivityToStart(app.PackageName, "MainActivity", Path.Combine(Root, builder.ProjectDirectory, "startup-logcat.log"), 15); ui = GetUI(); node = ui.XPathSelectElement($"//node[contains(@resource-id,'myButton')]"); StringAssert.AreEqualIgnoringCase("Click Me! One", node.Attribute("text").Value, "Text of Button myButton should have been \"Click Me! One\""); } }
public void ConvertCustomView([Values(true, false)] bool useAapt2) { var path = Path.Combine("temp", TestName); var app = new XamarinAndroidApplicationProject { ProjectName = "MyApp", Sources = { new BuildItem.Source("Foo.cs") { TextContent = () => "public class Foo : Bar { }" }, new BuildItem.Source("CustomTextView.cs") { TextContent = () => @"using Android.Widget; using Android.Content; using Android.Util; namespace MyApp { public class CustomTextView : TextView { public CustomTextView(Context context, IAttributeSet attributes) : base(context, attributes) { } } }" } } }; // Use a custom view app.LayoutMain = app.LayoutMain.Replace("</LinearLayout>", "<MyApp.CustomTextView android:id=\"@+id/myText\" /></LinearLayout>"); //NOTE: so _BuildApkEmbed runs in commercial tests app.SetProperty("EmbedAssembliesIntoApk", "True"); app.SetProperty("AndroidUseSharedRuntime", "False"); app.SetProperty("AndroidUseAapt2", useAapt2.ToString()); int count = 0; var lib = new DotNetStandard { ProjectName = "MyLibrary", Sdk = "Microsoft.NET.Sdk", TargetFramework = "netstandard2.0", Sources = { new BuildItem.Source("Bar.cs") { TextContent = () => "public class Bar { public Bar () { System.Console.WriteLine (" + count++ + "); } }" }, } }; //NOTE: this test is checking when $(ProduceReferenceAssembly) is False lib.SetProperty("ProduceReferenceAssembly", "False"); app.References.Add(new BuildItem.ProjectReference($"..\\{lib.ProjectName}\\{lib.ProjectName}.csproj", lib.ProjectName, lib.ProjectGuid)); using (var libBuilder = CreateDllBuilder(Path.Combine(path, lib.ProjectName), false)) using (var appBuilder = CreateApkBuilder(Path.Combine(path, app.ProjectName))) { Assert.IsTrue(libBuilder.Build(lib), "first library build should have succeeded."); Assert.IsTrue(appBuilder.Build(app), "first app build should have succeeded."); lib.Touch("Bar.cs"); Assert.IsTrue(libBuilder.Build(lib, doNotCleanupOnUpdate: true, saveProject: false), "second library build should have succeeded."); Assert.IsTrue(appBuilder.Build(app, doNotCleanupOnUpdate: true, saveProject: false), "second app build should have succeeded."); var targetsShouldSkip = new [] { "_BuildLibraryImportsCache", "_ResolveLibraryProjectImports", "_ConvertCustomView", }; foreach (var target in targetsShouldSkip) { Assert.IsTrue(appBuilder.Output.IsTargetSkipped(target), $"`{target}` should be skipped!"); } var targetsShouldRun = new [] { //MyLibrary.dll changed and $(ProduceReferenceAssembly)=False "CoreCompile", "_GenerateJavaStubs", "_BuildApkEmbed", "_CopyPackage", "_Sign", }; foreach (var target in targetsShouldRun) { Assert.IsFalse(appBuilder.Output.IsTargetSkipped(target), $"`{target}` should *not* be skipped!"); } } }
public void ResolveNativeLibrariesInManagedReferences([Values(true, false)] bool useShortFileNames) { var lib = new XamarinAndroidLibraryProject() { ProjectName = "Lib", IsRelease = true, ProjectGuid = Guid.NewGuid().ToString(), OtherBuildItems = { new BuildItem(AndroidBuildActions.EmbeddedNativeLibrary, "libs/armeabi-v7a/libfoo.so") { TextContent = () => string.Empty, Encoding = Encoding.ASCII, Timestamp = DateTimeOffset.Now, } }, Sources = { new BuildItem.Source("Class1.cs") { TextContent = () => @" using System; namespace Lib { public class Class1 { public Class1 () { } } }" }, }, }; lib.SetProperty(lib.ActiveConfigurationProperties, "UseShortFileNames", useShortFileNames); var so = lib.OtherBuildItems.First(x => x.Include() == "libs/armeabi-v7a/libfoo.so"); var lib2 = new XamarinAndroidLibraryProject() { ProjectName = "Lib2", ProjectGuid = Guid.NewGuid().ToString(), IsRelease = true, OtherBuildItems = { new BuildItem(AndroidBuildActions.EmbeddedNativeLibrary, "libs/armeabi-v7a/libfoo2.so") { TextContent = () => string.Empty, Encoding = Encoding.ASCII, Timestamp = DateTimeOffset.Now, }, new BuildItem.ProjectReference(@"..\Lib\Lib.csproj", "Lib", lib.ProjectGuid) { } }, Sources = { new BuildItem.Source("Class2.cs") { TextContent = () => @" using System; namespace Lib2 { public class Class2 { public Class2 () { var c = new Lib.Class1 (); } } }" }, }, }; lib2.SetProperty(lib.ActiveConfigurationProperties, "UseShortFileNames", useShortFileNames); var path = Path.Combine(Root, "temp", $"ResolveNativeLibrariesInManagedReferences_{useShortFileNames}"); using (var libbuilder = CreateDllBuilder(Path.Combine(path, "Lib"))) { Assert.IsTrue(libbuilder.Build(lib), "lib 1st. build failed"); using (var libbuilder2 = CreateDllBuilder(Path.Combine(path, "Lib2"))) { Assert.IsTrue(libbuilder2.Build(lib2), "lib 1st. build failed"); var app = new XamarinAndroidApplicationProject() { ProjectName = "App", IsRelease = true, OtherBuildItems = { new BuildItem.ProjectReference(@"..\Lib2\Lib2.csproj", "Lib2", lib2.ProjectGuid), } }; app.SetProperty(app.ActiveConfigurationProperties, "UseShortFileNames", useShortFileNames); using (var builder = CreateApkBuilder(Path.Combine(path, "App"))) { builder.Verbosity = LoggerVerbosity.Diagnostic; Assert.IsTrue(builder.Build(app), "app 1st. build failed"); var libfoo = ZipHelper.ReadFileFromZip(Path.Combine(Root, builder.ProjectDirectory, app.OutputPath, app.PackageName + "-Signed.apk"), "lib/armeabi-v7a/libfoo.so"); Assert.IsNotNull(libfoo, "libfoo.so should exist in the .apk"); so.TextContent = () => "newValue"; so.Timestamp = DateTimeOffset.Now; Assert.IsTrue(libbuilder.Build(lib), "lib 2nd. build failed"); Assert.IsTrue(libbuilder2.Build(lib2), "lib 2nd. build failed"); Assert.IsTrue(builder.Build(app), "app 2nd. build failed"); Assert.IsNotNull(libfoo, "libfoo.so should exist in the .apk"); Assert.AreEqual(so.TextContent().Length, new FileInfo(Path.Combine(Root, libbuilder.ProjectDirectory, lib.IntermediateOutputPath, useShortFileNames ? "nl" : "native_library_imports", "armeabi-v7a", "libfoo.so")).Length, "intermediate size mismatch"); libfoo = ZipHelper.ReadFileFromZip(Path.Combine(Root, builder.ProjectDirectory, app.OutputPath, app.PackageName + "-Signed.apk"), "lib/armeabi-v7a/libfoo.so"); Assert.AreEqual(so.TextContent().Length, libfoo.Length, "compressed size mismatch"); var libfoo2 = ZipHelper.ReadFileFromZip(Path.Combine(Root, builder.ProjectDirectory, app.OutputPath, app.PackageName + "-Signed.apk"), "lib/armeabi-v7a/libfoo2.so"); Assert.IsNotNull(libfoo2, "libfoo2.so should exist in the .apk"); Directory.Delete(path, recursive: true); } } } }
public void MonoAndroidExportReferencedAppStarts(bool useSharedRuntime, bool embedAssemblies, string fastDevType, bool activityStarts) { AssertCommercialBuild(); AssertHasDevices(); var proj = new XamarinAndroidApplicationProject() { IsRelease = false, AndroidFastDeploymentType = fastDevType, References = { new BuildItem.Reference("Mono.Android.Export"), }, }; proj.Sources.Add(new BuildItem.Source("ContainsExportedMethods.cs") { TextContent = () => @"using System; using Java.Interop; namespace UnnamedProject { class ContainsExportedMethods : Java.Lang.Object { public bool Constructed; public int Count; public ContainsExportedMethods () { Console.WriteLine (""# ContainsExportedMethods: constructed! Handle=0x{0}"", Handle.ToString (""x"")); Constructed = true; } [Export] public void Exported () { Count++; } } } ", }); proj.MainActivity = @"using System; using Android.App; using Android.Content; using Android.Runtime; using Android.Views; using Android.Widget; using Android.OS; namespace UnnamedProject { [Activity (Label = ""UnnamedProject"", MainLauncher = true, Icon = ""@drawable/icon"")] public class MainActivity : Activity { protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); var foo = new ContainsExportedMethods (); foo.Exported (); } } }" ; var abis = new string [] { "armeabi-v7a", "x86" }; proj.SetProperty(KnownProperties.AndroidSupportedAbis, string.Join(";", abis)); proj.SetProperty(KnownProperties.AndroidUseSharedRuntime, useSharedRuntime.ToString()); proj.SetProperty("EmbedAssembliesIntoApk", embedAssemblies.ToString()); proj.SetDefaultTargetDevice(); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { string apiLevel; proj.TargetFrameworkVersion = b.LatestTargetFrameworkVersion(out apiLevel); proj.AndroidManifest = $@"<?xml version=""1.0"" encoding=""utf-8""?> <manifest xmlns:android=""http://schemas.android.com/apk/res/android"" android:versionCode=""1"" android:versionName=""1.0"" package=""UnnamedProject.UnnamedProject""> <uses-sdk android:minSdkVersion=""24"" android:targetSdkVersion=""{apiLevel}"" /> <application android:label=""${{PROJECT_NAME}}""> </application > </manifest>"; Assert.True(b.Install(proj), "Project should have installed."); ClearAdbLogcat(); b.BuildLogFile = "run.log"; Assert.True(b.RunTarget(proj, "StartAndroidActivity", doNotCleanupOnUpdate: true), "Project should have run."); Assert.True(WaitForActivityToStart(proj.PackageName, "MainActivity", Path.Combine(Root, b.ProjectDirectory, "logcat.log"), 30), "Activity should have started."); string expectedLogcatOutput = "ContainsExportedMethods: constructed! Handle="; Assert.IsTrue(MonitorAdbLogcat((line) => { return(line.Contains(expectedLogcatOutput)); }, Path.Combine(Root, b.ProjectDirectory, "startup-logcat.log"), 45), $"Output did not contain {expectedLogcatOutput}!"); Assert.True(b.Uninstall(proj), "Project should have uninstalled."); } }
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."); } }
public void ClassLibraryMainLauncherRuns() { if (!HasDevices) { Assert.Ignore("Test needs a device attached."); return; } var path = Path.Combine("temp", TestName); var app = new XamarinAndroidApplicationProject { ProjectName = "MyApp", }; if (!CommercialBuildAvailable) { var abis = new string [] { "armeabi-v7a", "x86" }; app.SetProperty(KnownProperties.AndroidSupportedAbis, string.Join(";", abis)); } app.SetDefaultTargetDevice(); var lib = new XamarinAndroidLibraryProject { ProjectName = "MyLibrary" }; lib.Sources.Add(new BuildItem.Source("MainActivity.cs") { TextContent = () => lib.ProcessSourceTemplate(app.DefaultMainActivity).Replace("${JAVA_PACKAGENAME}", app.JavaPackageName), }); lib.AndroidResources.Clear(); foreach (var resource in app.AndroidResources) { lib.AndroidResources.Add(resource); } var reference = $"..\\{lib.ProjectName}\\{lib.ProjectName}.csproj"; app.References.Add(new BuildItem.ProjectReference(reference, lib.ProjectName, lib.ProjectGuid)); // Remove the default MainActivity.cs & AndroidResources app.AndroidResources.Clear(); app.AndroidResources.Add(new AndroidItem.AndroidResource("Resources\\layout\\foo.xml") { TextContent = () => "<?xml version=\"1.0\" encoding=\"utf-8\" ?><LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\" />" }); app.Sources.Remove(app.GetItem("MainActivity.cs")); using (var libBuilder = CreateDllBuilder(Path.Combine(path, lib.ProjectName))) using (var appBuilder = CreateApkBuilder(Path.Combine(path, app.ProjectName))) { SetTargetFrameworkAndManifest(app, appBuilder); Assert.IsTrue(libBuilder.Build(lib), "library build should have succeeded."); Assert.True(appBuilder.Install(app), "app should have installed."); ClearAdbLogcat(); if (CommercialBuildAvailable) { Assert.True(appBuilder.RunTarget(app, "_Run"), "Project should have run."); } else { AdbStartActivity($"{app.PackageName}/{app.JavaPackageName}.MainActivity"); } Assert.True(WaitForActivityToStart(app.PackageName, "MainActivity", Path.Combine(Root, appBuilder.ProjectDirectory, "logcat.log"), 30), "Activity should have started."); } }
public void MergeLibraryManifest() { byte [] classesJar; using (var stream = typeof(XamarinAndroidCommonProject).Assembly.GetManifestResourceStream("Xamarin.ProjectTools.Resources.Base.classes.jar")) { classesJar = new byte [stream.Length]; stream.Read(classesJar, 0, (int)stream.Length); } byte [] data; using (var ms = new MemoryStream()) { using (var zip = ZipArchive.Create(ms)) { zip.AddEntry("AndroidManifest.xml", @"<?xml version='1.0'?> <manifest xmlns:android='http://schemas.android.com/apk/res/android' package='com.xamarin.test'> <uses-sdk android:minSdkVersion='16'/> <permission android:name='${applicationId}.permission.C2D_MESSAGE' android:protectionLevel='signature' /> <application> <activity android:name='.signin.internal.SignInHubActivity' /> <provider android:authorities='${applicationId}.FacebookInitProvider' android:name='.internal.FacebookInitProvider' android:exported='false' /> <meta-data android:name='android.support.VERSION' android:value='25.4.0' /> <meta-data android:name='android.support.VERSION' android:value='25.4.0' /> </application> </manifest> ", encoding: System.Text.Encoding.UTF8); zip.CreateDirectory("res"); zip.AddEntry(classesJar, "classes.jar"); zip.AddEntry("R.txt", " ", encoding: System.Text.Encoding.UTF8); } data = ms.ToArray(); } var path = Path.Combine("temp", TestContext.CurrentContext.Test.Name); var lib = new XamarinAndroidBindingProject() { ProjectName = "Binding1", AndroidClassParser = "class-parse", Jars = { new AndroidItem.LibraryProjectZip("Jars\\foo.aar") { BinaryContent = () => data, } }, }; var proj = new XamarinAndroidApplicationProject() { PackageName = "com.xamarin.manifest", References = { new BuildItem.ProjectReference("..\\Binding1\\Binding1.csproj", lib.ProjectGuid) }, PackageReferences = { KnownPackages.SupportMediaCompat_27_0_2_1, KnownPackages.SupportFragment_27_0_2_1, KnownPackages.SupportCoreUtils_27_0_2_1, KnownPackages.SupportCoreUI_27_0_2_1, KnownPackages.SupportCompat_27_0_2_1, KnownPackages.AndroidSupportV4_27_0_2_1, KnownPackages.SupportV7AppCompat_27_0_2_1, }, }; proj.Sources.Add(new BuildItem.Source("TestActivity1.cs") { TextContent = () => @"using System; using System.Collections.Generic; using System.Linq; using System.Text; using Android.App; using Android.Content; using Android.OS; using Android.Runtime; using Android.Views; using Android.Widget; using Android.Support.V4.App; using Android.Util; [Activity (Label = ""TestActivity1"")] [IntentFilter (new[]{Intent.ActionMain}, Categories = new[]{ ""com.xamarin.sample"" })] public class TestActivity1 : FragmentActivity { } " , }); proj.Sources.Add(new BuildItem.Source("TestActivity2.cs") { TextContent = () => @"using System; using System.Collections.Generic; using System.Linq; using System.Text; using Android.App; using Android.Content; using Android.OS; using Android.Runtime; using Android.Views; using Android.Widget; using Android.Support.V4.App; using Android.Util; [Activity (Label = ""TestActivity2"")] [IntentFilter (new[]{Intent.ActionMain}, Categories = new[]{ ""com.xamarin.sample"" })] public class TestActivity2 : FragmentActivity { } " , }); using (var libbuilder = CreateDllBuilder(Path.Combine(path, "Binding1"))) { Assert.IsTrue(libbuilder.Build(lib), "Build should have succeeded."); using (var builder = CreateApkBuilder(Path.Combine(path, "App1"))) { Assert.IsTrue(builder.Build(proj), "Build should have succeeded."); var manifest = builder.Output.GetIntermediaryAsText(Root, "android/AndroidManifest.xml"); Assert.IsTrue(manifest.Contains("com.xamarin.manifest.permission.C2D_MESSAGE"), "${applicationId}.permission.C2D_MESSAGE was not replaced with com.xamarin.manifest.permission.C2D_MESSAGE"); Assert.IsTrue(manifest.Contains("com.xamarin.test.signin.internal.SignInHubActivity"), ".signin.internal.SignInHubActivity was not replaced with com.xamarin.test.signin.internal.SignInHubActivity"); Assert.IsTrue(manifest.Contains("com.xamarin.manifest.FacebookInitProvider"), "${applicationId}.FacebookInitProvider was not replaced with com.xamarin.manifest.FacebookInitProvider"); Assert.IsTrue(manifest.Contains("com.xamarin.test.internal.FacebookInitProvider"), ".internal.FacebookInitProvider was not replaced with com.xamarin.test.internal.FacebookInitProvider"); Assert.AreEqual(manifest.IndexOf("meta-data", StringComparison.OrdinalIgnoreCase), manifest.LastIndexOf("meta-data", StringComparison.OrdinalIgnoreCase), "There should be only one meta-data element"); var doc = XDocument.Parse(manifest); var ns = XNamespace.Get("http://schemas.android.com/apk/res/android"); var activities = doc.Element("manifest")?.Element("application")?.Elements("activity"); var e = activities.FirstOrDefault(x => x.Attribute(ns.GetName("label"))?.Value == "TestActivity2"); Assert.IsNotNull(e, "Manifest should contain an activity for TestActivity2"); Assert.IsNotNull(e.Element("intent-filter"), "TestActivity2 should have an intent-filter"); Assert.IsNotNull(e.Element("intent-filter").Element("action"), "TestActivity2 should have an intent-filter/action"); } } }
public void CustomApplicationRunsWithDebuggerAndBreaks(bool useSharedRuntime, bool embedAssemblies, string fastDevType, bool activityStarts) { if (!CommercialBuildAvailable) { Assert.Ignore("Test does not run on the Open Source Builds."); return; } if (!HasDevices) { Assert.Ignore("Test needs a device attached."); return; } var proj = new XamarinAndroidApplicationProject() { IsRelease = false, AndroidFastDeploymentType = fastDevType, }; var abis = new string [] { "armeabi-v7a", "x86" }; proj.SetProperty(KnownProperties.AndroidSupportedAbis, string.Join(";", abis)); proj.SetProperty(KnownProperties.AndroidUseSharedRuntime, useSharedRuntime.ToString()); proj.SetProperty("EmbedAssembliesIntoApk", embedAssemblies.ToString()); proj.SetDefaultTargetDevice(); proj.Sources.Add(new BuildItem.Source("MyApplication.cs") { TextContent = () => proj.ProcessSourceTemplate(@"using System; using Android.App; using Android.OS; using Android.Runtime; using Android.Widget; namespace ${ROOT_NAMESPACE} { [Application] public class MyApplication : Application { public MyApplication (IntPtr handle, JniHandleOwnership jniHandle) : base (handle, jniHandle) { } public override void OnCreate () { base.OnCreate (); } } } "), }); using (var b = CreateApkBuilder(Path.Combine("temp", TestName))) { string apiLevel; proj.TargetFrameworkVersion = b.LatestTargetFrameworkVersion(out apiLevel); proj.AndroidManifest = $@"<?xml version=""1.0"" encoding=""utf-8""?> <manifest xmlns:android=""http://schemas.android.com/apk/res/android"" android:versionCode=""1"" android:versionName=""1.0"" package=""UnnamedProject.UnnamedProject""> <uses-sdk android:minSdkVersion=""24"" android:targetSdkVersion=""{apiLevel}"" /> <application android:label=""${{PROJECT_NAME}}""> </application > </manifest>"; b.Save(proj, saveProject: true); proj.NuGetRestore(Path.Combine(Root, b.ProjectDirectory), b.PackagesDirectory); Assert.True(b.Build(proj), "Project should have built."); Assert.True(b.Install(proj), "Project should have installed."); int breakcountHitCount = 0; ManualResetEvent resetEvent = new ManualResetEvent(false); var sw = new Stopwatch(); // setup the debugger var session = new SoftDebuggerSession(); session.Breakpoints = new BreakpointStore { { Path.Combine(Root, b.ProjectDirectory, "MainActivity.cs"), 19 }, { Path.Combine(Root, b.ProjectDirectory, "MyApplication.cs"), 17 }, }; session.TargetHitBreakpoint += (sender, e) => { Console.WriteLine($"BREAK {e.Type}"); breakcountHitCount++; session.Continue(); }; var rnd = new Random(); int port = rnd.Next(10000, 20000); TestContext.Out.WriteLine($"{port}"); var args = new SoftDebuggerConnectArgs("", IPAddress.Loopback, port) { MaxConnectionAttempts = 10, }; var startInfo = new SoftDebuggerStartInfo(args) { WorkingDirectory = Path.Combine(b.ProjectDirectory, proj.IntermediateOutputPath, "android", "assets"), }; var options = new DebuggerSessionOptions() { EvaluationOptions = EvaluationOptions.DefaultOptions, }; options.EvaluationOptions.UseExternalTypeResolver = true; ClearAdbLogcat(); Assert.True(b.RunTarget(proj, "_Run", parameters: new string [] { $"AndroidSdbTargetPort={port}", $"AndroidSdbHostPort={port}", "AndroidAttachDebugger=True", }), "Project should have run."); // do we expect the app to start? Assert.AreEqual(activityStarts, WaitForDebuggerToStart(Path.Combine(Root, b.ProjectDirectory, "logcat.log")), "Activity should have started"); if (!activityStarts) { return; } // we need to give a bit of time for the debug server to start up. WaitFor(2000); session.LogWriter += (isStderr, text) => { Console.WriteLine(text); }; session.OutputWriter += (isStderr, text) => { Console.WriteLine(text); }; session.DebugWriter += (level, category, message) => { Console.WriteLine(message); }; session.Run(startInfo, options); var expectedTime = TimeSpan.FromSeconds(1); var actualTime = ProfileFor(() => session.IsConnected); TestContext.Out.WriteLine($"Debugger connected in {actualTime}"); Assert.LessOrEqual(actualTime, expectedTime, $"Debugger should have connected within {expectedTime} but it took {actualTime}."); // we need to wait here for a while to allow the breakpoints to hit // but we need to timeout TimeSpan timeout = TimeSpan.FromSeconds(60); while (session.IsConnected && breakcountHitCount < 2 && timeout >= TimeSpan.Zero) { Thread.Sleep(10); timeout = timeout.Subtract(TimeSpan.FromMilliseconds(10)); } WaitFor(2000); int expected = 2; Assert.AreEqual(expected, breakcountHitCount, $"Should have hit {expected} breakpoints. Only hit {breakcountHitCount}"); Assert.True(b.Uninstall(proj), "Project should have uninstalled."); session.Exit(); } }
public void InstallWithoutSharedRuntime() { AssertCommercialBuild(); AssertHasDevices(); var proj = new XamarinAndroidApplicationProject() { IsRelease = true, }; proj.SetProperty(proj.ReleaseProperties, "Optimize", false); proj.SetProperty(proj.ReleaseProperties, "DebugType", "none"); if (Builder.UseDotNet) { // NOTE: in .NET 6, EmbedAssembliesIntoApk=true by default for Release builds proj.SetProperty(proj.ReleaseProperties, "EmbedAssembliesIntoApk", "false"); } else { proj.RemoveProperty(proj.ReleaseProperties, "EmbedAssembliesIntoApk"); } var abis = new [] { "armeabi-v7a", "x86" }; proj.SetAndroidSupportedAbis(abis); using (var builder = CreateApkBuilder()) { if (RunAdbCommand("shell pm list packages Mono.Android.DebugRuntime").Trim().Length != 0) { RunAdbCommand("uninstall Mono.Android.DebugRuntime"); } Assert.IsTrue(builder.Install(proj)); var runtimeInfo = builder.GetSupportedRuntimes(); var apkPath = Path.Combine(Root, builder.ProjectDirectory, proj.IntermediateOutputPath, "android", "bin", $"{proj.PackageName}.apk"); using (var apk = ZipHelper.OpenZip(apkPath)) { foreach (var abi in abis) { string runtimeAbiName; if (Builder.UseDotNet) { runtimeAbiName = $"{abi}-net6"; } else { runtimeAbiName = abi; } var runtime = runtimeInfo.FirstOrDefault(x => x.Abi == runtimeAbiName && x.Runtime == "debug"); Assert.IsNotNull(runtime, "Could not find the expected runtime."); var inApk = ZipHelper.ReadFileFromZip(apk, String.Format("lib/{0}/{1}", abi, runtime.Name)); var inApkRuntime = runtimeInfo.FirstOrDefault(x => x.Abi == runtimeAbiName && x.Size == inApk.Length); Assert.IsNotNull(inApkRuntime, "Could not find the actual runtime used."); Assert.AreEqual(runtime.Size, inApkRuntime.Size, "expected {0} got {1}", "debug", inApkRuntime.Runtime); } } //FIXME: https://github.com/xamarin/androidtools/issues/141 //Assert.AreEqual (0, RunAdbCommand ("shell pm list packages Mono.Android.DebugRuntime").Trim ().Length, // "The Shared Runtime should not have been installed."); var directorylist = GetContentFromAllOverrideDirectories(proj.PackageName); StringAssert.Contains($"{proj.ProjectName}.dll", directorylist, $"{proj.ProjectName}.dll should exist in the .__override__ directory."); if (Builder.UseDotNet) { StringAssert.Contains($"System.Private.CoreLib.dll", directorylist, $"System.Private.CoreLib.dll should exist in the .__override__ directory."); } else { StringAssert.Contains($"System.dll", directorylist, $"System.dll should exist in the .__override__ directory."); } StringAssert.Contains($"Mono.Android.dll", directorylist, $"Mono.Android.dll should exist in the .__override__ directory."); Assert.IsTrue(builder.Uninstall(proj), "unnstall should have succeeded."); } }
public void CheckAssetsAreIncludedInAPK([Values(true, false)] bool useAapt2) { var projectPath = Path.Combine("temp", TestName); var libproj = new XamarinAndroidLibraryProject() { ProjectName = "Library1", IsRelease = true, OtherBuildItems = { new AndroidItem.AndroidAsset("Assets\\asset1.txt") { TextContent = () => "Asset1", Encoding = Encoding.ASCII, }, new AndroidItem.AndroidAsset("Assets\\subfolder\\") { }, new AndroidItem.AndroidAsset("Assets\\subfolder\\asset2.txt") { TextContent = () => "Asset2", Encoding = Encoding.ASCII, }, new AndroidItem.AndroidAsset("Assets\\subfolder\\asset5.txt") { TextContent = () => "Asset5", Encoding = Encoding.ASCII, Metadata = { { "LogicalName", Path.Combine(Path.GetPathRoot(Root), "Assets", "subfolder", "asset5.txt") } }, }, } }; var proj = new XamarinAndroidApplicationProject() { ProjectName = "App1", IsRelease = true, OtherBuildItems = { new AndroidItem.AndroidAsset("Assets\\asset3.txt") { TextContent = () => "Asset3", Encoding = Encoding.ASCII, }, new AndroidItem.AndroidAsset("Assets\\subfolder\\") { }, new AndroidItem.AndroidAsset("Assets\\subfolder\\asset4.txt") { TextContent = () => "Asset4", Encoding = Encoding.ASCII, }, new AndroidItem.AndroidAsset("Assets\\subfolder\\asset6.txt") { TextContent = () => "Asset6", Encoding = Encoding.ASCII, Metadata = { { "LogicalName", Path.Combine(Path.GetPathRoot(Root), "Assets", "subfolder", "asset6.txt") } }, }, } }; proj.SetProperty("AndroidUseAapt2", useAapt2.ToString()); proj.References.Add(new BuildItem("ProjectReference", "..\\Library1\\Library1.csproj")); using (var libb = CreateDllBuilder(Path.Combine(projectPath, libproj.ProjectName))) { Assert.IsTrue(libb.Build(libproj), "{0} should have built successfully.", libproj.ProjectName); using (var b = CreateApkBuilder(Path.Combine(projectPath, proj.ProjectName))) { Assert.IsTrue(b.Build(proj), "{0} should have built successfully.", proj.ProjectName); using (var apk = ZipHelper.OpenZip(Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "bin", "UnnamedProject.UnnamedProject.apk"))) { foreach (var a in libproj.OtherBuildItems.Where(x => x is AndroidItem.AndroidAsset)) { var item = a.Include().ToLower().Replace("\\", "/"); if (item.EndsWith("/")) { continue; } var data = ZipHelper.ReadFileFromZip(apk, item); Assert.IsNotNull(data, "{0} should be in the apk.", item); Assert.AreEqual(a.TextContent(), Encoding.ASCII.GetString(data), "The Contents of {0} should be \"{1}\"", item, a.TextContent()); } foreach (var a in proj.OtherBuildItems.Where(x => x is AndroidItem.AndroidAsset)) { var item = a.Include().ToLower().Replace("\\", "/"); if (item.EndsWith("/")) { continue; } var data = ZipHelper.ReadFileFromZip(apk, item); Assert.IsNotNull(data, "{0} should be in the apk.", item); Assert.AreEqual(a.TextContent(), Encoding.ASCII.GetString(data), "The Contents of {0} should be \"{1}\"", item, a.TextContent()); } } Directory.Delete(Path.Combine(Root, projectPath), recursive: true); } } }