public XamarinAndroidApplicationProject(string debugConfigurationName = "Debug", string releaseConfigurationName = "Release", [CallerMemberName] string packageName = "")
            : base(debugConfigurationName, releaseConfigurationName)
        {
            if (Builder.UseDotNet)
            {
                SetProperty(KnownProperties.OutputType, "Exe");
                SetProperty("XamarinAndroidSupportSkipVerifyVersions", "True");
                SetProperty("_FastDeploymentDiagnosticLogging", "True");

                // Workaround for AndroidX, see: https://github.com/xamarin/AndroidSupportComponents/pull/239
                Imports.Add(new Import(() => "Directory.Build.targets")
                {
                    TextContent = () =>
                                  @"<Project>
							<PropertyGroup>
								<VectorDrawableCheckBuildToolsVersionTaskBeforeTargets />
							</PropertyGroup>
						</Project>"
                });
            }
            else
            {
                SetProperty("_FastDeploymentDiagnosticLogging", "True");
                SetProperty("AndroidApplication", "True");
                SetProperty("AndroidResgenClass", "Resource");
                SetProperty("AndroidResgenFile", () => "Resources\\Resource.designer" + Language.DefaultDesignerExtension);
                SetProperty("AndroidManifest", "Properties\\AndroidManifest.xml");
                SetProperty(DebugProperties, "AndroidLinkMode", "None");
                SetProperty(ReleaseProperties, "AndroidLinkMode", "SdkOnly");
                SetProperty(DebugProperties, KnownProperties.EmbedAssembliesIntoApk, "False", "'$(EmbedAssembliesIntoApk)' == ''");
                SetProperty(ReleaseProperties, KnownProperties.EmbedAssembliesIntoApk, "True", "'$(EmbedAssembliesIntoApk)' == ''");
            }

            AndroidManifest  = default_android_manifest;
            TargetSdkVersion = AndroidSdkResolver.GetMaxInstalledPlatform().ToString();
            LayoutMain       = default_layout_main;
            StringsXml       = default_strings_xml;
            PackageName      = $"com.xamarin.{(packageName ?? ProjectName).ToLower ()}";
            JavaPackageName  = JavaPackageName ?? PackageName.ToLowerInvariant();

            OtherBuildItems.Add(new BuildItem.NoActionResource("Properties\\AndroidManifest.xml")
            {
                TextContent = ProcessManifestTemplate,
            });
            AndroidResources.Add(new AndroidItem.AndroidResource("Resources\\layout\\Main.axml")
            {
                TextContent = () => LayoutMain
            });
            AndroidResources.Add(new AndroidItem.AndroidResource("Resources\\values\\Strings.xml")
            {
                TextContent = () => StringsXml.Replace("${PROJECT_NAME}", ProjectName)
            });

            Sources.Add(new BuildItem.Source(() => "MainActivity" + Language.DefaultExtension)
            {
                TextContent = () => ProcessSourceTemplate(MainActivity ?? DefaultMainActivity)
            });
        }
예제 #2
0
        /// <summary>
        /// Runs the `dotnet` tool with the specified arguments.
        /// </summary>
        /// <param name="args">command arguments</param>
        /// <returns>Whether or not the command succeeded.</returns>
        protected bool Execute(params string [] args)
        {
            if (string.IsNullOrEmpty(ProcessLogFile))
            {
                ProcessLogFile = Path.Combine(XABuildPaths.TestOutputDirectory, $"dotnet{DateTime.Now.ToString ("yyyyMMddHHmmssff")}-process.log");
            }

            var  procOutput = new StringBuilder();
            bool succeeded;

            using (var p = new Process()) {
                p.StartInfo.FileName               = Path.Combine(AndroidSdkResolver.GetDotNetPreviewPath(), "dotnet");
                p.StartInfo.Arguments              = string.Join(" ", args);
                p.StartInfo.CreateNoWindow         = true;
                p.StartInfo.UseShellExecute        = false;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError  = true;
                // Ensure any variable alteration from DotNetXamarinProject.Construct is cleared.
                if (!Builder.UseDotNet && !TestEnvironment.IsWindows)
                {
                    p.StartInfo.EnvironmentVariables ["MSBUILD_EXE_PATH"] = null;
                }

                p.ErrorDataReceived += (sender, e) => {
                    if (e.Data != null)
                    {
                        procOutput.AppendLine(e.Data);
                    }
                };
                p.ErrorDataReceived += (sender, e) => {
                    if (e.Data != null)
                    {
                        procOutput.AppendLine(e.Data);
                    }
                };

                procOutput.AppendLine($"Running: {p.StartInfo.FileName} {p.StartInfo.Arguments}");
                p.Start();
                p.BeginOutputReadLine();
                p.BeginErrorReadLine();
                bool completed = p.WaitForExit((int)new TimeSpan(0, 15, 0).TotalMilliseconds);
                succeeded = completed && p.ExitCode == 0;
                procOutput.AppendLine($"Exit Code: {p.ExitCode}");
            }

            File.WriteAllText(ProcessLogFile, procOutput.ToString());
            return(succeeded);
        }
