加载一个react native 页面

来源:互联网 发布:centos6.5编译安装php 编辑:程序博客网 时间:2024/06/05 02:48

要在原生app中加载js视图,首先要先将js资源文件加载到app中,然后使用一个原生类的实例作为容器承接js定义的视图,最后将这个容器类实例添加到原生视图中。

加载JS Bundle

js代码是以JS Bundle的形式保存的,在app中使用js中定义的组件、方法之前,首先要加载JS Bundle。

1.获取JS bundle的资源路径

如果url已知那就跳过这一步,如果不知道url应该是怎样的可以看看。

JS bundle放在远端服务器上,当远端服务器没有开启的时候,使用本地预先打包好的JS bundle。(这个思路就只是为了调试,实际生产中一般不会用这个思路,应该是有更新的时候才会加载远端服务器上的js bundle,然后平时都是加载下载好的本地js bundle)

通过url来访问JS bundle资源。可以使用RCTBundleURLProvider类来获取JS bundle路径。它会检测远端服务器是否开启,如果开启,则返回远端服务器的资源路径,如果未开启则返回本地资源路径。

对于远端服务器上的bundle资源路径一般是这样的形式http://255.255.255.255:8081/index.ios.bundle?platform=ios&...
在上面的路径中,255.255.255.255部分为服务器主机地址,8081部分为端口,index.ios.bundle部分是JS bundle的名称,platform=ios&...部分是一些参数。RCTBundleURLProvider类分别把以上三部分称为,hostportbundleRootquery
对于本地资源,RCTBundleURLProvider是通过NSBundle来查询资源的URL的,因此只要提供本地预先打包的JS bundle的文件名(不带.bundle后缀),它就可以正确返回本地资源的URL。
RCTBundleURLProvider提供了方法来获取url:

NSURL *jsCodeLocation;jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];

这个方法使用了默认的配置,如果需要修改port可以通过修改RCTBundleURLProvider.m中的常量kRCTBundleURLProviderDefaultPort。修改host可以将想要的host作为值存放在UserDefaults里对应键@"RCT_jsLocation",例如:

[[NSUserDefaults standardUserDefaults]setValue:@“localhost" forKey:@"RCT_jsLocation"];

当然,也可以不用这个类,自己去实现路径选择的逻辑。

2.加载JS Bundle

使用RCTBridge类来加载JS Bundle。这个类就是用来做桥接的,用它可以加载JS Bundle,调用这个JS Bundle中用js定义的方法、组件。

初始化RCTBridge实例:

RCTBridge *rctBridge = [[RCTBridge alloc]initWithBundleURL:jsCodeLocation         moduleProvider:nil          launchOptions:launchOptions];

这里的launchOptions一般会传入appdelegate里面的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions中的launchOptions。其实对于JS Bundle一般也是在这个方法中完成,也就是在app刚启动的时候就加载JS Bundle。
这里的Bundle URL就是在上一节中讲到的JS Bundle路径。

使用JS Bundle中已注册的组件

对于JS Bundle中已注册的组件,RN是采用懒加载的方式,也就是在使用RCTBridge加载了JS Bundle以后,其中的组件并没有被初始化,而是在组件被使用时才会被初始化。在原生代码中加载js组件有两种目的,一种想要使用js中定义的方法,另一种想要展示js中定义的视图(可以是一个小的视图也可以是整个页面)。下面分别介绍针对这两种目的来加载js组件的方法。

1.加载JS Bundle中已经注册的组件

RCTBridge两个方法可以获取JS Bundle中已注册组件的实例:

- (id)moduleForName:(NSString *)moduleName;
- (id)moduleForClass:(Class)moduleClass;

这两个方法分别通过模块(组件)名称和组件在OC中对于的类来获取组件的实例,如果该组件已经有实例存在会直接返回,如果这个组件从未被实例化过,就会创建一个实例并返回。如果只是想获取当前已存在的实例,如果没有也不创建的话,可以使用以下方法先判断是否存在相应实例:

- (BOOL)moduleIsInitialized:(Class)moduleClass;

2.在原生视图中展示JS Bundle中定义的组件(视图)

在js的组件中,render()方法返回了这个组件的视图,在OC中要展示一个组件视图,需要使用RCTRootView类。RCTRootView继承于UIView,作为一个容器,承接js中定义的组件视图。在使用上,RCTRootView与一般的UIView最大的不同在于初始化的时候是加载JS Bundle中定义的组件的视图,一旦初始化以后,就可以像使用一般的UIView一样使用它。
初始化一个RCTRootView,需要指定所加载的组件的名称以及定义该组件的JS Bundle文件,通常有两种办法,一种是指定bundleURL和moduleName,另一种是指定bridge和moduleName
对应的方法如下:

  • 指定bundleURL+moduleName:
RCTRootView *rootView = [[RCTRootView alloc]initWithBundleURL:jsCodeLocation moduleName:@"NameOfAJSModule" initialProperties:nil launchOptions:launchOptions];
  • 指定bridge+moduleName:
RCTRootView *rootView = [[RCTRootView alloc]initWithBridge:rctBridge moduleName:@"dealingWithTouch" initialProperties:nil];

这两种方式是有区别的,使用第二种方法可以实现对同一个RCTBridge实例的复用,而使用第一种方法,每次都会创建一个新的RCTBridge实例。RCTBridge实例越多,意味着JavaScript上下文的越多。如果多个RCTRootView实例所加载的组件都来自于同一个js bundle,通常没有必要创建多个RCTBridge实例,这时应该使用第二种方法。

0 0