Esempio n. 1
0
        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) { }
        }
        public override bool Execute()
        {
            // if there are no assemblies, then we are done
            if (ResolvedAssemblies == null || ResolvedAssemblies.Length == 0)
            {
                Log.LogMessage($"There were no assemblies to check.");
                return(true);
            }

            var hasMissing = false;

            var assemblyNames = ResolvedAssemblies.Select(a => Path.GetFileNameWithoutExtension(a.ItemSpec));

            var mapping = new AndroidXAssembliesCsvMapping();

            var assemblyPairs      = new Dictionary <string, string>();
            var androidxAssemblies = new Dictionary <string, bool>();

            foreach (var support in assemblyNames)
            {
                // if there was no mapping found, then we don't care
                if (!mapping.TryGetAndroidXAssembly(support, out var androidx))
                {
                    continue;
                }

                ContainsSupportAssemblies = true;

                Log.LogMessage(MessageImportance.Low, $"Making sure that the Android Support assembly '{support}' has a replacement Android X assembly...");

                // make sure the mapped assembly is referenced
                var exists = assemblyNames.Contains(androidx);
                androidxAssemblies[androidx] = exists;
                assemblyPairs[androidx]      = support;

                if (exists)
                {
                    Log.LogMessage(MessageImportance.Low, $"Found the Android X assembly '{androidx}'.");
                }
                else
                {
                    Log.LogMessage(MessageImportance.Low, $"Missing the Android X assembly '{androidx}'.");
                    hasMissing = true;
                }
            }

            if (hasMissing)
            {
                var missing = androidxAssemblies.Where(p => !p.Value).Select(p => p.Key).ToArray();

                var tree = PackageDependencyTree.Load();

                var reduced = tree.Reduce(missing).ToArray();

                var packages   = new StringBuilder();
                var references = new StringBuilder();

                foreach (var assembly in reduced)
                {
                    mapping.TryGetAndroidXPackage(assembly, out var package);
                    mapping.TryGetAndroidXVersion(assembly, out var version);

                    packages.AppendLine();
                    packages.Append($" - {package}");

                    references.AppendLine();
                    references.Append($"    <PackageReference Include=\"{package}\" Version=\"{version}\" />");
                }

                var msg =
                    $"Could not find {missing.Length} Android X assemblies, make sure to install the following NuGet packages:" +
                    packages + Environment.NewLine +
                    $"You can also copy-and-paste the following snippet into your .csproj file:" +
                    references;

                if (UseWarningsInsteadOfErrors)
                {
                    Log.LogWarning(msg);
                }
                else
                {
                    Log.LogError(msg);
                }
            }

            return(!hasMissing || UseWarningsInsteadOfErrors);
        }