예제 #3
0
        static void DexDump(DataReceivedEventHandler handler, string dexFile, string androidSdkDirectory)
        {
            var androidSdk = new AndroidSdkInfo((l, m) => {
                Console.WriteLine($"{l}: {m}");
                if (l == TraceLevel.Error)
                {
                    throw new Exception(m);
                }
            }, androidSdkDirectory, javaSdkPath: AndroidSdkResolver.GetJavaSdkPath());
            var buildToolsPath = androidSdk.GetBuildToolsPaths().FirstOrDefault();

            if (string.IsNullOrEmpty(buildToolsPath))
            {
                throw new Exception($"Unable to find build-tools in `{androidSdkDirectory}`!");
            }

            var psi = new ProcessStartInfo {
                FileName               = Path.Combine(buildToolsPath, "dexdump"),
                Arguments              = Path.GetFileName(dexFile),
                CreateNoWindow         = true,
                WindowStyle            = ProcessWindowStyle.Hidden,
                UseShellExecute        = false,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
                WorkingDirectory       = Path.GetDirectoryName(dexFile),
            };

            using (var p = new Process {
                StartInfo = psi
            }) {
                p.ErrorDataReceived  += handler;
                p.OutputDataReceived += handler;

                p.Start();
                p.BeginErrorReadLine();
                p.BeginOutputReadLine();
                p.WaitForExit();

                if (p.ExitCode != 0)
                {
                    throw new Exception($"'{psi.FileName} {psi.Arguments}' exited with code: {p.ExitCode}");
                }
            }
        }
예제 #4
0
        public int GetMaxInstalledPlatform()
        {
            string sdkPath = AndroidSdkResolver.GetAndroidSdkPath();
            int    result  = 0;

            foreach (var dir in Directory.EnumerateDirectories(Path.Combine(sdkPath, "platforms")))
            {
                int    version;
                string v = Path.GetFileName(dir).Replace("android-", "");
                if (!int.TryParse(v, out version))
                {
                    continue;
                }
                if (version < result)
                {
                    continue;
                }
                result = version;
            }
            return(result);
        }
예제 #5
0
        public JarContentBuilder()
        {
            Action <TraceLevel, string> logger = (level, value) => {
                switch (level)
                {
                case TraceLevel.Error:
                    throw new Exception($"AndroidSdkInfo {level}: {value}");

                default:
                    Console.WriteLine($"AndroidSdkInfo {level}: {value}");
                    break;
                }
            };

            var sdkPath    = AndroidSdkResolver.GetAndroidSdkPath();
            var ndkPath    = AndroidSdkResolver.GetAndroidNdkPath();
            var androidSdk = new AndroidSdkInfo(logger, androidSdkPath: sdkPath, androidNdkPath: ndkPath);

            JavacFullPath = Path.Combine(androidSdk.JavaSdkPath, "bin", "javac");
            JarFullPath   = Path.Combine(androidSdk.JavaSdkPath, "bin", "jar");
        }
예제 #6
0
        public XASdkProject(string outputType = "Exe")
        {
            Sdk             = "Microsoft.NET.Sdk";
            TargetFramework = "net5.0-android";

            TargetSdkVersion     = AndroidSdkResolver.GetMaxInstalledPlatform().ToString();
            PackageName          = PackageName ?? string.Format("{0}.{0}", ProjectName);
            JavaPackageName      = JavaPackageName ?? PackageName.ToLowerInvariant();
            GlobalPackagesFolder = Path.Combine(XABuildPaths.TopDirectory, "packages");
            SetProperty(KnownProperties.OutputType, outputType);

            // Add relevant Android content to our project without writing it to the .csproj file
            if (outputType == "Exe")
            {
                Sources.Add(new BuildItem.Source("Properties\\AndroidManifest.xml")
                {
                    TextContent = ProcessManifestTemplate
                });
            }
            Sources.Add(new BuildItem.Source($"MainActivity{Language.DefaultExtension}")
            {
                TextContent = () => ProcessSourceTemplate(MainActivity ?? DefaultMainActivity)
            });
            Sources.Add(new BuildItem.Source("Resources\\layout\\Main.axml")
            {
                TextContent = () => default_layout_main
            });
            Sources.Add(new BuildItem.Source("Resources\\values\\Strings.xml")
            {
                TextContent = () => default_strings_xml.Replace("${PROJECT_NAME}", ProjectName)
            });
            Sources.Add(new BuildItem.Source("Resources\\drawable-mdpi\\Icon.png")
            {
                BinaryContent = () => icon_binary_mdpi
            });
            Sources.Add(new BuildItem.Source($"Resources\\Resource.designer{Language.DefaultExtension}")
            {
                TextContent = () => string.Empty
            });
        }
예제 #7
0
        protected bool BuildInternal(string projectOrSolution, string target, string [] parameters = null, Dictionary <string, string> environmentVariables = null, bool restore = true)
        {
            buildLogFullPath = (!string.IsNullOrEmpty(BuildLogFile))
                                ? Path.GetFullPath(Path.Combine(XABuildPaths.TestOutputDirectory, Path.GetDirectoryName(projectOrSolution), BuildLogFile))
                                : null;
            string processLog = !string.IsNullOrEmpty(BuildLogFile)
                                ? Path.Combine(Path.GetDirectoryName(buildLogFullPath), "process.log")
                                : null;

            var logger = buildLogFullPath == null
                                ? string.Empty
                                : string.Format("/noconsolelogger \"/flp1:LogFile={0};Encoding=UTF-8;Verbosity={1}\"",
                                                buildLogFullPath, Verbosity.ToString().ToLower());

            var start        = DateTime.UtcNow;
            var args         = new StringBuilder();
            var psi          = new ProcessStartInfo(BuildTool);
            var responseFile = Path.Combine(XABuildPaths.TestOutputDirectory, Path.GetDirectoryName(projectOrSolution), "project.rsp");

            if (UseDotNet)
            {
                args.Append("build ");
            }
            args.AppendFormat("{0} /t:{1} {2}",
                              QuoteFileName(Path.Combine(XABuildPaths.TestOutputDirectory, projectOrSolution)), target, logger);
            if (AutomaticNuGetRestore && restore && !UseDotNet)
            {
                args.Append(" /restore");
            }
            args.Append($" @\"{responseFile}\"");
            using (var sw = new StreamWriter(responseFile, append: false, encoding: Encoding.UTF8)) {
                sw.WriteLine($" /p:BuildingInsideVisualStudio={BuildingInsideVisualStudio}");
                if (BuildingInsideVisualStudio)
                {
                    sw.WriteLine(" /p:BuildingOutOfProcess=true");
                }
                string sdkPath = AndroidSdkResolver.GetAndroidSdkPath();
                if (Directory.Exists(sdkPath))
                {
                    sw.WriteLine(" /p:AndroidSdkDirectory=\"{0}\" ", sdkPath);
                }
                string ndkPath = AndroidSdkResolver.GetAndroidNdkPath();
                if (Directory.Exists(ndkPath))
                {
                    sw.WriteLine(" /p:AndroidNdkDirectory=\"{0}\" ", ndkPath);
                }
                string jdkPath = AndroidSdkResolver.GetJavaSdkPath();
                if (Directory.Exists(jdkPath))
                {
                    sw.WriteLine(" /p:JavaSdkDirectory=\"{0}\" ", jdkPath);
                }
                if (parameters != null)
                {
                    foreach (var param in parameters)
                    {
                        sw.WriteLine(" /p:{0}", param);
                    }
                }
                var msbuildArgs = Environment.GetEnvironmentVariable("NUNIT_MSBUILD_ARGS");
                if (!string.IsNullOrEmpty(msbuildArgs))
                {
                    sw.WriteLine(msbuildArgs);
                }

                psi.EnvironmentVariables ["MSBUILD"] = "msbuild";
                sw.WriteLine($" /bl:\"{Path.GetFullPath (Path.Combine (XABuildPaths.TestOutputDirectory, Path.GetDirectoryName (projectOrSolution), "msbuild.binlog"))}\"");

                if (environmentVariables != null)
                {
                    foreach (var kvp in environmentVariables)
                    {
                        psi.EnvironmentVariables [kvp.Key] = kvp.Value;
                    }
                }
            }

            //NOTE: commit messages can "accidentally" cause test failures
            // Consider if you added an error message in a commit message, then wrote a test asserting the error no longer occurs.
            // Both Jenkins and VSTS have an environment variable containing the full commit message, which will inexplicably cause your test to fail...
            // For a Jenkins case, see https://github.com/xamarin/xamarin-android/pull/1049#issuecomment-347625456
            // For a VSTS case, see http://build.devdiv.io/1806783
            psi.EnvironmentVariables ["ghprbPullLongDescription"]       =
                psi.EnvironmentVariables ["BUILD_SOURCEVERSIONMESSAGE"] = "";

            psi.Arguments = args.ToString();

            psi.CreateNoWindow         = true;
            psi.UseShellExecute        = false;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError  = true;
            psi.StandardErrorEncoding  = Encoding.UTF8;
            psi.StandardOutputEncoding = Encoding.UTF8;

            bool             nativeCrashDetected = false;
            bool             result          = false;
            bool             ranToCompletion = false;
            int              attempts        = 1;
            ManualResetEvent err             = new ManualResetEvent(false);
            ManualResetEvent stdout          = new ManualResetEvent(false);

            for (int attempt = 0; attempt < attempts; attempt++)
            {
                if (processLog != null)
                {
                    File.AppendAllText(processLog, psi.FileName + " " + args.ToString() + Environment.NewLine);
                }
                using (var p = new Process()) {
                    p.ErrorDataReceived += (sender, e) => {
                        if (e.Data != null && !string.IsNullOrEmpty(processLog))
                        {
                            File.AppendAllText(processLog, e.Data + Environment.NewLine);
                            if (e.Data.StartsWith(SigSegvError, StringComparison.OrdinalIgnoreCase))
                            {
                                nativeCrashDetected = true;
                            }
                            if (e.Data.StartsWith(ConsoleLoggerError, StringComparison.OrdinalIgnoreCase))
                            {
                                nativeCrashDetected = true;
                            }
                        }
                        if (e.Data == null)
                        {
                            err.Set();
                        }
                    };
                    p.OutputDataReceived += (sender, e) => {
                        if (e.Data != null && !string.IsNullOrEmpty(processLog))
                        {
                            File.AppendAllText(processLog, e.Data + Environment.NewLine);
                            if (e.Data.StartsWith(SigSegvError, StringComparison.OrdinalIgnoreCase))
                            {
                                nativeCrashDetected = true;
                            }
                            if (e.Data.StartsWith(ConsoleLoggerError, StringComparison.OrdinalIgnoreCase))
                            {
                                nativeCrashDetected = true;
                            }
                        }
                        if (e.Data == null)
                        {
                            stdout.Set();
                        }
                    };
                    p.StartInfo = psi;
                    Console.WriteLine($"{psi.FileName} {psi.Arguments}");
                    p.Start();
                    p.BeginOutputReadLine();
                    p.BeginErrorReadLine();
                    ranToCompletion = p.WaitForExit((int)new TimeSpan(0, 15, 0).TotalMilliseconds);
                    if (psi.RedirectStandardOutput)
                    {
                        stdout.WaitOne();
                    }
                    if (psi.RedirectStandardError)
                    {
                        err.WaitOne();
                    }
                    result = ranToCompletion && p.ExitCode == 0;
                }

                LastBuildTime = DateTime.UtcNow - start;

                if (processLog != null && !ranToCompletion)
                {
                    File.AppendAllText(processLog, "Build Timed Out!");
                }
                if (buildLogFullPath != null && File.Exists(buildLogFullPath))
                {
                    foreach (var line in LastBuildOutput)
                    {
                        if (line.StartsWith("Time Elapsed", StringComparison.OrdinalIgnoreCase))
                        {
                            var match = timeElapsedRegEx.Match(line);
                            if (match.Success)
                            {
                                LastBuildTime = TimeSpan.Parse(match.Groups ["TimeSpan"].Value);
                                Console.WriteLine($"Found Time Elapsed {LastBuildTime}");
                            }
                        }
                    }
                }

                if (nativeCrashDetected)
                {
                    Console.WriteLine($"Native crash detected! Running the build for {projectOrSolution} again.");
                    if (attempt == 0)
                    {
                        File.Move(processLog, processLog + ".bak");
                    }
                    nativeCrashDetected = false;
                    continue;
                }
                else
                {
                    break;
                }
            }


            if (buildLogFullPath != null && processLog != null)
            {
                Directory.CreateDirectory(Path.GetDirectoryName(buildLogFullPath));
                if (File.Exists(processLog))
                {
                    File.AppendAllText(buildLogFullPath, File.ReadAllText(processLog));
                }
            }
            if (!result && ThrowOnBuildFailure)
            {
                string message = "Build failure: " + Path.GetFileName(projectOrSolution) + (BuildLogFile != null && File.Exists(buildLogFullPath) ? "Build log recorded at " + buildLogFullPath : null);
                //NOTE: enormous logs will lock up IDE's UI. Build result files should be appended to the TestResult on failure.
                throw new FailedBuildException(message);
            }

            return(result);
        }