Example #1
0
        public bool RunTask()
        {
            Log.LogDebugMessage("ResolveSdksTask:");
            Log.LogDebugMessage("  AndroidApiLevel: {0}", AndroidApiLevel);
            Log.LogDebugMessage("  AndroidSdkBuildToolsVersion: {0}", AndroidSdkBuildToolsVersion);
            Log.LogDebugMessage($"  {nameof (AndroidSdkPath)}: {AndroidSdkPath}");
            Log.LogDebugMessage($"  {nameof (AndroidNdkPath)}: {AndroidNdkPath}");
            Log.LogDebugTaskItems("  ReferenceAssemblyPaths: ", ReferenceAssemblyPaths);
            Log.LogDebugMessage("  TargetFrameworkVersion: {0}", TargetFrameworkVersion);
            Log.LogDebugMessage("  UseLatestAndroidPlatformSdk: {0}", UseLatestAndroidPlatformSdk);
            Log.LogDebugMessage("  SequencePointsMode: {0}", SequencePointsMode);
            Log.LogDebugMessage("  LintToolPath: {0}", LintToolPath);

            // OS X:    $prefix/lib/xamarin.android/xbuild/Xamarin/Android
            // Windows: %ProgramFiles(x86)%\MSBuild\Xamarin\Android
            if (string.IsNullOrEmpty(MonoAndroidToolsPath))
            {
                MonoAndroidToolsPath = Path.GetDirectoryName(typeof(ResolveSdks).Assembly.Location);
            }
            MonoAndroidBinPath = MonoAndroidHelper.GetOSBinPath() + Path.DirectorySeparatorChar;

            MonoAndroidHelper.RefreshMonoDroidSdk(MonoAndroidToolsPath, null, ReferenceAssemblyPaths);
            MonoAndroidHelper.RefreshAndroidSdk(AndroidSdkPath, AndroidNdkPath, JavaSdkPath);

            this.AndroidNdkPath = AndroidSdk.AndroidNdkPath;
            this.AndroidSdkPath = AndroidSdk.AndroidSdkPath;
            this.JavaSdkPath    = AndroidSdk.JavaSdkPath;

            if (string.IsNullOrEmpty(AndroidSdkPath))
            {
                Log.LogCodedError("XA5205", "The Android SDK Directory could not be found. Please set via /p:AndroidSdkDirectory.");
                return(false);
            }

            string toolsZipAlignPath = Path.Combine(AndroidSdkPath, "tools", ZipAlign);
            bool   findZipAlign      = (string.IsNullOrEmpty(ZipAlignPath) || !Directory.Exists(ZipAlignPath)) && !File.Exists(toolsZipAlignPath);

            var lintPaths = new string [] {
                LintToolPath ?? string.Empty,
                Path.Combine(AndroidSdkPath, "tools"),
                Path.Combine(AndroidSdkPath, "tools", "bin"),
            };

            LintToolPath = null;
            foreach (var path in lintPaths)
            {
                if (File.Exists(Path.Combine(path, Lint)))
                {
                    LintToolPath = path;
                    break;
                }
            }

            foreach (var dir in AndroidSdk.GetBuildToolsPaths(AndroidSdkBuildToolsVersion))
            {
                Log.LogDebugMessage("Trying build-tools path: {0}", dir);
                if (dir == null || !Directory.Exists(dir))
                {
                    continue;
                }

                var toolsPaths = new string[] {
                    Path.Combine(dir),
                    Path.Combine(dir, "bin"),
                };

                string aapt = toolsPaths.FirstOrDefault(x => File.Exists(Path.Combine(x, Aapt)));
                if (string.IsNullOrEmpty(aapt))
                {
                    Log.LogDebugMessage("Could not find `{0}`; tried: {1}", Aapt,
                                        string.Join(";", toolsPaths.Select(x => Path.Combine(x, Aapt))));
                    continue;
                }
                AndroidSdkBuildToolsPath    = Path.GetFullPath(dir);
                AndroidSdkBuildToolsBinPath = Path.GetFullPath(aapt);

                string zipalign = toolsPaths.FirstOrDefault(x => File.Exists(Path.Combine(x, ZipAlign)));
                if (findZipAlign && string.IsNullOrEmpty(zipalign))
                {
                    Log.LogDebugMessage("Could not find `{0}`; tried: {1}", ZipAlign,
                                        string.Join(";", toolsPaths.Select(x => Path.Combine(x, ZipAlign))));
                    continue;
                }
                else
                {
                    break;
                }
            }

            if (string.IsNullOrEmpty(AndroidSdkBuildToolsPath))
            {
                Log.LogCodedError("XA5205",
                                  string.Format(
                                      "Cannot find `{0}`. Please install the Android SDK Build-tools package with the `{1}{2}tools{2}{3}` program.",
                                      Aapt, AndroidSdkPath, Path.DirectorySeparatorChar, Android));
                return(false);
            }

            if (string.IsNullOrEmpty(ZipAlignPath) || !Directory.Exists(ZipAlignPath))
            {
                ZipAlignPath = new[] {
                    Path.Combine(AndroidSdkBuildToolsPath),
                    Path.Combine(AndroidSdkBuildToolsBinPath),
                    Path.Combine(AndroidSdkPath, "tools"),
                }
                .Where(p => File.Exists(Path.Combine(p, ZipAlign)))
                .FirstOrDefault();
            }
            if (string.IsNullOrEmpty(ZipAlignPath))
            {
                Log.LogCodedError("XA5205",
                                  string.Format(
                                      "Cannot find `{0}`. Please install the Android SDK Build-tools package with the `{1}{2}tools{2}{3}` program.",
                                      ZipAlign, AndroidSdkPath, Path.DirectorySeparatorChar, Android));
                return(false);
            }

            if (!ValidateApiLevels())
            {
                return(false);
            }

            string frameworksPath = Path.GetDirectoryName(MonoDroidSdk.FrameworkPath);

            if (!Directory.Exists(Path.Combine(frameworksPath, TargetFrameworkVersion)))
            {
                Log.LogError(
                    subcategory:      string.Empty,
                    errorCode:        "XA0001",
                    helpKeyword:      string.Empty,
                    file:             ProjectFilePath,
                    lineNumber:       0,
                    columnNumber:     0,
                    endLineNumber:    0,
                    endColumnNumber:  0,
                    message:          "Unsupported or invalid $(TargetFrameworkVersion) value of '{0}'. Please update your Project Options.",
                    messageArgs:      new[] {
                    TargetFrameworkVersion,
                }
                    );
                return(false);
            }

            SequencePointsMode mode;

            if (!Aot.TryGetSequencePointsMode(SequencePointsMode ?? "None", out mode))
            {
                Log.LogCodedError("XA0104", "Invalid Sequence Point mode: {0}", SequencePointsMode);
            }
            AndroidSequencePointsMode = mode.ToString();

            MonoAndroidHelper.TargetFrameworkDirectories = ReferenceAssemblyPaths;

            AndroidApiLevelName = MonoAndroidHelper.GetPlatformApiLevelName(AndroidApiLevel);

            Log.LogDebugMessage("ResolveSdksTask Outputs:");
            Log.LogDebugMessage("  AndroidApiLevel: {0}", AndroidApiLevel);
            Log.LogDebugMessage("  AndroidApiLevelName: {0}", AndroidApiLevelName);
            Log.LogDebugMessage("  AndroidNdkPath: {0}", AndroidNdkPath);
            Log.LogDebugMessage("  AndroidSdkBuildToolsPath: {0}", AndroidSdkBuildToolsPath);
            Log.LogDebugMessage("  AndroidSdkBuildToolsBinPath: {0}", AndroidSdkBuildToolsBinPath);
            Log.LogDebugMessage("  AndroidSdkPath: {0}", AndroidSdkPath);
            Log.LogDebugMessage("  JavaSdkPath: {0}", JavaSdkPath);
            Log.LogDebugMessage("  MonoAndroidBinPath: {0}", MonoAndroidBinPath);
            Log.LogDebugMessage("  MonoAndroidToolsPath: {0}", MonoAndroidToolsPath);
            Log.LogDebugMessage("  TargetFrameworkVersion: {0}", TargetFrameworkVersion);
            Log.LogDebugMessage("  ZipAlignPath: {0}", ZipAlignPath);
            Log.LogDebugMessage("  SupportedApiLevel: {0}", SupportedApiLevel);
            Log.LogDebugMessage("  AndroidSequencePointMode: {0}", AndroidSequencePointsMode);
            Log.LogDebugMessage("  LintToolPath: {0}", LintToolPath);

            if (!string.IsNullOrEmpty(CacheFile))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(CacheFile));

                var document = new XDocument(
                    new XDeclaration("1.0", "UTF-8", null),
                    new XElement("Sdk",
                                 new XElement("AndroidApiLevel", AndroidApiLevel),
                                 new XElement("AndroidApiLevelName", AndroidApiLevelName),
                                 new XElement("AndroidNdkPath", AndroidNdkPath),
                                 new XElement("AndroidSdkBuildToolsPath", AndroidSdkBuildToolsPath),
                                 new XElement("AndroidSdkBuildToolsBinPath", AndroidSdkBuildToolsBinPath),
                                 new XElement("AndroidSdkPath", AndroidSdkPath),
                                 new XElement("JavaSdkPath", JavaSdkPath),
                                 new XElement("MonoAndroidBinPath", MonoAndroidBinPath),
                                 new XElement("MonoAndroidToolsPath", MonoAndroidToolsPath),
                                 new XElement("ReferenceAssemblyPaths",
                                              (ReferenceAssemblyPaths ?? new string [0])
                                              .Select(e => new XElement("ReferenceAssemblyPath", e))),
                                 new XElement("TargetFrameworkVersion", TargetFrameworkVersion),
                                 new XElement("ZipAlignPath", ZipAlignPath),
                                 new XElement("MonoAndroidIncludePath", MonoAndroidIncludePath),
                                 new XElement("SupportedApiLevel", SupportedApiLevel),
                                 new XElement("AndroidSequencePointsMode", AndroidSequencePointsMode.ToString()),
                                 new XElement("LintToolPath", LintToolPath)
                                 ));
                document.Save(CacheFile);
            }

            //note: this task does not error out if it doesn't find all things. that's the job of the targets
            return(!Log.HasLoggedErrors);
        }
