react-native入門,編寫靜態頁面,整合原生專案
React-Native技術調研
0.前提:
搭建環境:https://reactnative.cn/docs/getting-started/,
分mac/win/linux,平臺分android/ios。
1.建立一個新專案
使用rn建立一個專案和把rn技術整合到一個現有的原生專案是有差別的。
//建立和執行一個rn專案:
react-native init AwesomeProject
cd AwesomeProject
react-native run-ios
編譯和執行需要一段時間...耐心等待..根據rn版本的不同,ios虛擬機器也不不同,比如最新的0.57版本的是iphoneX,低版本的rn預設創造的ios虛擬機器就老一點。
注意官網中特別提到:
!!!注意!!!:init 命令預設會建立最新的版本,而目前最新的 0.45 及以上版本需要下載 boost
等幾個第三方庫編譯。這些庫在國內即便FQ也很難下載成功,導致很多人無法執行iOS專案!!!中文網在論壇中提供了這些庫的國內下載連結。如果你嫌麻煩,又沒有對新版本的需求,那麼可以暫時建立0.44.3的版本。
我在rn版本0.57.5,react-cli版本2.0.1直接init建立專案沒有遇到以上問題。
幾個常用操作
- cmd+r 重新整理,可配置熱更新,調出選單enable liveload
- cmd+d 調出選單
2.試著用RN寫一個靜態頁面
https://github.com/ZhangMingZhao1/react-native-pratice/tree/master/earphone_guide
3.整合到一個原生專案
這裡以一個rn整合到ios object-c為例,現實中這種情況可能也更多一些。
a.
用xcode新建一個單頁面應用,語言選擇object-c,名字為ReactNativeDemo,在專案根目錄下,新建ReactNative資料夾,用於存放跟reactnative相關檔案。(後面簡稱rn)
b.
在rn資料夾中新建一個package.json,內容為:
{ "name": "ReactNativeDemo", "version": "0.0.1", "private": true, "scripts": { "start": "node node_modules/react-native/local-cli/cli.js start" }, "dependencies": { "react": "16.0.0", "react-native": "0.51.0" } }
注意版本嚴格規定
c.
進入rn資料夾,npm install,在rn資料夾新建index.js,以前版本是inex.ios.js。
內容為:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
class ScoresView extends React.Component {
render() {
var contents = this.props['scores'].map((score) => (
<Text key={score.name}>
{score.name}:{score.value}
{'\n'}
</Text>
));
return (
<View style={styles.container}>
<Text style={styles.highScoresTitle}>2048 High Scores!</Text>
<Text style={styles.scores}>{contents}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF',
},
highScoresTitle: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
scores: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
// 註冊元件,程式入口
// 第一個引數:註冊模組名稱,這裡親測不和專案名一致也可以,但是好多資料說名字要和專案名一致
// 第二個引數:函式,此函式返回元件類名,程式啟動就會自動去載入這個元件
AppRegistry.registerComponent('App', () => ScoresView);
d.
進入專案根目錄,安裝cocoapods,
brew install cocoapods
我的mac下會報個錯,在一個檔案下沒有許可權寫入,而homebrew現在禁止使用sudo執行,根據提示的指令可以收回那個檔案的許可權,複製貼上執行就好。
安裝好後,在根目錄使用pod init,在生成的Podfile中內容改為:
source 'https://github.com/CocoaPods/Specs.git'
react_native_path = './ReactNative/node_modules/react-native'
platform :ios, ‘9.0’
use_frameworks!
target 'ReactNativeDemo' do
# 'node_modules'目錄一般位於根目錄中
# 但是如果你的結構不同,那你就要根據實際路徑修改下面的`:path`
pod 'React', :path => react_native_path, :subspecs => [
'Core',
#'BatchedBridge', # 0.45 版本以後需要新增
'CxxBridge',
'DevSupport', # 如果RN版本 >= 0.43,則需要加入此行才能開啟開發者選單
'RCTText',
'RCTImage',
'RCTNetwork',
'RCTWebSocket', # 這個模組是用於除錯功能的
# 在這裡繼續新增你所需要的模組
]
# 如果你的RN版本 >= 0.42.0,則加入下面這行
pod 'yoga', :path => react_native_path + '/ReactCommon/yoga'
# Third party deps
pod 'DoubleConversion', :podspec => react_native_path + '/third-party-podspecs/DoubleConversion.podspec'
pod 'GLog', :podspec => react_native_path + '/third-party-podspecs/GLog.podspec'
pod 'Folly', :podspec => react_native_path + '/third-party-podspecs/Folly.podspec'
end
這個檔案類似npm的package.json,記錄了所需檔案的依賴,所以下一步就是
pod install
e.
在總ios專案中修改http的安全策略,在info.plist加上:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
f.
用xcode開啟專案,在Main.storyboard拖入一個按鈕,在ViewController.m中加入標頭檔案:
#import <React/RCTRootView.h>
再增加一個按鈕的跳轉方法:
- (IBAction)pushToReactNativeView:(id)sender {
NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];
RCTRootView *rootView =
[[RCTRootView alloc] initWithBundleURL: jsCodeLocation
moduleName: @"App"
initialProperties:
@{
@"scores" : @[
@{
@"name" : @"Alex",
@"value": @"42"
},
@{
@"name" : @"Joel",
@"value": @"10"
}
]
}
launchOptions: nil];
UIViewController *vc = [[UIViewController alloc] init];
vc.view = rootView;
[self presentViewController:vc animated:YES completion:nil];
}
可能會出現加載出錯,這是因為pod install安裝的檔案沒有載入進來,重啟xcode專案,重新開啟專案即可。
然後把ViewController.m檔案中的#import <fishhook/fishhook.h> 改為 #import "fishhook.h",不然後面執行可能會報錯。
g.
給這個按鈕和這個方法繫結起來,進入keyboard,按住 ctrl,點選按鈕會出現一個箭頭,指向左上角的ViewContrller,可出現一個框,選擇剛才寫的pushToReactNativeView方法,會在右下角看到關聯了。
這部可詳見iOS學習之基礎控制元件新增和事件繫結,推薦一個連結:https://www.jianshu.com/p/6eb302a62956
h.
進入到rn資料夾,npm start 啟動node伺服器,這時會進入dev狀態,動態打包。回到xcode,執行專案,點選按鈕,就會看到跳轉到rn寫的頁面。
4.RN打包給原生專案使用
a.
在rn專案根目錄中建立release_ios 資料夾,(打包必須建立資料夾)具體可以自己命名,作為資源目標的輸出檔案目錄。
在根目錄下執行打包命令:
react-native bundle --entry-file index.js --platform ios --dev false --bundle-output release_ios/main.jsbundle --assets-dest release_ios/
會看到release_ios下多出assets資料夾(如果有圖片),和兩個jsbindle檔案.
b.
將main.jsbundle和assets拖入Xcode的專案導航面板中,選擇預設匯入即可(位置和裡面的資料夾同級)
修改上面的ViewController,m,
將埠動態引入改為本地,讓React Native去使用我們剛才匯入的jsbundle,這樣以來我們就擺脫了對本地nodejs伺服器的依賴。當然也可以將jsbundle 放到自己的遠端伺服器中,更換遠端的伺服器檔案就可以載入jsbundle,為了提高效能我們可以在本地做一次快取。@後面是自己打包檔案的名字不加字尾。
c.
ios app的打包就可以看官網了:https://developer.apple.com/support/app-store-connect/
5.留下的疑問,待繼續研究
- npm start後打包的檔案是在哪裡放著的,找了一下沒找到,難道和webpack dev一樣使用了memory-fs-js,把臨時打包檔案動態寫進了記憶體裡嗎?
- 大家可以補充..etc