public override bool Execute() { tempFile = OutputManifestFile + ".tmp"; responseFile = Path.Combine(Path.GetDirectoryName(OutputManifestFile), "manifestmerger.rsp"); try { bool result = base.Execute(); if (!result) { return(result); } var m = new ManifestDocument(tempFile, Log); using (var ms = new MemoryStream()) { m.Save(ms); MonoAndroidHelper.CopyIfStreamChanged(ms, OutputManifestFile); return(result); } } finally { if (File.Exists(tempFile)) { File.Delete(tempFile); } if (File.Exists(responseFile)) { File.Delete(responseFile); } } }
public override bool Execute() { tempFile = OutputManifestFile + ".tmp"; responseFile = Path.Combine(Path.GetDirectoryName(OutputManifestFile), "manifestmerger.rsp"); try { bool result = base.Execute(); if (!result) { return(result); } var m = new ManifestDocument(tempFile); var ms = MemoryStreamPool.Shared.Rent(); try { m.Save(Log, ms, removeNodes: true); if (!MonoAndroidHelper.CopyIfStreamChanged(ms, OutputManifestFile)) { // NOTE: We still need to update the timestamp on this file, or the target would run again File.SetLastWriteTimeUtc(OutputManifestFile, DateTime.UtcNow); } return(result); } finally { MemoryStreamPool.Shared.Return(ms); } } finally { if (File.Exists(tempFile)) { File.Delete(tempFile); } if (File.Exists(responseFile)) { File.Delete(responseFile); } } }
protected string GenerateCommandLineCommands(string ManifestFile, string currentAbi, string currentResourceOutputFile) { // For creating Resource.Designer.cs: // Running command: C:\Program Files (x86)\Android\android-sdk-windows\platform-tools\aapt // "package" // "-M" "C:\Users\Jonathan\AppData\Local\Temp\ryob4gaw.way\AndroidManifest.xml" // "-J" "C:\Users\Jonathan\AppData\Local\Temp\ryob4gaw.way" // "-F" "C:\Users\Jonathan\AppData\Local\Temp\ryob4gaw.way\resources.apk" // "-S" "c:\users\jonathan\documents\visual studio 2010\Projects\MonoAndroidApplication4\MonoAndroidApplication4\obj\Debug\res" // "-I" "C:\Program Files (x86)\Android\android-sdk-windows\platforms\android-8\android.jar" // "--max-res-version" "10" // For packaging: // Running command: C:\Program Files (x86)\Android\android-sdk-windows\platform-tools\aapt // "package" // "-f" // "-m" // "-M" "AndroidManifest.xml" // "-J" "src" // "--custom-package" "androidmsbuildtest.androidmsbuildtest" // "-F" "bin\packaged_resources" // "-S" "C:\Users\Jonathan\Documents\Visual Studio 2010\Projects\AndroidMSBuildTest\AndroidMSBuildTest\obj\Debug\res" // "-I" "C:\Program Files (x86)\Android\android-sdk-windows\platforms\android-8\android.jar" // "--extra-packages" "com.facebook.android:my.another.library" var cmd = new CommandLineBuilder(); cmd.AppendSwitch("package"); if (MonoAndroidHelper.LogInternalExceptions) { cmd.AppendSwitch("-v"); } if (NonConstantId) { cmd.AppendSwitch("--non-constant-id"); } cmd.AppendSwitch("-f"); cmd.AppendSwitch("-m"); string manifestFile; string manifestDir = Path.Combine(Path.GetDirectoryName(ManifestFile), currentAbi != null ? currentAbi : "manifest"); Directory.CreateDirectory(manifestDir); manifestFile = Path.Combine(manifestDir, Path.GetFileName(ManifestFile)); ManifestDocument manifest = new ManifestDocument(ManifestFile, this.Log); if (currentAbi != null) { manifest.SetAbi(currentAbi); } manifest.ApplicationName = ApplicationName; manifest.Save(manifestFile); cmd.AppendSwitchIfNotNull("-M ", manifestFile); Directory.CreateDirectory(JavaDesignerOutputDirectory); cmd.AppendSwitchIfNotNull("-J ", JavaDesignerOutputDirectory); if (PackageName != null) { cmd.AppendSwitchIfNotNull("--custom-package ", PackageName.ToLowerInvariant()); } if (!string.IsNullOrEmpty(currentResourceOutputFile)) { cmd.AppendSwitchIfNotNull("-F ", currentResourceOutputFile + ".bk"); } // The order of -S arguments is *important*, always make sure this one comes FIRST cmd.AppendSwitchIfNotNull("-S ", ResourceDirectory.TrimEnd('\\')); if (AdditionalResourceDirectories != null) { foreach (var resdir in AdditionalResourceDirectories) { cmd.AppendSwitchIfNotNull("-S ", resdir.ItemSpec.TrimEnd('\\')); } } if (AdditionalAndroidResourcePaths != null) { foreach (var dir in AdditionalAndroidResourcePaths) { cmd.AppendSwitchIfNotNull("-S ", Path.Combine(dir.ItemSpec.TrimEnd(System.IO.Path.DirectorySeparatorChar), "res")); } } if (LibraryProjectJars != null) { foreach (var jar in LibraryProjectJars) { cmd.AppendSwitchIfNotNull("-j ", jar); } } cmd.AppendSwitchIfNotNull("-I ", JavaPlatformJarPath); // Add asset directory if it exists if (!string.IsNullOrWhiteSpace(AssetDirectory) && Directory.Exists(AssetDirectory)) { cmd.AppendSwitchIfNotNull("-A ", AssetDirectory.TrimEnd('\\')); } if (!string.IsNullOrWhiteSpace(UncompressedFileExtensions)) { foreach (var ext in UncompressedFileExtensions.Split(new char[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries)) { cmd.AppendSwitchIfNotNull("-0 ", ext); } } if (!string.IsNullOrEmpty(ExtraPackages)) { cmd.AppendSwitchIfNotNull("--extra-packages ", ExtraPackages); } // TODO: handle resource names if (ExplicitCrunch) { cmd.AppendSwitch("--no-crunch"); } cmd.AppendSwitch("--auto-add-overlay"); var extraArgsExpanded = ExpandString(ExtraArgs); if (extraArgsExpanded != ExtraArgs) { Log.LogDebugMessage(" ExtraArgs expanded: {0}", extraArgsExpanded); } if (!string.IsNullOrWhiteSpace(extraArgsExpanded)) { cmd.AppendSwitch(extraArgsExpanded); } if (!AndroidUseLatestPlatformSdk) { cmd.AppendSwitchIfNotNull("--max-res-version ", ApiLevel); } return(cmd.ToString()); }
string GenerateCommandLineCommands(string ManifestFile, string currentAbi, string currentResourceOutputFile) { var cmd = new CommandLineBuilder(); cmd.AppendSwitch("link"); if (MonoAndroidHelper.LogInternalExceptions) { cmd.AppendSwitch("-v"); } string manifestDir = Path.Combine(Path.GetDirectoryName(ManifestFile), currentAbi != null ? currentAbi : "manifest"); Directory.CreateDirectory(manifestDir); string manifestFile = Path.Combine(manifestDir, Path.GetFileName(ManifestFile)); ManifestDocument manifest = new ManifestDocument(ManifestFile, this.Log); manifest.SdkVersion = AndroidSdkPlatform; if (!string.IsNullOrEmpty(VersionCodePattern)) { try { manifest.CalculateVersionCode(currentAbi, VersionCodePattern, VersionCodeProperties); } catch (ArgumentOutOfRangeException ex) { Log.LogCodedError("XA0003", ManifestFile, 0, ex.Message); return(string.Empty); } } if (currentAbi != null && string.IsNullOrEmpty(VersionCodePattern)) { manifest.SetAbi(currentAbi); } if (!manifest.ValidateVersionCode(out string error, out string errorCode)) { Log.LogCodedError(errorCode, ManifestFile, 0, error); return(string.Empty); } manifest.ApplicationName = ApplicationName; manifest.Save(manifestFile); cmd.AppendSwitchIfNotNull("--manifest ", manifestFile); if (!string.IsNullOrEmpty(JavaDesignerOutputDirectory)) { var designerDirectory = Path.IsPathRooted(JavaDesignerOutputDirectory) ? JavaDesignerOutputDirectory : Path.Combine(WorkingDirectory, JavaDesignerOutputDirectory); Directory.CreateDirectory(designerDirectory); cmd.AppendSwitchIfNotNull("--java ", JavaDesignerOutputDirectory); } if (PackageName != null) { cmd.AppendSwitchIfNotNull("--custom-package ", PackageName.ToLowerInvariant()); } if (AdditionalResourceArchives != null) { foreach (var item in AdditionalResourceArchives) { var flata = Path.Combine(WorkingDirectory, item.ItemSpec); if (File.Exists(flata)) { cmd.AppendSwitchIfNotNull("-R ", flata); } else { Log.LogDebugMessage("Archive does not exist: " + flata); } } } if (CompiledResourceFlatArchive != null) { var flata = Path.Combine(WorkingDirectory, CompiledResourceFlatArchive.ItemSpec); if (File.Exists(flata)) { cmd.AppendSwitchIfNotNull("-R ", flata); } else { Log.LogDebugMessage("Archive does not exist: " + flata); } } cmd.AppendSwitch("--auto-add-overlay"); if (!string.IsNullOrWhiteSpace(UncompressedFileExtensions)) { foreach (var ext in UncompressedFileExtensions.Split(new char [] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries)) { cmd.AppendSwitchIfNotNull("-0 ", ext); } } if (!string.IsNullOrEmpty(ExtraPackages)) { cmd.AppendSwitchIfNotNull("--extra-packages ", ExtraPackages); } cmd.AppendSwitchIfNotNull("-I ", JavaPlatformJarPath); if (!string.IsNullOrEmpty(ResourceSymbolsTextFile)) { cmd.AppendSwitchIfNotNull("--output-text-symbols ", ResourceSymbolsTextFile); } if (ProtobufFormat) { cmd.AppendSwitch("--proto-format"); } var extraArgsExpanded = ExpandString(ExtraArgs); if (extraArgsExpanded != ExtraArgs) { Log.LogDebugMessage(" ExtraArgs expanded: {0}", extraArgsExpanded); } if (!string.IsNullOrWhiteSpace(extraArgsExpanded)) { cmd.AppendSwitch(extraArgsExpanded); } if (!string.IsNullOrWhiteSpace(AssetsDirectory)) { var assetDir = AssetsDirectory.TrimEnd('\\'); if (!Path.IsPathRooted(assetDir)) { assetDir = Path.Combine(WorkingDirectory, assetDir); } if (!string.IsNullOrWhiteSpace(assetDir) && Directory.Exists(assetDir)) { cmd.AppendSwitchIfNotNull("-A ", assetDir); } } cmd.AppendSwitchIfNotNull("-o ", currentResourceOutputFile); return(cmd.ToString()); }
string [] GenerateCommandLineCommands(string ManifestFile, string currentAbi, string currentResourceOutputFile) { List <string> cmd = new List <string> (); string manifestDir = Path.Combine(Path.GetDirectoryName(ManifestFile), currentAbi != null ? currentAbi : "manifest"); Directory.CreateDirectory(manifestDir); string manifestFile = Path.Combine(manifestDir, Path.GetFileName(ManifestFile)); ManifestDocument manifest = new ManifestDocument(ManifestFile); manifest.SdkVersion = AndroidSdkPlatform; if (!string.IsNullOrEmpty(VersionCodePattern)) { try { manifest.CalculateVersionCode(currentAbi, VersionCodePattern, VersionCodeProperties); } catch (ArgumentOutOfRangeException ex) { LogCodedError("XA0003", ManifestFile, 0, ex.Message); return(cmd.ToArray()); } } if (currentAbi != null && string.IsNullOrEmpty(VersionCodePattern)) { manifest.SetAbi(currentAbi); } if (!manifest.ValidateVersionCode(out string error, out string errorCode)) { LogCodedError(errorCode, ManifestFile, 0, error); return(cmd.ToArray()); } manifest.ApplicationName = ApplicationName; manifest.Save(LogCodedWarning, manifestFile); cmd.Add("link"); if (MonoAndroidHelper.LogInternalExceptions) { cmd.Add("-v"); } cmd.Add($"--manifest"); cmd.Add(GetFullPath(manifestFile)); if (!string.IsNullOrEmpty(JavaDesignerOutputDirectory)) { var designerDirectory = Path.IsPathRooted(JavaDesignerOutputDirectory) ? JavaDesignerOutputDirectory : Path.Combine(WorkingDirectory, JavaDesignerOutputDirectory); Directory.CreateDirectory(designerDirectory); cmd.Add("--java"); cmd.Add(GetFullPath(JavaDesignerOutputDirectory)); } if (PackageName != null) { cmd.Add("--custom-package"); cmd.Add(PackageName.ToLowerInvariant()); } if (AdditionalResourceArchives != null) { for (int i = AdditionalResourceArchives.Length - 1; i >= 0; i--) { var flata = GetFullPath(AdditionalResourceArchives [i].ItemSpec); if (Directory.Exists(flata)) { foreach (var line in Directory.EnumerateFiles(flata, "*.flat", SearchOption.TopDirectoryOnly)) { cmd.Add("-R"); cmd.Add(GetFullPath(line)); } } else if (File.Exists(flata)) { cmd.Add("-R"); cmd.Add(flata); } else { LogDebugMessage($"Archive does not exist: {flata}"); } } } if (CompiledResourceFlatArchive != null) { var flata = GetFullPath(CompiledResourceFlatArchive.ItemSpec); if (Directory.Exists(flata)) { foreach (var line in Directory.EnumerateFiles(flata, "*.flat", SearchOption.TopDirectoryOnly)) { cmd.Add("-R"); cmd.Add(GetFullPath(line)); } } else if (File.Exists(flata)) { cmd.Add("-R"); cmd.Add(flata); } else { LogDebugMessage($"Archive does not exist: {flata}"); } } if (CompiledResourceFlatFiles != null) { var appFiles = new List <string> (); for (int i = CompiledResourceFlatFiles.Length - 1; i >= 0; i--) { var file = CompiledResourceFlatFiles [i]; var fullPath = GetFullPath(file.ItemSpec); if (!File.Exists(fullPath)) { LogDebugMessage($"File does not exist: {fullPath}"); } else if (!string.IsNullOrEmpty(file.GetMetadata("ResourceDirectory"))) { cmd.Add("-R"); cmd.Add(fullPath); } else { appFiles.Add(fullPath); } } foreach (var fullPath in appFiles) { cmd.Add("-R"); cmd.Add(fullPath); } } cmd.Add("--auto-add-overlay"); if (!string.IsNullOrWhiteSpace(UncompressedFileExtensions)) { foreach (var ext in UncompressedFileExtensions.Split(new char [] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries)) { cmd.Add("-0"); cmd.Add(ext.StartsWith(".", StringComparison.OrdinalIgnoreCase) ? ext : $".{ext}"); } } if (!string.IsNullOrEmpty(ExtraPackages)) { cmd.Add("--extra-packages"); cmd.Add(ExtraPackages); } cmd.Add("-I"); cmd.Add(GetFullPath(JavaPlatformJarPath)); if (!string.IsNullOrEmpty(ResourceSymbolsTextFile)) { cmd.Add("--output-text-symbols"); cmd.Add(GetFullPath(ResourceSymbolsTextFile)); } if (ProtobufFormat) { cmd.Add("--proto-format"); } if (!string.IsNullOrWhiteSpace(ExtraArgs)) { foreach (Match match in exraArgSplitRegEx.Matches(ExtraArgs)) { string value = match.Value.Trim(' ', '"', '\''); if (!string.IsNullOrEmpty(value)) { cmd.Add(value); } } } // When adding Assets the first item found takes precedence. // So we need to add the applicaiton Assets first. if (!string.IsNullOrEmpty(AssetsDirectory)) { var assetDir = GetFullPath(AssetsDirectory.TrimEnd('\\')); if (Directory.Exists(assetDir)) { cmd.Add("-A"); cmd.Add(assetDir); } else { LogDebugMessage($"asset directory did not exist: {assetDir}"); } } if (AdditionalAndroidAssetPaths != null) { for (int i = 0; i < AdditionalAndroidAssetPaths.Length; i++) { var assetDir = GetFullPath(AdditionalAndroidAssetPaths [i].ItemSpec.TrimEnd('\\')); if (!string.IsNullOrWhiteSpace(assetDir)) { if (Directory.Exists(assetDir)) { cmd.Add("-A"); cmd.Add(GetFullPath(assetDir)); } else { LogDebugMessage($"asset directory did not exist: {assetDir}"); } } } } if (!string.IsNullOrEmpty(ProguardRuleOutput)) { cmd.Add("--proguard"); cmd.Add(GetFullPath(proguardRuleOutputTemp)); } cmd.Add("-o"); cmd.Add(GetFullPath(currentResourceOutputFile)); return(cmd.ToArray()); }
protected string GenerateCommandLineCommands(string ManifestFile, string currentAbi, string currentResourceOutputFile) { // For creating Resource.designer.cs: // Running command: C:\Program Files (x86)\Android\android-sdk-windows\platform-tools\aapt // "package" // "-M" "C:\Users\Jonathan\AppData\Local\Temp\ryob4gaw.way\AndroidManifest.xml" // "-J" "C:\Users\Jonathan\AppData\Local\Temp\ryob4gaw.way" // "-F" "C:\Users\Jonathan\AppData\Local\Temp\ryob4gaw.way\resources.apk" // "-S" "c:\users\jonathan\documents\visual studio 2010\Projects\MonoAndroidApplication4\MonoAndroidApplication4\obj\Debug\res" // "-I" "C:\Program Files (x86)\Android\android-sdk-windows\platforms\android-8\android.jar" // "--max-res-version" "10" // For packaging: // Running command: C:\Program Files (x86)\Android\android-sdk-windows\platform-tools\aapt // "package" // "-f" // "-m" // "-M" "AndroidManifest.xml" // "-J" "src" // "--custom-package" "androidmsbuildtest.androidmsbuildtest" // "-F" "bin\packaged_resources" // "-S" "C:\Users\Jonathan\Documents\Visual Studio 2010\Projects\AndroidMSBuildTest\AndroidMSBuildTest\obj\Debug\res" // "-I" "C:\Program Files (x86)\Android\android-sdk-windows\platforms\android-8\android.jar" // "--extra-packages" "com.facebook.android:my.another.library" var cmd = new CommandLineBuilder(); cmd.AppendSwitch("package"); if (MonoAndroidHelper.LogInternalExceptions) { cmd.AppendSwitch("-v"); } if (NonConstantId) { cmd.AppendSwitch("--non-constant-id"); } cmd.AppendSwitch("-f"); cmd.AppendSwitch("-m"); string manifestFile; string manifestDir = Path.Combine(Path.GetDirectoryName(ManifestFile), currentAbi != null ? currentAbi : "manifest"); Directory.CreateDirectory(manifestDir); manifestFile = Path.Combine(manifestDir, Path.GetFileName(ManifestFile)); ManifestDocument manifest = new ManifestDocument(ManifestFile); manifest.SdkVersion = AndroidSdkPlatform; if (!string.IsNullOrEmpty(VersionCodePattern)) { try { manifest.CalculateVersionCode(currentAbi, VersionCodePattern, VersionCodeProperties); } catch (ArgumentOutOfRangeException ex) { LogCodedError("XA0003", ManifestFile, 0, ex.Message); return(string.Empty); } } if (currentAbi != null && string.IsNullOrEmpty(VersionCodePattern)) { manifest.SetAbi(currentAbi); } if (!manifest.ValidateVersionCode(out string error, out string errorCode)) { LogCodedError(errorCode, ManifestFile, 0, error); return(string.Empty); } manifest.ApplicationName = ApplicationName; manifest.Save(LogCodedWarning, manifestFile); cmd.AppendSwitchIfNotNull("-M ", manifestFile); var designerDirectory = Path.IsPathRooted(JavaDesignerOutputDirectory) ? JavaDesignerOutputDirectory : Path.Combine(WorkingDirectory, JavaDesignerOutputDirectory); Directory.CreateDirectory(designerDirectory); cmd.AppendSwitchIfNotNull("-J ", JavaDesignerOutputDirectory); if (PackageName != null) { cmd.AppendSwitchIfNotNull("--custom-package ", PackageName.ToLowerInvariant()); } if (!string.IsNullOrEmpty(currentResourceOutputFile)) { cmd.AppendSwitchIfNotNull("-F ", currentResourceOutputFile + ".bk"); } // The order of -S arguments is *important*, always make sure this one comes FIRST cmd.AppendSwitchIfNotNull("-S ", resourceDirectory.TrimEnd('\\')); if (AdditionalResourceDirectories != null) { foreach (var dir in AdditionalResourceDirectories) { var resdir = dir.ItemSpec.TrimEnd('\\'); if (Directory.Exists(resdir)) { cmd.AppendSwitchIfNotNull("-S ", resdir); } } } if (AdditionalAndroidResourcePaths != null) { foreach (var dir in AdditionalAndroidResourcePaths) { var resdir = Path.Combine(dir.ItemSpec, "res"); if (Directory.Exists(resdir)) { cmd.AppendSwitchIfNotNull("-S ", resdir); } } } if (LibraryProjectJars != null) { foreach (var jar in LibraryProjectJars) { cmd.AppendSwitchIfNotNull("-j ", jar); } } cmd.AppendSwitchIfNotNull("-I ", JavaPlatformJarPath); // Add asset directory if it exists if (!string.IsNullOrWhiteSpace(AssetDirectory)) { var assetDir = AssetDirectory.TrimEnd('\\'); if (!Path.IsPathRooted(assetDir)) { assetDir = Path.Combine(WorkingDirectory, assetDir); } if (!string.IsNullOrWhiteSpace(assetDir) && Directory.Exists(assetDir)) { cmd.AppendSwitchIfNotNull("-A ", assetDir); } } if (!string.IsNullOrWhiteSpace(UncompressedFileExtensions)) { foreach (var ext in UncompressedFileExtensions.Split(new char[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries)) { cmd.AppendSwitchIfNotNull("-0 ", ext.StartsWith(".", StringComparison.OrdinalIgnoreCase) ? ext : $".{ext}"); } } if (!string.IsNullOrEmpty(ExtraPackages)) { cmd.AppendSwitchIfNotNull("--extra-packages ", ExtraPackages); } cmd.AppendSwitch("--auto-add-overlay"); if (!string.IsNullOrEmpty(ResourceSymbolsTextFileDirectory)) { cmd.AppendSwitchIfNotNull("--output-text-symbols ", ResourceSymbolsTextFileDirectory); } var extraArgsExpanded = ExpandString(ExtraArgs); if (extraArgsExpanded != ExtraArgs) { LogDebugMessage(" ExtraArgs expanded: {0}", extraArgsExpanded); } if (!string.IsNullOrWhiteSpace(extraArgsExpanded)) { cmd.AppendSwitch(extraArgsExpanded); } if (!AndroidUseLatestPlatformSdk) { cmd.AppendSwitchIfNotNull("--max-res-version ", ApiLevel); } return(cmd.ToString()); }
void Run(DirectoryAssemblyResolver res) { PackageNamingPolicy pnp; JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash; foreach (var dir in FrameworkDirectories) { if (Directory.Exists(dir.ItemSpec)) { res.SearchDirectories.Add(dir.ItemSpec); } } var selectedWhitelistAssemblies = new List <string> (); // Put every assembly we'll need in the resolver foreach (var assembly in ResolvedAssemblies) { var assemblyFullPath = Path.GetFullPath(assembly.ItemSpec); res.Load(assemblyFullPath); if (MonoAndroidHelper.FrameworkAttributeLookupTargets.Any(a => Path.GetFileName(assembly.ItemSpec) == a)) { selectedWhitelistAssemblies.Add(assemblyFullPath); } } // However we only want to look for JLO types in user code var assemblies = ResolvedUserAssemblies.Select(p => p.ItemSpec).ToList(); var fxAdditions = MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies) .Where(a => assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(a))); assemblies = assemblies.Concat(fxAdditions).ToList(); // Step 1 - Find all the JLO types var scanner = new JavaTypeScanner(this.CreateTaskLogger()) { ErrorOnCustomJavaObject = ErrorOnCustomJavaObject, }; var all_java_types = scanner.GetJavaTypes(assemblies, res); WriteTypeMappings(all_java_types); var java_types = all_java_types .Where(t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(t)) .ToArray(); // Step 2 - Generate Java stub code var success = Generator.CreateJavaSources( Log, java_types, Path.Combine(OutputDirectory, "src"), ApplicationJavaClass, UseSharedRuntime, int.Parse(AndroidSdkPlatform) <= 10, ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll")); if (!success) { return; } // We need to save a map of .NET type -> ACW type for resource file fixups var managed = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal); var java = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal); // Allocate a MemoryStream with a reasonable guess at its capacity using (var stream = new MemoryStream(java_types.Length * 32)) using (var acw_map = new StreamWriter(stream)) { foreach (var type in java_types) { string managedKey = type.FullName.Replace('/', '.'); string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.'); acw_map.Write(type.GetPartialAssemblyQualifiedName()); acw_map.Write(';'); acw_map.Write(javaKey); acw_map.WriteLine(); TypeDefinition conflict; if (managed.TryGetValue(managedKey, out conflict)) { Log.LogWarning( "Duplicate managed type found! Mappings between managed types and Java types must be unique. " + "First Type: '{0}'; Second Type: '{1}'.", conflict.GetAssemblyQualifiedName(), type.GetAssemblyQualifiedName()); Log.LogWarning( "References to the type '{0}' will refer to '{1}'.", managedKey, conflict.GetAssemblyQualifiedName()); continue; } if (java.TryGetValue(javaKey, out conflict)) { Log.LogError( "Duplicate Java type found! Mappings between managed types and Java types must be unique. " + "First Type: '{0}'; Second Type: '{1}'", conflict.GetAssemblyQualifiedName(), type.GetAssemblyQualifiedName()); success = false; continue; } managed.Add(managedKey, type); java.Add(javaKey, type); acw_map.Write(managedKey); acw_map.Write(';'); acw_map.Write(javaKey); acw_map.WriteLine(); acw_map.Write(JavaNativeTypeManager.ToCompatJniName(type).Replace('/', '.')); acw_map.Write(';'); acw_map.Write(javaKey); acw_map.WriteLine(); } acw_map.Flush(); MonoAndroidHelper.CopyIfStreamChanged(stream, AcwMapFile); } // Step 3 - Merge [Activity] and friends into AndroidManifest.xml var manifest = new ManifestDocument(ManifestTemplate, this.Log); manifest.PackageName = PackageName; manifest.ApplicationName = ApplicationName ?? PackageName; manifest.Placeholders = ManifestPlaceholders; manifest.Assemblies.AddRange(assemblies); manifest.Resolver = res; manifest.SdkDir = AndroidSdkDir; manifest.SdkVersion = AndroidSdkPlatform; manifest.Debug = Debug; manifest.MultiDex = MultiDex; manifest.NeedsInternet = NeedsInternet; manifest.InstantRunEnabled = InstantRunEnabled; var additionalProviders = manifest.Merge(all_java_types, selectedWhitelistAssemblies, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments); using (var stream = new MemoryStream()) { manifest.Save(stream); // Only write the new manifest if it actually changed MonoAndroidHelper.CopyIfStreamChanged(stream, MergedAndroidManifestOutput); } // Create the CacheFile if needed if (!string.IsNullOrEmpty(CacheFile)) { bool extractNativeLibraries = manifest.ExtractNativeLibraries(); if (!extractNativeLibraries) { //We need to write the value to a file, if _GenerateJavaStubs is skipped on incremental builds var document = new XDocument( new XDeclaration("1.0", "UTF-8", null), new XElement("Properties", new XElement(nameof(ReadJavaStubsCache.EmbeddedDSOsEnabled), "True")) ); document.SaveIfChanged(CacheFile); } else { //Delete the file otherwise, since we only need to specify when EmbeddedDSOsEnabled=True File.Delete(CacheFile); } } // Create additional runtime provider java sources. string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java"; string providerTemplate = GetResource <JavaCallableWrapperGenerator> (providerTemplateFile); foreach (var provider in additionalProviders) { var contents = providerTemplate.Replace("MonoRuntimeProvider", provider); var real_provider = Path.Combine(OutputDirectory, "src", "mono", provider + ".java"); MonoAndroidHelper.CopyIfStringChanged(contents, real_provider); } // Create additional application java sources. StringWriter regCallsWriter = new StringWriter(); regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first."); foreach (var type in java_types) { if (JavaNativeTypeManager.IsApplication(type) || JavaNativeTypeManager.IsInstrumentation(type)) { string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.'); regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);", type.GetAssemblyQualifiedName(), javaKey); } } regCallsWriter.Close(); var real_app_dir = Path.Combine(OutputDirectory, "src", "mono", "android", "app"); string applicationTemplateFile = "ApplicationRegistration.java"; SaveResource(applicationTemplateFile, applicationTemplateFile, real_app_dir, template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString())); // Create NotifyTimeZoneChanges java sources. string notifyTimeZoneChangesFile = "NotifyTimeZoneChanges.java"; SaveResource(notifyTimeZoneChangesFile, notifyTimeZoneChangesFile, real_app_dir, template => template); }
void Run(DirectoryAssemblyResolver res) { PackageNamingPolicy pnp; JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash; var temp = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); Directory.CreateDirectory(temp); foreach (var dir in FrameworkDirectories) { if (Directory.Exists(dir.ItemSpec)) { res.SearchDirectories.Add(dir.ItemSpec); } } var selectedWhitelistAssemblies = new List <string> (); // Put every assembly we'll need in the resolver foreach (var assembly in ResolvedAssemblies) { res.Load(Path.GetFullPath(assembly.ItemSpec)); if (MonoAndroidHelper.FrameworkAttributeLookupTargets.Any(a => Path.GetFileName(assembly.ItemSpec) == a)) { selectedWhitelistAssemblies.Add(Path.GetFullPath(assembly.ItemSpec)); } } // However we only want to look for JLO types in user code var assemblies = ResolvedUserAssemblies.Select(p => p.ItemSpec).ToList(); var fxAdditions = MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies) .Where(a => assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(a))); assemblies = assemblies.Concat(fxAdditions).ToList(); // Step 1 - Find all the JLO types var scanner = new JavaTypeScanner(this.CreateTaskLogger()) { ErrorOnCustomJavaObject = ErrorOnCustomJavaObject, }; var all_java_types = scanner.GetJavaTypes(assemblies, res); WriteTypeMappings(all_java_types); var java_types = all_java_types.Where(t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(t)); // Step 2 - Generate Java stub code var keep_going = Generator.CreateJavaSources( Log, java_types, temp, ApplicationJavaClass, UseSharedRuntime, int.Parse(AndroidSdkPlatform) <= 10, ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll")); var temp_map_file = Path.Combine(temp, "acw-map.temp"); // We need to save a map of .NET type -> ACW type for resource file fixups var managed = new Dictionary <string, TypeDefinition> (); var java = new Dictionary <string, TypeDefinition> (); var acw_map = new StreamWriter(temp_map_file); foreach (var type in java_types) { string managedKey = type.FullName.Replace('/', '.'); string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.'); acw_map.WriteLine("{0};{1}", type.GetPartialAssemblyQualifiedName(), javaKey); TypeDefinition conflict; if (managed.TryGetValue(managedKey, out conflict)) { Log.LogWarning( "Duplicate managed type found! Mappings between managed types and Java types must be unique. " + "First Type: '{0}'; Second Type: '{1}'.", conflict.GetAssemblyQualifiedName(), type.GetAssemblyQualifiedName()); Log.LogWarning( "References to the type '{0}' will refer to '{1}'.", managedKey, conflict.GetAssemblyQualifiedName()); continue; } if (java.TryGetValue(javaKey, out conflict)) { Log.LogError( "Duplicate Java type found! Mappings between managed types and Java types must be unique. " + "First Type: '{0}'; Second Type: '{1}'", conflict.GetAssemblyQualifiedName(), type.GetAssemblyQualifiedName()); keep_going = false; continue; } managed.Add(managedKey, type); java.Add(javaKey, type); acw_map.WriteLine("{0};{1}", managedKey, javaKey); acw_map.WriteLine("{0};{1}", JavaNativeTypeManager.ToCompatJniName(type).Replace('/', '.'), javaKey); } acw_map.Close(); //The previous steps found an error, so we must abort and not generate any further output //We must do so subsequent unchanged builds fail too. if (!keep_going) { File.Delete(temp_map_file); return; } MonoAndroidHelper.CopyIfChanged(temp_map_file, AcwMapFile); try { File.Delete(temp_map_file); } catch (Exception) { } // Only overwrite files if the contents actually changed foreach (var file in Directory.GetFiles(temp, "*", SearchOption.AllDirectories)) { var dest = Path.GetFullPath(Path.Combine(OutputDirectory, "src", file.Substring(temp.Length + 1))); MonoAndroidHelper.CopyIfChanged(file, dest); } // Step 3 - Merge [Activity] and friends into AndroidManifest.xml var manifest = new ManifestDocument(ManifestTemplate, this.Log); manifest.PackageName = PackageName; manifest.ApplicationName = ApplicationName ?? PackageName; manifest.Placeholders = ManifestPlaceholders; manifest.Assemblies.AddRange(assemblies); manifest.Resolver = res; manifest.SdkDir = AndroidSdkDir; manifest.SdkVersion = AndroidSdkPlatform; manifest.Debug = Debug; manifest.NeedsInternet = NeedsInternet; var additionalProviders = manifest.Merge(all_java_types, selectedWhitelistAssemblies, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments); var temp_manifest = Path.Combine(temp, "AndroidManifest.xml"); var real_manifest = Path.GetFullPath(MergedAndroidManifestOutput); manifest.Save(temp_manifest); // Only write the new manifest if it actually changed MonoAndroidHelper.CopyIfChanged(temp_manifest, real_manifest); // Create additional runtime provider java sources. string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java"; string providerTemplate = new StreamReader(typeof(JavaCallableWrapperGenerator).Assembly.GetManifestResourceStream(providerTemplateFile)).ReadToEnd(); foreach (var provider in additionalProviders) { var temp_provider = Path.Combine(temp, provider + ".java"); File.WriteAllText(temp_provider, providerTemplate.Replace("MonoRuntimeProvider", provider)); var real_provider_dir = Path.GetFullPath(Path.Combine(OutputDirectory, "src", "mono")); Directory.CreateDirectory(real_provider_dir); var real_provider = Path.Combine(real_provider_dir, provider + ".java"); MonoAndroidHelper.CopyIfChanged(temp_provider, real_provider); } // Create additional application java sources. Action <string, string, string, Func <string, string> > save = (resource, filename, destDir, applyTemplate) => { string temp_file = Path.Combine(temp, filename); string template = applyTemplate(new StreamReader(typeof(GenerateJavaStubs).Assembly.GetManifestResourceStream(resource)).ReadToEnd()); File.WriteAllText(temp_file, template); Directory.CreateDirectory(destDir); var real_file = Path.Combine(destDir, filename); MonoAndroidHelper.CopyIfChanged(temp_file, real_file); }; StringWriter regCallsWriter = new StringWriter(); regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first."); foreach (var type in java_types) { if (JavaNativeTypeManager.IsApplication(type) || JavaNativeTypeManager.IsInstrumentation(type)) { string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.'); regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);", type.GetAssemblyQualifiedName(), javaKey); } } regCallsWriter.Close(); var real_app_dir = Path.GetFullPath(Path.Combine(OutputDirectory, "src", "mono", "android", "app")); string applicationTemplateFile = "ApplicationRegistration.java"; save(applicationTemplateFile, applicationTemplateFile, real_app_dir, template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString())); // Create NotifyTimeZoneChanges java sources. string notifyTimeZoneChangesFile = "NotifyTimeZoneChanges.java"; save(notifyTimeZoneChangesFile, notifyTimeZoneChangesFile, real_app_dir, template => template); // Delete our temp directory try { Directory.Delete(temp, true); } catch (Exception) { } }
void Run(DirectoryAssemblyResolver res) { PackageNamingPolicy pnp; JavaNativeTypeManager.PackageNamingPolicy = Enum.TryParse(PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash; foreach (var dir in FrameworkDirectories) { if (Directory.Exists(dir.ItemSpec)) { res.SearchDirectories.Add(dir.ItemSpec); } } // Put every assembly we'll need in the resolver foreach (var assembly in ResolvedAssemblies) { if (bool.TryParse(assembly.GetMetadata(AndroidSkipJavaStubGeneration), out bool value) && value) { Log.LogDebugMessage($"Skipping Java Stub Generation for {assembly.ItemSpec}"); continue; } res.Load(assembly.ItemSpec); } // However we only want to look for JLO types in user code List <string> assemblies = new List <string> (); foreach (var asm in ResolvedUserAssemblies) { if (bool.TryParse(asm.GetMetadata(AndroidSkipJavaStubGeneration), out bool value) && value) { Log.LogDebugMessage($"Skipping Java Stub Generation for {asm.ItemSpec}"); continue; } if (!assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(asm.ItemSpec))) { continue; } Log.LogDebugMessage($"Adding {asm.ItemSpec} to assemblies."); assemblies.Add(asm.ItemSpec); } foreach (var asm in MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies(ResolvedAssemblies)) { if (bool.TryParse(asm.GetMetadata(AndroidSkipJavaStubGeneration), out bool value) && value) { Log.LogDebugMessage($"Skipping Java Stub Generation for {asm.ItemSpec}"); continue; } if (!assemblies.All(x => Path.GetFileName(x) != Path.GetFileName(asm.ItemSpec))) { continue; } Log.LogDebugMessage($"Adding {asm.ItemSpec} to assemblies."); assemblies.Add(asm.ItemSpec); } // Step 1 - Find all the JLO types var scanner = new JavaTypeScanner(this.CreateTaskLogger()) { ErrorOnCustomJavaObject = ErrorOnCustomJavaObject, }; var all_java_types = scanner.GetJavaTypes(assemblies, res); WriteTypeMappings(all_java_types); var java_types = all_java_types .Where(t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration(t)) .ToArray(); // Step 2 - Generate Java stub code var success = Generator.CreateJavaSources( Log, java_types, Path.Combine(OutputDirectory, "src"), ApplicationJavaClass, AndroidSdkPlatform, UseSharedRuntime, int.Parse(AndroidSdkPlatform) <= 10, ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll")); if (!success) { return; } // We need to save a map of .NET type -> ACW type for resource file fixups var managed = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal); var java = new Dictionary <string, TypeDefinition> (java_types.Length, StringComparer.Ordinal); var managedConflicts = new Dictionary <string, List <string> > (0, StringComparer.Ordinal); var javaConflicts = new Dictionary <string, List <string> > (0, StringComparer.Ordinal); // Allocate a MemoryStream with a reasonable guess at its capacity using (var stream = new MemoryStream(java_types.Length * 32)) using (var acw_map = new StreamWriter(stream)) { foreach (var type in java_types) { string managedKey = type.FullName.Replace('/', '.'); string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.'); acw_map.Write(type.GetPartialAssemblyQualifiedName()); acw_map.Write(';'); acw_map.Write(javaKey); acw_map.WriteLine(); TypeDefinition conflict; bool hasConflict = false; if (managed.TryGetValue(managedKey, out conflict)) { if (!managedConflicts.TryGetValue(managedKey, out var list)) { managedConflicts.Add(managedKey, list = new List <string> { conflict.GetPartialAssemblyName() }); } list.Add(type.GetPartialAssemblyName()); hasConflict = true; } if (java.TryGetValue(javaKey, out conflict)) { if (!javaConflicts.TryGetValue(javaKey, out var list)) { javaConflicts.Add(javaKey, list = new List <string> { conflict.GetAssemblyQualifiedName() }); } list.Add(type.GetAssemblyQualifiedName()); success = false; hasConflict = true; } if (!hasConflict) { managed.Add(managedKey, type); java.Add(javaKey, type); acw_map.Write(managedKey); acw_map.Write(';'); acw_map.Write(javaKey); acw_map.WriteLine(); acw_map.Write(JavaNativeTypeManager.ToCompatJniName(type).Replace('/', '.')); acw_map.Write(';'); acw_map.Write(javaKey); acw_map.WriteLine(); } } acw_map.Flush(); MonoAndroidHelper.CopyIfStreamChanged(stream, AcwMapFile); } foreach (var kvp in managedConflicts) { Log.LogCodedWarning( "XA4214", "The managed type `{0}` exists in multiple assemblies: {1}. " + "Please refactor the managed type names in these assemblies so that they are not identical.", kvp.Key, string.Join(", ", kvp.Value)); Log.LogCodedWarning("XA4214", "References to the type `{0}` will refer to `{0}, {1}`.", kvp.Key, kvp.Value [0]); } foreach (var kvp in javaConflicts) { Log.LogCodedError( "XA4215", "The Java type `{0}` is generated by more than one managed type. " + "Please change the [Register] attribute so that the same Java type is not emitted.", kvp.Key); foreach (var typeName in kvp.Value) { Log.LogCodedError("XA4215", " `{0}` generated by: {1}", kvp.Key, typeName); } } // Step 3 - Merge [Activity] and friends into AndroidManifest.xml var manifest = new ManifestDocument(ManifestTemplate, this.Log); manifest.PackageName = PackageName; manifest.ApplicationName = ApplicationName ?? PackageName; manifest.Placeholders = ManifestPlaceholders; manifest.Assemblies.AddRange(assemblies); manifest.Resolver = res; manifest.SdkDir = AndroidSdkDir; manifest.SdkVersion = AndroidSdkPlatform; manifest.Debug = Debug; manifest.MultiDex = MultiDex; manifest.NeedsInternet = NeedsInternet; manifest.InstantRunEnabled = InstantRunEnabled; var additionalProviders = manifest.Merge(all_java_types, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments); using (var stream = new MemoryStream()) { manifest.Save(stream); // Only write the new manifest if it actually changed MonoAndroidHelper.CopyIfStreamChanged(stream, MergedAndroidManifestOutput); } // Create additional runtime provider java sources. string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java"; string providerTemplate = GetResource(providerTemplateFile); foreach (var provider in additionalProviders) { var contents = providerTemplate.Replace("MonoRuntimeProvider", provider); var real_provider = Path.Combine(OutputDirectory, "src", "mono", provider + ".java"); MonoAndroidHelper.CopyIfStringChanged(contents, real_provider); } // Create additional application java sources. StringWriter regCallsWriter = new StringWriter(); regCallsWriter.WriteLine("\t\t// Application and Instrumentation ACWs must be registered first."); foreach (var type in java_types) { if (JavaNativeTypeManager.IsApplication(type) || JavaNativeTypeManager.IsInstrumentation(type)) { string javaKey = JavaNativeTypeManager.ToJniName(type).Replace('/', '.'); regCallsWriter.WriteLine("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);", type.GetAssemblyQualifiedName(), javaKey); } } regCallsWriter.Close(); var real_app_dir = Path.Combine(OutputDirectory, "src", "mono", "android", "app"); string applicationTemplateFile = "ApplicationRegistration.java"; SaveResource(applicationTemplateFile, applicationTemplateFile, real_app_dir, template => template.Replace("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString())); }