Example #2
0
        /// <summary>
        /// Generates a Package.proj file for MSBuild to invoke
        /// - Generates Resource.designer.dll for rewiring resource values from the final Java project
        /// - Links .NET assemblies and places output into /android/assets/assemblies
        /// - Extracts assets and resources from Android library projects into /obj/
        /// - Copies assets and resources into AAR
        /// - Invokes aapt to generate R.txt
        /// - One day I would like to get rid of the temp files, but I could not get the MSBuild APIs to work in-process
        /// </summary>
        public static string GeneratePackageProject(List <IKVM.Reflection.Assembly> assemblies, string outputDirectory, string assembliesDirectory)
        {
            var mainAssembly = assemblies[0].Location;

            outputDirectory     = Path.GetFullPath(outputDirectory);
            assembliesDirectory = Path.GetFullPath(assembliesDirectory);

            var androidDir   = Path.Combine(outputDirectory, "android");
            var assetsDir    = Path.Combine(androidDir, "assets");
            var resourceDir  = Path.Combine(androidDir, "res");
            var manifestPath = Path.Combine(androidDir, "AndroidManifest.xml");
            var packageName  = Generators.JavaGenerator.GetNativeLibPackageName(mainAssembly);
            var project      = CreateProject();
            var target       = project.AddTarget("Build");

            //Generate Resource.designer.dll
            var resourceDesigner = new ResourceDesignerGenerator
            {
                Assemblies      = assemblies,
                MainAssembly    = mainAssembly,
                OutputDirectory = outputDirectory,
                PackageName     = packageName,
            };

            resourceDesigner.Generate();

            if (!resourceDesigner.WriteAssembly())
            {
                //Let's generate CS if this failed
                string resourcePath = resourceDesigner.WriteSource();
                throw new Exception($"Resource.designer.dll compilation failed! See {resourcePath} for details.");
            }

            //ResolveAssemblies Task
            ResolveAssemblies(target, mainAssembly);

            //LinkAssemblies Task
            var linkAssemblies = target.AddTask("LinkAssemblies");

            linkAssemblies.SetParameter("UseSharedRuntime", "False");
            linkAssemblies.SetParameter("LinkMode", LinkMode);
            linkAssemblies.SetParameter("LinkDescriptions", "@(LinkDescription)");
            linkAssemblies.SetParameter("DumpDependencies", "True");
            linkAssemblies.SetParameter("ResolvedAssemblies", "@(ResolvedAssemblies);" + Path.Combine(outputDirectory, "Resource.designer.dll"));
            linkAssemblies.SetParameter("MainAssembly", mainAssembly);
            linkAssemblies.SetParameter("OutputDirectory", assembliesDirectory);

            //Aapt Task to generate R.txt
            var aapt = target.AddTask("Aapt");

            aapt.SetParameter("ImportsDirectory", outputDirectory);
            aapt.SetParameter("OutputImportDirectory", outputDirectory);
            aapt.SetParameter("ManifestFiles", manifestPath);
            aapt.SetParameter("ApplicationName", packageName);
            aapt.SetParameter("JavaPlatformJarPath", Path.Combine(XamarinAndroid.PlatformDirectory, "android.jar"));
            aapt.SetParameter("JavaDesignerOutputDirectory", outputDirectory);
            aapt.SetParameter("AssetDirectory", assetsDir);
            aapt.SetParameter("ResourceDirectory", resourceDir);
            aapt.SetParameter("ToolPath", AndroidSdk.GetBuildToolsPaths().First());
            aapt.SetParameter("ToolExe", "aapt");
            aapt.SetParameter("ApiLevel", XamarinAndroid.TargetSdkVersion);
            aapt.SetParameter("ExtraArgs", "--output-text-symbols " + androidDir);

            //There is an extra /manifest/AndroidManifest.xml file created
            var removeDir = target.AddTask("RemoveDir");

            removeDir.SetParameter("Directories", Path.Combine(androidDir, "manifest"));

            //NOTE: might avoid the temp file later
            var projectFile = Path.Combine(outputDirectory, "Package.proj");

            project.Save(projectFile);
            return(projectFile);
        }
        /// <summary>
        /// Generates a Package.proj file for MSBuild to invoke
        /// - Generates Resource.designer.dll for rewiring resource values from the final Java project
        /// - Links .NET assemblies and places output into /android/assets/assemblies
        /// - Extracts assets and resources from Android library projects into /obj/
        /// - Copies assets and resources into AAR
        /// - Invokes aapt to generate R.txt
        /// - One day I would like to get rid of the temp files, but I could not get the MSBuild APIs to work in-process
        /// </summary>
        public static string GeneratePackageProject(List <IKVM.Reflection.Assembly> assemblies, Options options)
        {
            var mainAssembly        = assemblies[0].Location;
            var outputDirectory     = Path.GetFullPath(options.OutputDir);
            var assembliesDirectory = Path.Combine(outputDirectory, "android", "assets", "assemblies");

            var androidDir   = Path.Combine(outputDirectory, "android");
            var assetsDir    = Path.Combine(androidDir, "assets");
            var resourceDir  = Path.Combine(androidDir, "res");
            var manifestPath = Path.Combine(androidDir, "AndroidManifest.xml");
            var packageName  = Generators.JavaGenerator.GetNativeLibPackageName(mainAssembly);
            var project      = CreateProject();
            var target       = project.AddTarget("Build");

            //ResolveAssemblies Task
            ResolveAssemblies(target, assemblies);

            //LinkAssemblies Task
            var linkAssemblies = target.AddTask("LinkAssemblies");

            linkAssemblies.SetParameter("UseSharedRuntime", "False");
            linkAssemblies.SetParameter("LinkMode", LinkMode);
            linkAssemblies.SetParameter("LinkDescriptions", "@(LinkDescription)");
            linkAssemblies.SetParameter("DumpDependencies", "True");
            linkAssemblies.SetParameter("ResolvedAssemblies", "@(ResolvedAssemblies);" + Path.Combine(outputDirectory, "Resource.designer.dll"));
            linkAssemblies.SetParameter("MainAssembly", mainAssembly);
            linkAssemblies.SetParameter("OutputDirectory", assembliesDirectory);

            //If not Debug, delete our PDB files
            if (!options.Compilation.DebugMode)
            {
                var itemGroup = target.AddItemGroup();
                itemGroup.AddItem("PdbFilesToDelete", Path.Combine(assembliesDirectory, "*.pdb"));

                var delete = target.AddTask("Delete");
                delete.SetParameter("Files", "@(PdbFilesToDelete)");
            }

            //Aapt Task to generate R.txt
            var aapt = target.AddTask("Aapt");

            aapt.SetParameter("ImportsDirectory", outputDirectory);
            aapt.SetParameter("OutputImportDirectory", outputDirectory);
            aapt.SetParameter("ManifestFiles", manifestPath);
            aapt.SetParameter("ApplicationName", packageName);
            aapt.SetParameter("JavaPlatformJarPath", Path.Combine(XamarinAndroid.PlatformDirectory, "android.jar"));
            aapt.SetParameter("JavaDesignerOutputDirectory", outputDirectory);
            aapt.SetParameter("AssetDirectory", assetsDir);
            aapt.SetParameter("ResourceDirectory", resourceDir);
            aapt.SetParameter("ToolPath", AndroidSdk.GetBuildToolsPaths().First());
            aapt.SetParameter("ToolExe", "aapt");
            aapt.SetParameter("ApiLevel", XamarinAndroid.TargetSdkVersion);
            aapt.SetParameter("ExtraArgs", "--output-text-symbols " + androidDir);

            //There is an extra /manifest/AndroidManifest.xml file created
            var removeDir = target.AddTask("RemoveDir");

            removeDir.SetParameter("Directories", Path.Combine(androidDir, "manifest"));

            //NOTE: might avoid the temp file later
            var projectFile = Path.Combine(outputDirectory, "Package.proj");

            project.Save(projectFile);
            return(projectFile);
        }