加载一个react native 页面
2017-01-23 10:13
190 查看
要在原生app中加载js视图,首先要先将js资源文件加载到app中,然后使用一个原生类的实例作为容器承接js定义的视图,最后将这个容器类实例添加到原生视图中。
JS bundle放在远端服务器上,当远端服务器没有开启的时候,使用本地预先打包好的JS bundle。(这个思路就只是为了调试,实际生产中一般不会用这个思路,应该是有更新的时候才会加载远端服务器上的js bundle,然后平时都是加载下载好的本地js bundle)
通过url来访问JS bundle资源。可以使用RCTBundleURLProvider类来获取JS bundle路径。它会检测远端服务器是否开启,如果开启,则返回远端服务器的资源路径,如果未开启则返回本地资源路径。
对于远端服务器上的bundle资源路径一般是这样的形式
在上面的路径中,
对于本地资源,RCTBundleURLProvider是通过NSBundle来查询资源的URL的,因此只要提供本地预先打包的JS bundle的文件名(不带.bundle后缀),它就可以正确返回本地资源的URL。
RCTBundleURLProvider提供了方法来获取url:
这个方法使用了默认的配置,如果需要修改port可以通过修改RCTBundleURLProvider.m中的常量
当然,也可以不用这个类,自己去实现路径选择的逻辑。
初始化RCTBridge实例:
这里的
这里的Bundle URL就是在上一节中讲到的JS Bundle路径。
这两个方法分别通过模块(组件)名称和组件在OC中对于的类来获取组件的实例,如果该组件已经有实例存在会直接返回,如果这个组件从未被实例化过,就会创建一个实例并返回。如果只是想获取当前已存在的实例,如果没有也不创建的话,可以使用以下方法先判断是否存在相应实例:
初始化一个RCTRootView,需要指定所加载的组件的名称以及定义该组件的JS Bundle文件,通常有两种办法,一种是指定
对应的方法如下:
指定bundleURL+moduleName:
指定bridge+moduleName:
这两种方式是有区别的,使用第二种方法可以实现对同一个RCTBridge实例的复用,而使用第一种方法,每次都会创建一个新的RCTBridge实例。RCTBridge实例越多,意味着JavaScript上下文的越多。如果多个RCTRootView实例所加载的组件都来自于同一个js bundle,通常没有必要创建多个RCTBridge实例,这时应该使用第二种方法。
加载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实例,这时应该使用第二种方法。
相关文章推荐
- 加载一个react native 页面
- React-Native中navigator.pop()后如何更新前一个页面
- 加载页面时自动打开另一个新页面的并同时打开一个exe程序
- Firefox - 附加软件 - Firebug - Net网络视图 - 可以用来检查一个页面中未能加载的引用内容
- 使用jquery当页面打开时,将一个事件绑定到控件(同时执行两个事件),并修改加载样式类中的样式
- ajax请求的与页面本身有的数据(页面加载时候存在)的一个区别
- 当jsp页面完全加载完成后执行一个js函数
- 一个比较帅的页面加载效果!
- 页面加载完成后自动执行一个方法函数的JQ、JS方法
- [求助]有一个页面,在浏览器中查看加载不出来,过会儿就会提示WebDev.WevServer20.exe已停
- 在CHtmlView中,判断一个页面加载完成的准确方法
- 当jsp页面完全加载完成后执行一个js函数
- ComponentArt 动态加载的TreeView, 添加一个新节点后,新节点为什么在页面中不会显示?
- 1_页面中怎样加载一个地图
- 一个bug引发的思考 --- ASP.NET页面加载顺序讨论
- 一个小bug 看浏览器内核加载页面的方式
- 向页面动态加载JS文件的的一个小技巧
- 一个bug引发的思考 --- ASP.NET页面加载顺序讨论
- 判断一个页面加载所耗费的时间
- 给程序增加一个加载页面,提高用户体验