集成
與現(xiàn)有App集成拍鲤,以及高度適應(yīng)問題剩檀,官方文檔中都有說明憋沿,單拉一篇文章出來旺芽,主要是想記錄一下其中的問題點(diǎn)沪猴,給大家做些參考。
集成到現(xiàn)有App采章,無非是把react界面放到現(xiàn)有App中的某個(gè)頁面中运嗜,那么第一點(diǎn)是要把react native加到現(xiàn)有工程,第二點(diǎn)創(chuàng)建RCTRootView并添加到某頁面悯舟。
react native添加到現(xiàn)有工程担租,有兩種方式:
1、使用cocoapods抵怎,自動化管理奋救;
2岭参、手工集成,即將react native各個(gè)子工程手動添加到項(xiàng)目中尝艘;
但是演侯,在此之前,還有一件至關(guān)重要的事:下載react native工程
背亥。
react native使用node.js作為工程集成環(huán)境秒际,包管理使用npm工具,所以這一步也比較簡單:
//在現(xiàn)有App工程目錄中創(chuàng)建package.json文件狡汉,執(zhí)行npm install:
{
"name": "reactDemo",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"react": "^15.2.1",
"react-native": "^0.29.2"
}
}
當(dāng)前目錄就會創(chuàng)建node_modules娄徊,react native所有依賴項(xiàng)都存在此目錄中。
使用cocoapods集成比較方便:
//創(chuàng)建podfile盾戴,配置工程依賴項(xiàng)寄锐,注意:path路徑要設(shè)置自己的node_modules正確路徑
target 'App工程名稱' do
pod 'React', :path => './node_modules/react-native', :subspecs => [
'Core',
'RCTText',
'RCTWebSocket', # needed for debugging
# Add any other subspecs you want to use in your project
'RCTImage',
'RCTNetwork',
'RCTActionSheet',
'RCTGeolocation',
'RCTLinkingIOS',
'RCTVibration',
'RCTSettings',
]
end
執(zhí)行: pod install, 即可集成react native到現(xiàn)有工程尖啡。
手動添加react native锐峭,就要麻煩一下,進(jìn)入node_modules目錄查找相應(yīng)react工程可婶,即project沿癞,將project添加到現(xiàn)有工程中即可。
下一步矛渴,創(chuàng)建react頁面椎扬,并作為子頁面添加到現(xiàn)有項(xiàng)目中:
NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
_rctView = [[RCTRootView alloc] initWithBundleURL: jsCodeLocation moduleName:@"reactDemo" initialProperties:@{} launchOptions:nil];
[self.view addSubview: _rctView];
到這一步,算是整體集成完畢具温,可以啟動服務(wù)看頁面是否能正常展示蚕涤。
react高度適應(yīng)
react頁面高度是不定的,這就給react頁面的父頁面設(shè)定帶來一些問題铣猩。官方也給出了解決方案揖铜,就是父頁面使用UIScrollView,并監(jiān)聽react頁面高度變化达皿,使父頁面隨react頁面變化而變化天吓。
設(shè)置監(jiān)聽RCTRootView的高度變化:
_rctView.delegate = self;
_rctView.sizeFlexibility = RCTRootViewSizeFlexibilityHeight;
#pragma mark - RCTRootViewDelegate
- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView {
CGRect newFrame = rootView.frame;
newFrame.size = rootView.intrinsicSize;
rootView.frame = newFrame;
self.view.frame = newFrame;
if (self.delegate) {
[self.delegate didChangeHeight: newFrame.size.height];
}
}
ok,集成和高度適應(yīng)都完畢了峦椰,下來還有什么問題龄寞?
touchable與UIScrollView事件沖突問題
這里說的事件沖突,倒不是說UIScrollView截獲了Touchable的點(diǎn)擊事件汤功,而是Touchable會把UIScrollView的滾動事件誤認(rèn)為是點(diǎn)擊事件物邑。所以造成的現(xiàn)象就是,當(dāng)滾動UIScrollView時(shí),同時(shí)會出發(fā)Touchable點(diǎn)擊事件色解,這種體驗(yàn)糟糕的不要不要的茂嗓。
react native自身也封裝了ScrollView,在使用react native的ScrollView時(shí)不會存在這個(gè)問題科阎,明顯react native發(fā)現(xiàn)并解決了該問題在抛。react native的點(diǎn)擊事件又必須依賴Touchable,我們又不能使用react native的ScrollView萧恕,所以這個(gè)問題不能靠框架解決刚梭。
解決思路:
Touchable是完全依賴事件模擬的點(diǎn)擊操作,發(fā)生混亂的原因是UIScrollView滾動相關(guān)事件傳遞給了js側(cè)的Touchable票唆,所以只要把滾動的相關(guān)事件屏蔽調(diào)就可以實(shí)現(xiàn)目標(biāo)朴读。
解決方法:
RCTRootView是native與js側(cè)的橋梁,所有UI觸摸事件都是通過該View傳遞給js走趋,該View有個(gè)cancelTouches方法衅金,用來取消當(dāng)前的觸摸事件,所以簿煌,只要在scrollViewWillBeginDragging
方法中調(diào)用[_rctView cancelTouches]
即可氮唯。
交互與擴(kuò)展
既然集成react native到本地項(xiàng)目中,那么必然還存在兩者之間的交互姨伟。react native核心技術(shù)是javascriptCore惩琉,交互必然也是通過它了。與WebView不同夺荒,javascriptCore是獨(dú)立存在項(xiàng)目中瞒渠,整個(gè)react native都是通過一個(gè)單獨(dú)的jscontext建立之間的聯(lián)系,也就無法截獲WebView的請求消息進(jìn)行通信技扼。好消息是伍玖,無論舊的WebView方式還是新的javascriptCore方式,只需要封裝一下甚至無需封裝剿吻,就可以將舊的jsbridge接口移植到react native項(xiàng)目中窍箍。
有關(guān)jsbridge和javascriptCore可以參考之前的文章:
如何注入到react native可以參考這篇文章:
如何注入到react native中的WebView,可以參考這篇文章:
如何讓你的項(xiàng)目可以隨意更換react native服務(wù)器地址丽旅,可以參考這個(gè)工具:
react-native-debug-server-host
需要注意一點(diǎn):react native的jscontext是在子線程中創(chuàng)建執(zhí)行椰棘,所以如果你的接口中有UI的操作,需要手動指定到UI線程執(zhí)行魔招。