您的位置:首页 > Web前端 > React

加载一个react native 页面

2017-01-23 10:13 190 查看
要在原生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类分别把以上三部分称为,
host
port
bundleRoot
query


对于本地资源,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实例,这时应该使用第二种方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  url native react bridge ios