public override void Run() { this.Init(); Dictionary <string, ClrApi> platformApis = this.LoadApis(); ClrApi mergedApi = this.MergeApis(platformApis); platformApis.Add(PluginInfo.PortablePlatformName, mergedApi); Assembly mergedAssembly = mergedApi.Assemblies.Single(); string xamarinPlatformId = XamarinPlatformIds.Get(PluginInfo.PortablePlatformName); string targetRelativePath = Path.Combine("build", xamarinPlatformId, mergedAssembly.Name + ".dll"); Log.Message(" " + targetRelativePath); Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(this.TargetOutputPath, targetRelativePath))); PortableAssemblyEmitter assemblyEmitter = new PortableAssemblyEmitter { Assembly = mergedAssembly, AssemblyFilePath = Path.Combine(this.TargetOutputPath, targetRelativePath), }; assemblyEmitter.Run(); Dictionary <string, Assembly> platformAssemblies = platformApis.ToDictionary(pa => pa.Key, pa => pa.Value.Assemblies.Single()); this.CopyAssemblies(platformAssemblies); this.GenerateNuspec(mergedAssembly, platformAssemblies); this.PackNugetPackage(); }
void ExportApi(ICollection <string> referencePaths) { string[] includeNamespaces = this.PluginInfo.AndroidPlatform.NamespaceMappings.Select(m => m.Namespace) .Concat(new[] { typeof(AndroidApiCompiler).Namespace }).ToArray(); Assembly apiAssembly = ClrApi.LoadFrom( this.BuiltBindingsAssemblyPath, referencePaths, includeNamespaces); ClrApi androidApi = new ClrApi { Platform = PluginInfo.AndroidPlatformName, Assemblies = new List <Assembly>(new[] { apiAssembly }), }; string apiXmlPath = Path.GetFullPath(Path.Combine( this.PlatformIntermediatePath, this.PlatformName + "-api.xml")); using (StreamWriter writer = File.CreateText(apiXmlPath)) { androidApi.ToXml(writer); } Log.Important($"Exported {this.PlatformName} API metadata to {apiXmlPath}"); }
protected Dictionary <string, ClrApi> LoadApis() { Dictionary <string, ClrApi> platformApis = new Dictionary <string, ClrApi>(); foreach (string platform in PluginLinker.SupportedPlatforms.Where(p => !platformApis.ContainsKey(p))) { string platformApiFile = this.FindIntermediateFile(Path.Combine(platform, platform + "-api.xml")); if (platformApiFile != null) { using (StreamReader reader = File.OpenText(platformApiFile)) { ClrApi platformApi = ClrApi.FromXml(reader); platformApis.Add(platform, platformApi); if (platform == PluginInfo.WindowsPlatformName) { this.windowsLanguage = platformApi.Language; } } } } if (platformApis.Count == 0) { throw new InvalidOperationException("No plugin APIs were found. Run the compile step first."); } return(platformApis); }
void RemovePlatformIfNotAvailable(ClrApi api, string platform) { PluginInfo.PlatformInfo platformInfo = this.PluginInfo.Platforms.FirstOrDefault(p => p.Name == platform); if (!api.Platforms.Contains(platform) && platformInfo != null) { this.PluginInfo.Platforms.Remove(platformInfo); } }
void GenerateWindowsAdapterProject() { Log.Important("Generating Windows C# bindings project at\n" + this.bindingsProject); string project = Utils.ExtractResourceText(ProjectFiles.Project); project = project.Replace($"$({MsbuildProperties.AssemblyName})", this.PluginInfo.Assembly.Name); project = project.Replace( $"$({MsbuildProperties.PluginAssemblyName})", Path.GetFileNameWithoutExtension(this.pluginMetadataFilePath)); project = project.Replace( $"$({MsbuildProperties.PluginAssemblyPath})", this.pluginMetadataFilePath.Replace("x86", "$(Platform)")); File.WriteAllText(this.bindingsProject, project); Utils.ExtractResource(ProjectFiles.ProjectJson, this.PlatformIntermediatePath); string propertiesPath = Path.Combine(this.PlatformIntermediatePath, "Properties"); if (!Directory.Exists(propertiesPath)) { Directory.CreateDirectory(propertiesPath); } this.GenerateAssemblyInfo(Path.Combine(propertiesPath, ProjectFiles.AssemblyInfo)); string adaptersPath = Path.Combine(this.PlatformIntermediatePath, "Adapters"); if (!Directory.Exists(adaptersPath)) { Directory.CreateDirectory(adaptersPath); } string refPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + @"\Reference Assemblies\Microsoft\Framework\"; string[] referenceAssemblyPaths = new string[] { refPath + @".NETFramework\v4.5\System.dll", refPath + @".NETFramework\v4.5\Facades\System.Runtime.dll", refPath + @".NETFramework\v4.6.1\Facades\System.Diagnostics.Debug.dll", refPath + @".NETFramework\v4.6.1\Facades\System.Runtime.dll", refPath + @".NETFramework\v4.6.1\Facades\System.Threading.Tasks.dll", refPath + @".NETCore\v4.5\System.Runtime.WindowsRuntime.dll", refPath + @".NETCore\v4.5\System.Runtime.WindowsRuntime.UI.Xaml.dll", refPath + @".NETCore\v4.5.1\System.Runtime.InteropServices.WindowsRuntime.dll", }; Assembly androidApi = ClrApi.LoadFrom(this.pluginMetadataFilePath, referenceAssemblyPaths); WindowsApiAdapter adapter = new WindowsApiAdapter(); adapter.PluginInfo = this.PluginInfo; adapter.OutputDirectoryPath = adaptersPath; adapter.GenerateAdapterCodeForApi(androidApi); }
public static ClrApi FromXml(TextReader textReader) { XmlReader reader = XmlReader.Create( textReader, new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Document }); ClrApi clrApi = (ClrApi) new XmlSerializer(typeof(ClrApi)).Deserialize(reader); return(clrApi); }
void GenerateIOSCSharpBindingsProject(bool includeAdapters, ICollection <string> referencePaths = null) { Log.Important("Generating iOS C# bindings project at\n" + this.bindingsProjectFilePath); string project = Utils.ExtractResourceText(Resources.Project); string assemblyName = this.PluginInfo.Assembly.Name; string tempAssemblyName = "temp"; project = project.Replace( $"$({MsbuildProperties.AssemblyName})", (includeAdapters ? assemblyName : tempAssemblyName)); project = project.Replace($"$({MsbuildProperties.NativeLibFileName})", this.nativeLibFileName); File.WriteAllText(this.bindingsProjectFilePath, project); string propertiesPath = Path.Combine(this.PlatformIntermediatePath, "Properties"); if (!Directory.Exists(propertiesPath)) { Directory.CreateDirectory(propertiesPath); } this.GenerateAssemblyInfo( Path.Combine(propertiesPath, ProjectFiles.AssemblyInfo), new string[] { "[assembly: ObjCRuntime.LinkWith(" + $"\"{this.nativeLibFileName}\", SmartLink = true, ForceLoad = true)]", }); string adaptersPath = Path.Combine(this.PlatformIntermediatePath, "Adapters"); if (!Directory.Exists(adaptersPath)) { Directory.CreateDirectory(adaptersPath); } if (includeAdapters) { string tempPath = Path.Combine( Path.GetDirectoryName(this.BuiltBindingsAssemblyPath), tempAssemblyName + ".dll"); Assembly iosApi = ClrApi.LoadFrom(tempPath, referencePaths); IOSApiAdapter adapter = new IOSApiAdapter(); adapter.PluginInfo = this.PluginInfo; adapter.OutputDirectoryPath = adaptersPath; adapter.GenerateAdapterCodeForApi(iosApi); } }
protected void CreateTypeScriptBindings( ClrApi pluginApi, bool forceAsync, bool es6, string bridgeModuleName, string scriptOutputPath) { foreach (Assembly apiAssembly in pluginApi.Assemblies) { TypeScriptEmitter tsEmitter = new TypeScriptEmitter { Assembly = apiAssembly, OutputPath = scriptOutputPath, ForceAsyncAPIs = forceAsync, ES6 = es6, BridgeModuleName = bridgeModuleName, PluginInfo = this.PluginInfo, }; tsEmitter.Run(); } }
public override void Run() { this.Init(); ClrApi pluginApi = this.MergeApis(this.LoadApis()); PluginLinker.CopyNativeProjects(this.SourcePath, null, this.TargetOutputPath); string scriptOutputPath = Path.Combine(this.TargetOutputPath, "js"); if (!Directory.Exists(scriptOutputPath)) { Directory.CreateDirectory(scriptOutputPath); } this.CreateTypeScriptBindings( pluginApi, true, true, c3pReactNativePackageName, scriptOutputPath); string modulesDirectoryPath = Path.Combine(scriptOutputPath, "node_modules"); Directory.CreateDirectory(modulesDirectoryPath); this.CreateBridgeModuleTypeScriptDefinition(modulesDirectoryPath); Utils.ExtractResource("NativeObject.ts", modulesDirectoryPath); Utils.ExtractResource("NativeBridge.ts", modulesDirectoryPath); Utils.ExtractResource("react-native.d.ts", modulesDirectoryPath); Utils.ExtractResource("tsconfig.json", scriptOutputPath); this.GeneratePluginModule(pluginApi, scriptOutputPath); this.RemoveES6PromiseImports(scriptOutputPath); Utils.CompileTypeScript(scriptOutputPath); Log.Message(Utils.EnsureTrailingSlash(Path.GetFullPath(this.TargetOutputPath))); this.GeneratePackageJson(c3pReactNativePackageName, new[] { " \"main\": \"js/plugin.js\"" }); Utils.PackNpmPackage(this.TargetOutputPath); }
void ExportApi() { string refPath = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework"; string[] referenceAssemblyPaths = new string[] { refPath + @"\v4.5\System.dll", refPath + @"\v4.5\Facades\System.Runtime.dll", refPath + @"\v4.6.1\Facades\System.Diagnostics.Debug.dll", refPath + @"\v4.6.1\Facades\System.Runtime.dll", refPath + @"\v4.6.1\Facades\System.Threading.Tasks.dll", this.pluginMetadataFilePath, }; string[] includeNamespaces = this.PluginInfo.WindowsPlatform.IncludeNamespaces?.Select(m => m.Namespace) .Concat(new[] { typeof(WindowsApiCompiler).Namespace }).ToArray(); Assembly apiAssembly = ClrApi.LoadFrom( this.BuiltBindingsAssemblyPath, referenceAssemblyPaths, includeNamespaces); ClrApi androidApi = new ClrApi { Platform = PluginInfo.WindowsPlatformName, Assemblies = new List <Assembly>(new[] { apiAssembly }), Language = this.Language, }; string apiXmlPath = Path.GetFullPath(Path.Combine( this.PlatformIntermediatePath, this.PlatformName + "-api.xml")); using (StreamWriter writer = File.CreateText(apiXmlPath)) { androidApi.ToXml(writer); } Log.Important($"Exported {this.PlatformName} API metadata to {apiXmlPath}"); }
public override void Run() { this.Init(); ClrApi pluginApi = this.MergeApis(this.LoadApis()); PluginLinker.CopyNativeCode(this.SourcePath, null, this.TargetOutputPath); if (this.PluginInfo.WindowsPlatform != null) { string windowsSourcePath = Path.Combine( this.SourcePath, "windows" + (this.windowsLanguage != null ? "-" + this.windowsLanguage : null)); if (Directory.Exists(windowsSourcePath)) { string windowsOutputPath = Path.Combine(this.TargetOutputPath, "windows"); if (!Directory.Exists(windowsOutputPath)) { Directory.CreateDirectory(windowsOutputPath); } PluginLinker.CopyProjectDirectory(windowsSourcePath, windowsOutputPath); } } CordovaPluginLinker.CollectSourceFilesInfo(this.TargetOutputPath, this.PluginInfo); this.CreateAndroidConfigFileInfo(); this.CreateIOSConfigFileInfo(); this.CreateWindowsConfigFileInfo(); this.AddProjectReferences(); string scriptOutputPath = Path.Combine(this.TargetOutputPath, "www"); if (Directory.Exists(scriptOutputPath)) { Directory.Delete(scriptOutputPath, true); } Directory.CreateDirectory(scriptOutputPath); this.CreateTypeScriptBindings( pluginApi, true, false, c3pPluginId + "." + c3pCordovaModuleName, scriptOutputPath); string modulesDirectoryPath = Path.Combine(scriptOutputPath, "node_modules"); Directory.CreateDirectory(modulesDirectoryPath); // This is messy, because Cordova's implementation of module resolution // doesn't respect the 'main' property from the package.json. this.CreateBridgeModuleTypeScriptDefinition(Path.Combine( modulesDirectoryPath, c3pPluginId + "." + c3pCordovaModuleName + ".d.ts")); Utils.ExtractResource( "es6-promise.d.ts", modulesDirectoryPath, c3pPluginId + "." + "es6-promise.d.ts"); foreach (string tsFile in new[] { "NativeObject.ts", "NativeBridge.ts" }) { Utils.ExtractResource(tsFile, modulesDirectoryPath, c3pPluginId + "." + tsFile); string fixTsCode = File.ReadAllText(Path.Combine( modulesDirectoryPath, c3pPluginId + "." + tsFile)); fixTsCode = fixTsCode.Replace("\"es6-promise\"", "\"" + c3pPluginId + ".es6-promise\"") .Replace("\"./NativeObject\"", "\"" + c3pPluginId + ".NativeObject\""); File.WriteAllText( Path.Combine(modulesDirectoryPath, c3pPluginId + "." + tsFile), fixTsCode); } Utils.ExtractResource("tsconfig.json", scriptOutputPath); Utils.CompileTypeScript(scriptOutputPath); Log.Message(Utils.EnsureTrailingSlash(Path.GetFullPath(this.TargetOutputPath))); this.GeneratePluginXml(scriptOutputPath); this.GeneratePackageJson(c3pCordovaPackageName); Utils.PackNpmPackage(this.TargetOutputPath); }
public void Run() { if (this.PluginInfo == null) { throw new ArgumentNullException(nameof(PluginInfo)); } if (this.PlatformApis == null || this.PlatformApis.Count == 0 || this.PlatformApis.Values.Any(a => a == null || a.Assemblies == null || a.Assemblies.Count == 0)) { throw new ArgumentNullException(nameof(PlatformApis)); } if (this.PlatformApis.Values.Any(a => a.Assemblies.Count > 1)) { throw new NotSupportedException("Merging does not support multiple assemblies."); } this.platformAssemblies = this.PlatformApis.ToDictionary(pa => pa.Key, pa => pa.Value.Assemblies.Single()); this.platformTypesIndex = IndexTypes(this.platformAssemblies); this.platformMembersIndex = IndexMembers(this.platformTypesIndex); this.ValidateAssemblies(); if (this.validationWarnings.Count > 0) { Log.Warning(""); foreach (string message in this.validationWarnings) { Log.Warning("{0}", message); } } if (this.validationErrors.Count > 0) { Log.Error(""); foreach (string message in this.validationErrors) { Log.Error("{0}", message); } Log.Error(""); throw new InvalidOperationException("Cannot merge APIs due to validation errors."); } Assembly mergedAssembly = this.MergeAssemblies(this.platformAssemblies.Values); this.MergedApi = new ClrApi { Platform = String.Join(",", this.PlatformApis.Keys), Assemblies = new List <Assembly>(new[] { mergedAssembly }), }; // Event classes are automatically marshalled by value. foreach (Class eventClass in mergedAssembly.Types.OfType <Class>().Where( c => c.ExtendsType == "System.EventArgs")) { PluginInfo.AssemblyClassInfo classInfo = this.PluginInfo.Assembly.Classes .FirstOrDefault(c => c.Name == eventClass.Name || c.Name == eventClass.FullName); if (classInfo != null) { classInfo.MarshalByValue = "true"; } else { this.PluginInfo.Assembly.Classes.Add(new PluginInfo.AssemblyClassInfo { Name = eventClass.Name, MarshalByValue = "true", }); } } }
void GeneratePluginModule(ClrApi pluginApi, string scriptOutputPath) { using (CodeWriter code = new CodeWriter(Path.Combine(scriptOutputPath, "plugin.ts"))) { code.Code("import { Platform, NativeModules } from \"react-native\";"); code.Code(); HashSet <string> allNamespaces = new HashSet <string>(); if (this.PluginInfo.AndroidPlatform != null) { code.Code("if (Platform.OS === \"android\") {"); foreach (var namespaceMapping in this.PluginInfo.AndroidPlatform.NamespaceMappings) { code.Code("\tNativeModules.C3P.registerNamespaceMapping(" + $"\"{namespaceMapping.Namespace}\", \"{namespaceMapping.Package}\");"); allNamespaces.Add(namespaceMapping.Namespace); } code.Code("}"); } if (this.PluginInfo.IOSPlatform != null) { code.Code("if (Platform.OS === \"ios\") {"); foreach (var namespaceMapping in this.PluginInfo.IOSPlatform.NamespaceMappings) { code.Code("\tNativeModules.C3P.registerNamespaceMapping(" + $"\"{namespaceMapping.Namespace}\", \"{namespaceMapping.Prefix}\");"); allNamespaces.Add(namespaceMapping.Namespace); } code.Code("}"); } if (this.PluginInfo.WindowsPlatform != null) { code.Code("if (Platform.OS === \"windows\") {"); foreach (var namespaceInfo in this.PluginInfo.WindowsPlatform.IncludeNamespaces) { code.Code("\tNativeModules.C3P.registerNamespaceMapping(" + $"\"{namespaceInfo.Namespace}\");"); allNamespaces.Add(namespaceInfo.Namespace); } code.Code("}"); } code.Code(); foreach (var classInfo in this.PluginInfo.Assembly.Classes.Where(c => c.MarshalByValue == "true")) { code.Code($"NativeModules.C3P.registerMarshalByValueClass(\"{classInfo.Name}\");"); } string[] includeNamespaces = allNamespaces.ToArray(); code.Code(); foreach (Type pluginType in pluginApi.Assemblies.Single().Types .Where(t => includeNamespaces.Contains(t.Namespace))) { code.Code($"import {pluginType.Name} = require(\"./{pluginType.Name}\");"); } code.Code(); code.Code("export = {"); foreach (Type pluginType in pluginApi.Assemblies.Single().Types .Where(t => includeNamespaces.Contains(t.Namespace))) { code.Code($"\t{pluginType.Name}: {pluginType.Name},"); } code.Code("}"); } }
void GenerateAndroidCSharpBindingsProject(bool includeAdapters, ICollection <string> referencePaths = null) { Log.Important("Generating Android C# bindings project at\n" + this.bindingsProject); string project = Utils.ExtractResourceText(ProjectFiles.Project); string assemblyName = this.PluginInfo.Assembly.Name; string tempAssemblyName = "temp"; project = project.Replace($"$({MsbuildProperties.JavadocPath})", Path.GetFullPath(this.javadocPath)); project = project.Replace( $"$({MsbuildProperties.AssemblyName})", (includeAdapters ? assemblyName : tempAssemblyName)); project = project.Replace( "<ItemGroup Label=\"Jars\">", "<ItemGroup Label=\"Jars\">\n" + this.GetMsbuildJarItems()); project = project.Replace( "<ItemGroup Label=\"Libs\">", "<ItemGroup Label=\"Libs\">\n" + this.GetMsbuildLibItems()); File.WriteAllText(this.bindingsProject, project); string propertiesPath = Path.Combine(this.PlatformIntermediatePath, "Properties"); if (!Directory.Exists(propertiesPath)) { Directory.CreateDirectory(propertiesPath); } this.GenerateAssemblyInfo(Path.Combine(propertiesPath, ProjectFiles.AssemblyInfo)); string adaptersPath = Path.Combine(this.PlatformIntermediatePath, "Adapters"); if (!Directory.Exists(adaptersPath)) { Directory.CreateDirectory(adaptersPath); } string transformsPath = Path.Combine(this.PlatformIntermediatePath, "Transforms"); if (!Directory.Exists(transformsPath)) { Directory.CreateDirectory(transformsPath); } if (includeAdapters) { string apiXmlPath = Path.Combine( this.PlatformIntermediatePath, "obj", (this.DebugConfiguration ? "Debug" : "Release"), "api.xml"); if (!File.Exists(apiXmlPath)) { throw new FileNotFoundException("Exported Java API XML file not found at " + apiXmlPath); } JavaApi javaApi; using (StreamReader reader = File.OpenText(apiXmlPath)) { javaApi = JavaApi.FromXml(reader); } string tempPath = Path.Combine( Path.GetDirectoryName(this.BuiltBindingsAssemblyPath), tempAssemblyName + ".dll"); Assembly androidApi = ClrApi.LoadFrom( tempPath, referencePaths); AndroidApiAdapter adapter = new AndroidApiAdapter(); adapter.PluginInfo = this.PluginInfo; adapter.JavaApi = javaApi; adapter.OutputDirectoryPath = adaptersPath; adapter.GenerateAdapterCodeForApi(androidApi); } this.GenerateBindingMetadata(transformsPath); string enumFields = "<enum-field-mappings></enum-field-mappings>"; File.WriteAllText(Path.Combine(transformsPath, ProjectFiles.EnumFields), enumFields); string enumMethods = "<enum-method-mappings></enum-method-mappings>"; File.WriteAllText(Path.Combine(transformsPath, ProjectFiles.EnumMethods), enumMethods); }