Esempio n. 3
0
        bool Execute(DirectoryAssemblyResolver resolver)
        {
            Log.LogDebugMessage("ResolveAssemblies Task");
            Log.LogDebugMessage("  ReferenceAssembliesDirectory: {0}", ReferenceAssembliesDirectory);
            Log.LogDebugMessage("  I18nAssemblies: {0}", I18nAssemblies);
            Log.LogDebugMessage("  LinkMode: {0}", LinkMode);
            Log.LogDebugTaskItems("  Assemblies:", Assemblies);

            foreach (var dir in ReferenceAssembliesDirectory.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
            {
                resolver.SearchDirectories.Add(dir);
            }

            var assemblies = new HashSet <string> ();

            var topAssemblyReferences = new List <AssemblyDefinition> ();

            try {
                foreach (var assembly in Assemblies)
                {
                    var assembly_path = Path.GetDirectoryName(assembly.ItemSpec);

                    if (!resolver.SearchDirectories.Contains(assembly_path))
                    {
                        resolver.SearchDirectories.Add(assembly_path);
                    }

                    // Add each user assembly and all referenced assemblies (recursive)
                    var assemblyDef = resolver.Load(assembly.ItemSpec);
                    if (assemblyDef == null)
                    {
                        throw new InvalidOperationException("Failed to load assembly " + assembly.ItemSpec);
                    }
                    topAssemblyReferences.Add(assemblyDef);
                    assemblies.Add(Path.GetFullPath(assemblyDef.MainModule.FullyQualifiedName));
                }
            } catch (Exception ex) {
                Log.LogError("Exception while loading assemblies: {0}", ex);
                return(false);
            }
            try {
                foreach (var assembly in topAssemblyReferences)
                {
                    AddAssemblyReferences(resolver, assemblies, assembly, true);
                }
            } catch (Exception ex) {
                Log.LogError("Exception while loading assemblies: {0}", ex);
                return(false);
            }

            // Add I18N assemblies if needed
            AddI18nAssemblies(resolver, assemblies);

            ResolvedAssemblies             = assemblies.Select(a => new TaskItem(a)).ToArray();
            ResolvedSymbols                = assemblies.Select(a => a + ".mdb").Where(a => File.Exists(a)).Select(a => new TaskItem(a)).ToArray();
            ResolvedFrameworkAssemblies    = ResolvedAssemblies.Where(p => MonoAndroidHelper.IsFrameworkAssembly(p.ItemSpec, true)).ToArray();
            ResolvedUserAssemblies         = ResolvedAssemblies.Where(p => !MonoAndroidHelper.IsFrameworkAssembly(p.ItemSpec, true)).ToArray();
            ResolvedDoNotPackageAttributes = do_not_package_atts.ToArray();

            Log.LogDebugTaskItems("  [Output] ResolvedAssemblies:", ResolvedAssemblies);
            Log.LogDebugTaskItems("  [Output] ResolvedUserAssemblies:", ResolvedUserAssemblies);
            Log.LogDebugTaskItems("  [Output] ResolvedFrameworkAssemblies:", ResolvedFrameworkAssemblies);
            Log.LogDebugTaskItems("  [Output] ResolvedDoNotPackageAttributes:", ResolvedDoNotPackageAttributes);

            return(!Log.HasLoggedErrors);
        }
        bool CreateJavaSources(IEnumerable <TypeDefinition> javaTypes, TypeDefinitionCache cache)
        {
            string outputPath                = Path.Combine(OutputDirectory, "src");
            string monoInit                  = GetMonoInitSource(AndroidSdkPlatform);
            bool   hasExportReference        = ResolvedAssemblies.Any(assembly => Path.GetFileName(assembly.ItemSpec) == "Mono.Android.Export.dll");
            bool   generateOnCreateOverrides = int.Parse(AndroidSdkPlatform) <= 10;

            bool ok = true;

            foreach (var t in javaTypes)
            {
                using (var writer = MemoryStreamPool.Shared.CreateStreamWriter()) {
                    try {
                        var jti = new JavaCallableWrapperGenerator(t, Log.LogWarning, cache)
                        {
                            GenerateOnCreateOverrides = generateOnCreateOverrides,
                            ApplicationJavaClass      = ApplicationJavaClass,
                            MonoRuntimeInitialization = monoInit,
                        };

                        jti.Generate(writer);
                        writer.Flush();

                        var path = jti.GetDestinationPath(outputPath);
                        MonoAndroidHelper.CopyIfStreamChanged(writer.BaseStream, path);
                        if (jti.HasExport && !hasExportReference)
                        {
                            Diagnostic.Error(4210, Properties.Resources.XA4210);
                        }
                    } catch (XamarinAndroidException xae) {
                        ok = false;
                        Log.LogError(
                            subcategory: "",
                            errorCode: "XA" + xae.Code,
                            helpKeyword: string.Empty,
                            file: xae.SourceFile,
                            lineNumber: xae.SourceLine,
                            columnNumber: 0,
                            endLineNumber: 0,
                            endColumnNumber: 0,
                            message: xae.MessageWithoutCode,
                            messageArgs: new object [0]
                            );
                    } catch (DirectoryNotFoundException ex) {
                        ok = false;
                        if (OS.IsWindows)
                        {
                            Diagnostic.Error(5301, Properties.Resources.XA5301, t.FullName, ex);
                        }
                        else
                        {
                            Diagnostic.Error(4209, Properties.Resources.XA4209, t.FullName, ex);
                        }
                    } catch (Exception ex) {
                        ok = false;
                        Diagnostic.Error(4209, Properties.Resources.XA4209, t.FullName, ex);
                    }
                }
            }
            return(ok);
        }