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); }
/// <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); }