接觸RN也有一段時(shí)間了,基本上來(lái)說(shuō)算是入門了置逻,到目前RN的應(yīng)用還沒有達(dá)到期望的廣泛度,大部分還是以原生+RN的方式進(jìn)行混合開發(fā),今天抽空寫一下關(guān)于RN嵌入到iOS原生項(xiàng)目中的知識(shí)點(diǎn)鞍恢。
前期準(zhǔn)備
現(xiàn)在大部分嵌入方式都是采用cocoapods的方式引入RN依賴庫(kù)到原生項(xiàng)目中,當(dāng)然你也可以選擇手動(dòng)方式每窖,不過(guò)很麻煩帮掉,本文采用的cocoapods來(lái)管理依賴。
RN所需要的環(huán)境也要裝好窒典,中文網(wǎng)有蟆炊,具體我就不說(shuō)了
集成
用Xcode創(chuàng)建一個(gè)項(xiàng)目,然后在項(xiàng)目中創(chuàng)建一個(gè)目錄瀑志,把RN相關(guān)的都放在里面涩搓,如下圖,我創(chuàng)建了一個(gè)js目錄(這個(gè)目錄你也可以放到iOS項(xiàng)目的根目錄劈猪,任意)昧甘。
然后cd到剛剛創(chuàng)建的js目錄中,執(zhí)行
npm init
战得,創(chuàng)建node環(huán)境充边,這時(shí)js目錄中會(huì)多出一個(gè)package.json文件,這個(gè)文件和iOS中的Podfile類似常侦,是用來(lái)記錄著RN工程中要安裝的依賴浇冰,目前你只需要關(guān)注dependencies這一項(xiàng)(把下面的內(nèi)容覆蓋到你生成的package.json文件中)贬媒,該項(xiàng)中記錄著RN項(xiàng)目要安裝的依賴庫(kù)。
{
"name": "MixRNAndIOS",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"react": "15.3.2",
"react-native": "^0.36.1"
},
"jest": {
"preset": "jest-react-native"
},
"devDependencies": {
"babel-jest": "16.0.0",
"babel-preset-react-native": "1.9.0",
"jest": "16.0.2",
"jest-react-native": "16.0.0",
"react-test-renderer": "15.3.2"
}
}
緊接著我們用npm包管理器來(lái)安裝RN的依賴庫(kù)肘习,還是在js目錄執(zhí)行npm install
,安裝完畢之后际乘,js目錄會(huì)多出一個(gè)名為node_modules文件夾,RN所必須依賴的庫(kù)都在這里面井厌,然后我們創(chuàng)建一個(gè)index.ios.js作為RN項(xiàng)目的入口文件(名字可以任意起)蚓庭,然后我們就可以在入口文件中愉快的寫RN代碼了。
上面的步驟順利執(zhí)行完之后仅仆,RN項(xiàng)目已經(jīng)完成了器赞,現(xiàn)在我們要把RN集成到iOS原生項(xiàng)目中。
在項(xiàng)目根目錄創(chuàng)建一個(gè)Podfile文件墓拜,如下所示港柜,在項(xiàng)目的根目錄執(zhí)行pod install 來(lái)安裝Podfile中指定的依賴庫(kù)。
# The target name is most likely the name of your project.
target 'MixRNAndIOS' do
# Your 'node_modules' directory is probably in the root of your project,
# but if not, adjust the `:path` accordingly
pod 'React', :path => ‘./MixRNAndIOS/js/node_modules/react-native', :subspecs => [
'Core',
'RCTText',
'RCTNetwork',
'RCTWebSocket', # needed for debugging
# Add any other subspecs you want to use in your project
'RCTImage',
]
end
注意:Podfile文件中的path路徑
用pod安裝完iOS所依賴的RN庫(kù)之后我們就可以著手集成RN了咳榜。
RN為我們?cè)趇OS平臺(tái)上提供了一個(gè)RCTRootView夏醉,RCTRootView是繼承自iOS中UIView類,所以你可以像使用UIView一樣使用RCTRootView涌韩,RN與iOS的交互都要在RCTRootView中進(jìn)行畔柔,本篇文章先不講交互的事,只講集成臣樱,先把代碼貼上靶擦,如下所示:
#import "ViewController.h"
#import "RCTRootView.h"
@interface ViewController ()
@property (nonatomic, strong) NSDictionary *props;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.props = @{ @"param" : @[
@{
@"name" : @"Alex",
@"des": @"hello,我是從原生傳遞給RN界面的參數(shù)"
}
]
};
UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake((self.view.bounds.size.width - 300)/2, 200, 300, 40)];
[btn setTitle:@"點(diǎn)我進(jìn)入react native界面" forState:UIControlStateNormal];
[btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[btn addTarget:self action:@selector(highScoreButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
- (void)highScoreButtonPressed{
NSURL *jsCodeLocation;
#ifdef DEBUG
//開發(fā)的時(shí)候用雇毫,需要打開本地服務(wù)器
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"];
#else
//發(fā)布APP的時(shí)候用
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"index.ios" withExtension:@"jsbundle"];
#endif
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL : jsCodeLocation
moduleName : @"RNHighScores"
initialProperties : self.props //將native數(shù)據(jù)傳送到RN中
launchOptions : nil];
rootView.frame = [UIScreen mainScreen].bounds;
UIViewController *vc = [[UIViewController alloc] init];
vc.view.backgroundColor = [UIColor redColor];
[vc.view addSubview:rootView];
[self presentViewController:vc animated:YES completion:nil];
}
創(chuàng)建RCTRootView玄捕,將RCTRootView添加到VC中的view上就OK了
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"index.ios" withExtension:@"jsbundle"];
這一行你先忽略,后面會(huì)說(shuō)棚放。
然后cd到j(luò)s目錄枚粘,執(zhí)行react-native start
或者執(zhí)行npm start
,來(lái)啟動(dòng)本地node服務(wù)器飘蚯,如果沒有錯(cuò)誤的話我們就只需最后一步了馍迄,用Xcode打開項(xiàng)目,運(yùn)行項(xiàng)目局骤,大功告成柬姚。
打RN離線包
此時(shí)我們的項(xiàng)目是依賴于剛剛啟動(dòng)的本地服務(wù)器的,要是上線怎么辦庄涡,所以我們需要打個(gè)RN離線包,這樣就可以擺脫本地服務(wù)器了搬设。
進(jìn)入js目錄穴店,創(chuàng)建一個(gè)bundle目錄撕捍,這里面存放打包后的RN資源,包括RN代碼和圖片等靜態(tài)資源泣洞,在js目錄里執(zhí)行下面的打包命令忧风,
react-native bundle --entry-file ./index.ios.js --bundle-output ./bundle/index.ios.jsbundle --platform ios --assets-dest ./bundle --dev false
如果成功的話,在bundle目錄下會(huì)生成存放RN靜態(tài)資源的assert目錄和RN的index.ios.jsbundle代碼文件球凰,將這倆家伙拖進(jìn)Xcode中
注意:要以引用的方式拖進(jìn)Xcode中狮腿。
在文章的集成部分我粘貼了一大段代碼,源代碼中有兩句代碼用來(lái)生成RN資源的URL呕诉,第一句是依賴本地服務(wù)器的缘厢,一般調(diào)試RN代碼時(shí)用,第二句是引入打包后的RN資源的URL甩挫,發(fā)布APP的時(shí)候用的贴硫,我用宏來(lái)進(jìn)行控制。
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"index.ios" withExtension:@"jsbundle"];
注意:假如我們把第一種獲取URL的方式注釋掉伊者,宏也注釋掉英遭,如果iOS項(xiàng)目是DEBUG模式,而我們加載的明明是RN的離線包亦渗,你會(huì)發(fā)現(xiàn)從原生頁(yè)面跳轉(zhuǎn)到RN頁(yè)面的時(shí)候挖诸,頂部的statusBar會(huì)有加載資源的進(jìn)度顯示,不要糾結(jié)法精,運(yùn)行項(xiàng)目的時(shí)候改成release模式就好了多律,來(lái)張效果圖。
友情提示亿虽,在RN中想引入iOS中Assets.xcassets里面的圖片的話可以直接寫圖片的文件名菱涤,如下面這樣。
<Image source={{uri:'happiness.jpg'}} style={styles.happy}/>