集成
與現有App集成,以及高度適應問題,官方文檔中都有說明,單拉一篇文章出來,主要是想記錄一下其中的問題點,給大家做些參考。
集成到現有App,無非是把react界面放到現有App中的某個頁面中,那么第一點是要把react native加到現有工程,第二點創建RCTRootView并添加到某頁面。
react native添加到現有工程,有兩種方式:
1、使用cocoapods,自動化管理;
2、手工集成,即將react native各個子工程手動添加到項目中;
但是,在此之前,還有一件至關重要的事:下載react native工程
。
react native使用node.js作為工程集成環境,包管理使用npm工具,所以這一步也比較簡單:
//在現有App工程目錄中創建package.json文件,執行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"
}
}
當前目錄就會創建node_modules,react native所有依賴項都存在此目錄中。
使用cocoapods集成比較方便:
//創建podfile,配置工程依賴項,注意:path路徑要設置自己的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
執行: pod install, 即可集成react native到現有工程。
手動添加react native,就要麻煩一下,進入node_modules目錄查找相應react工程,即project,將project添加到現有工程中即可。
下一步,創建react頁面,并作為子頁面添加到現有項目中:
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];
到這一步,算是整體集成完畢,可以啟動服務看頁面是否能正常展示。
react高度適應
react頁面高度是不定的,這就給react頁面的父頁面設定帶來一些問題。官方也給出了解決方案,就是父頁面使用UIScrollView,并監聽react頁面高度變化,使父頁面隨react頁面變化而變化。
設置監聽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,集成和高度適應都完畢了,下來還有什么問題?
touchable與UIScrollView事件沖突問題
這里說的事件沖突,倒不是說UIScrollView截獲了Touchable的點擊事件,而是Touchable會把UIScrollView的滾動事件誤認為是點擊事件。所以造成的現象就是,當滾動UIScrollView時,同時會出發Touchable點擊事件,這種體驗糟糕的不要不要的。
react native自身也封裝了ScrollView,在使用react native的ScrollView時不會存在這個問題,明顯react native發現并解決了該問題。react native的點擊事件又必須依賴Touchable,我們又不能使用react native的ScrollView,所以這個問題不能靠框架解決。
解決思路:
Touchable是完全依賴事件模擬的點擊操作,發生混亂的原因是UIScrollView滾動相關事件傳遞給了js側的Touchable,所以只要把滾動的相關事件屏蔽調就可以實現目標。
解決方法:
RCTRootView是native與js側的橋梁,所有UI觸摸事件都是通過該View傳遞給js,該View有個cancelTouches方法,用來取消當前的觸摸事件,所以,只要在scrollViewWillBeginDragging
方法中調用[_rctView cancelTouches]
即可。
交互與擴展
既然集成react native到本地項目中,那么必然還存在兩者之間的交互。react native核心技術是javascriptCore,交互必然也是通過它了。與WebView不同,javascriptCore是獨立存在項目中,整個react native都是通過一個單獨的jscontext建立之間的聯系,也就無法截獲WebView的請求消息進行通信。好消息是,無論舊的WebView方式還是新的javascriptCore方式,只需要封裝一下甚至無需封裝,就可以將舊的jsbridge接口移植到react native項目中。
有關jsbridge和javascriptCore可以參考之前的文章:
如何注入到react native可以參考這篇文章:
如何注入到react native中的WebView,可以參考這篇文章:
如何讓你的項目可以隨意更換react native服務器地址,可以參考這個工具:
react-native-debug-server-host
需要注意一點:react native的jscontext是在子線程中創建執行,所以如果你的接口中有UI的操作,需要手動指定到UI線程執行。