将React Native集成到Xamarin项目中
我的任务是查看是否可以将React Native集成到Xamarin.Forms项目中.
我认为我已经非常接近实现这一点,但我不能肯定地说.我知道这是一个奇怪/倒退的解决方案,但无论如何我还想去看看它是否能击败它…… 介绍 到目前为止我尝试过的 BaseType(typeof(NSObject))] interface TheViewController { [Export("setMainViewController:")] void SetTheMainViewController(UIViewController viewController); } 在Xcode项目中,创建了一个TheViewController类. setMainViewController:以下列方式实现: -(void)setMainViewController:(UIViewController *)viewController{ AppDelegate * ad = (AppDelegate*)[UIApplication sharedApplication].delegate; NSURL * jsCodeLocation = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:@"main" ofType:@"jsbundle"]]; RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"prototyper" initialProperties:nil launchOptions:ad.savedLaunchOptions]; rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; ad.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; viewController.view = rootView; ad.window.rootViewController = viewController; [ad.window makeKeyAndVisible]; } 我有效地试图从Xamarin传递一个UIViewController来为React Native添加自己的东西. private Binding.TheViewController _theViewController; public override void ViewDidLoad() { base.ViewDidLoad(); _theViewController = new TheViewController(); _theViewController.SetTheMainViewController(this); } 这个类正在实现PageRenderer,使用覆盖Xamarin.Forms的ContentPage [assembly:ExportRenderer(typeof(RNTest.MainViewController),typeof(RNTest.iOS.MainViewController))] 好吧,经过所有这些,我去了部署到设备,并且,预计会遇到一些错误. AOT编译器进入我的lib并尝试做它的魔法并在React Native项目中抛出许多链接器错误,如下所示.
我打算在绑定中设置更多方法来设置回调等,以开始构建一些关于使用Objective-C来回传递信息的功能,我将使用一些本机代码链接将其传递给React Native. 摘要
我能够使用以下步骤来实现这一点.这里有很多,所以如果我错过了一个细节,请原谅我.
构建静态库 >在Xcode中创建一个Cocoa Touch静态库项目. npm install react-native >将所有React Xcode项目添加到项目中. (Screenshot)您可以查看现有React Native应用程序的.pbxproj文件,以获取有关如何查找所有这些内容的线索. 创建一个Xamarin应用程序 >在Visual Studio中创建一个新的iOS Single View App项目/解决方案. (Screenshot) // @interface RCTBundleURLProvider : NSObject [BaseType(typeof(NSObject))] interface RCTBundleURLProvider { // +(instancetype)sharedSettings; [Static] [Export("sharedSettings")] RCTBundleURLProvider SharedSettings(); // -(NSURL *)jsBundleURLForBundleRoot:(NSString *)bundleRoot fallbackResource:(NSString *)resourceName; [Export("jsBundleURLForBundleRoot:fallbackResource:")] NSUrl JsBundleURLForBundleRoot(string bundleRoot,[NullAllowed] string resourceName); } // @interface RCTRootView : UIView [BaseType(typeof(UIView))] interface RCTRootView { // -(instancetype)initWithBundleURL:(NSURL *)bundleURL moduleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties launchOptions:(NSDictionary *)launchOptions; [Export("initWithBundleURL:moduleName:initialProperties:launchOptions:")] IntPtr Constructor(NSUrl bundleURL,string moduleName,[NullAllowed] NSDictionary initialProperties,[NullAllowed] NSDictionary launchOptions); } // @protocol RCTBridgeModule <NSObject> [Protocol,Model] [BaseType(typeof(NSObject))] interface RCTBridgeModule { } >将以下代码添加到Structs.cs.确保包含System,System.Runtime.InteropServices和Foundation的using语句. [StructLayout(LayoutKind.Sequential)] public struct RCTMethodInfo { public string jsName; public string objcName; public bool isSync; } public static class CFunctions { [DllImport ("__Internal")] public static extern void RCTRegisterModule(IntPtr module); } >在应用程序项目中添加对bindings库项目的引用. var jsCodeLocation = RCTBundleURLProvider.SharedSettings().JsBundleURLForBundleRoot("index",null); var rootView = new RCTRootView(jsCodeLocation,"<Name of your React app>",null,launchOptions); Window = new UIWindow(UIScreen.MainScreen.Bounds); Window.RootViewController = new UIViewController() { View = rootView }; Window.MakeKeyAndVisible(); >将以下内容添加到Info.plist. <key>UIViewControllerBasedStatusBarAppearance</key> <false/> <key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>localhost</key> <dict> <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key> <true/> </dict> </dict> </dict> 此时,您应该能够通过在相应目录中启动React Packager(react-native start)来运行任何React Native应用程序.以下部分将向您展示如何从React Native调用C#. 创建本机模块 >在iOS应用项目中添加课程. public class TestClass : RCTBridgeModule >将ModuleName方法添加到您的类.将返回的值更改为您想在JavaScript中调用该类的任何值.您可以指定空字符串以使用原始字符串. [Export("moduleName")] public static string ModuleName() => "TestClass"; >将RequiresMainQueueSetup方法添加到您的类中.我认为如果您实现本机(UI)组件,则需要返回true. [Export("requiresMainQueueSetup")] public static bool RequiresMainQueueSetup() => false; >编写要导出的方法(从JavaScript调用).这是一个例子. [Export("test:")] public void Test(string msg) => Debug.WriteLine(msg); >对于导出的每个方法,请编写一个返回有关它的信息的其他方法.每个方法的名称都需要以__rct_export__开头.只要它是唯一的,名称的其余部分无关紧要.我能找到的唯一方法就是返回一个IntPtr而不是一个RCTMethodInfo.以下是一个例子. [Export("__rct_export__test")] public static IntPtr TestExport() { var temp = new RCTMethodInfo() { jsName = string.Empty,objcName = "test: (NSString*) msg",isSync = false }; var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(temp)); Marshal.StructureToPtr(temp,ptr,false); return ptr; } > jsName是您要从JavaScript调用方法的名称.您可以指定空字符串以使用原始字符串. >在AppDelegate.cs中启动视图之前注册您的课程.类的名称将是带有下划线而不是点的完全限定名称.这是一个例子. CFunctions.RCTRegisterModule(ObjCRuntime.Class.GetHandle("ReactTest_TestClass")); 从JavaScript调用您的本机模块 >将NativeModules导入JavaScript文件. import { NativeModules } from 'react-native'; >调用您导出的方法之一. NativeModules.TestClass.test('C# called successfully.'); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |