React-Native號稱是跨平臺開發且具備原生應用的體驗,早在兩年前我曾經嘗試過使用React-Native,可是環境搭建過程及其複雜,可參見我以前寫的文章:iOS現有項目手動集成ReactNative。最近公司新開項目須要實現iOS和Android平臺熱更新方案,以便快速開展業務。本文用來梳理React-Native在iOS上的一些實踐。包括以下內容:html
因爲React-Native項目一直在更新,不一樣的版本在使用的過程當中會遇到不一樣的問題,因此強烈建議你使用英文官方文檔做爲開發參考。node
根據React-Native的官方文檔一路能一路很順利的搭建成功。我這裏簡單說一下主要步驟,詳細可參考:安裝文檔react
安裝依賴,包括Node、Watchman、React Native命令行界面、Xcode。ios
brew install node
brew install watchman
複製代碼
npm install -g react-native-cli
複製代碼
建立項目git
react-native init AwesomeProject
複製代碼
運行項目github
cd AwesomeProject
react-native run-ios
複製代碼
若是順利的話你能夠看到你的第一個React-Native項目了。shell
一樣我建議你參考官方文檔,我現有項目是Swift,你能夠根據你的項目狀況選擇對應的安裝方法。npm
package.json
文件{
"name": "MyReactNativeApp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"postinstall": "sed -i '' 's/#import <RCTAnimation\\/RCTValueAnimatedNode.h>/#import <React\\/RCTValueAnimatedNode.h>/' ./node_modules/react-native/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.h; sed -i '' 's/#import <fishhook\\/fishhook.h>/#import <React\\/fishhook.h>/' ./node_modules/react-native/Libraries/WebSocket/RCTReconnectingWebSocket.m"
},
"dependencies": {
"react": "^16.4.0",
"react-native": "^0.55.4"
}
}
複製代碼
brew install yarn
複製代碼
yarn add react-native
複製代碼
若是出現警告json
warning "react-native@0.52.2" has unmet peer dependency "react@16.2.0".
swift
則你須要安裝React
yarn add react@version_printed_above // version_printed_above 具體版本號
複製代碼
# Uncomment the next line to define a global platform for your project
platform :ios, '9.0'
target 'ReactDemo' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
# Pods for ReactDemo
pod 'React', :path => '../node_modules/react-native', :subspecs => [
'Core',
'CxxBridge', # Include this for RN >= 0.47
'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43
'RCTText',
'RCTNetwork',
'RCTWebSocket', # needed for debugging
Add any other subspecs you want to use in your project
]
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
# Third party deps podspec link
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
target 'ReactDemoTests' do
inherit! :search_paths
# Pods for testing
end
target 'ReactDemoUITests' do
inherit! :search_paths
# Pods for testing
end
end
def fix_cplusplus_header_compiler_error
filepath = '../node_modules/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceSizeMeasureMode.h'
contents = []
file = File.open(filepath, 'r')
file.each_line do | line |
contents << line
end
file.close
if contents[32].include? "&"
contents.insert(26, "#ifdef __cplusplus")
contents[36] = "#endif"
file = File.open(filepath, 'w') do |f|
f.puts(contents)
end
end
end
def fix_unused_yoga_headers
filepath = './Pods/Target Support Files/yoga/yoga-umbrella.h'
contents = []
file = File.open(filepath, 'r')
file.each_line do | line |
contents << line
end
file.close
if contents[12].include? "Utils.h"
contents.delete_at(15) # #import "YGNode.h"
contents.delete_at(15) # #import "YGNodePrint.h"
contents.delete_at(15) # #import "Yoga-internal.h"
contents.delete_at(12) # #import "Utils.h"
file = File.open(filepath, 'w') do |f|
f.puts(contents)
end
end
end
def react_native_fix
fix_cplusplus_header_compiler_error
fix_unused_yoga_headers
end
post_install do |installer|
react_native_fix
end
複製代碼
執行pod install命令。
import React from 'react';
import {AppRegistry, StyleSheet, Text, View} from 'react-native';
class RNHighScores 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,
},
});
// Module name
AppRegistry.registerComponent('RNHighScores', () => RNHighScores);
複製代碼
@IBAction func highScoreButtonTapped(sender : UIButton) {
NSLog("Hello")
let jsCodeLocation = URL(string: "http://localhost:8081/index.bundle?platform=ios")
let mockData:NSDictionary = ["scores":
[
["name":"Alex", "value":"42"],
["name":"Joel", "value":"10"]
]
]
let rootView = RCTRootView(
bundleURL: jsCodeLocation,
moduleName: "RNHighScores",
initialProperties: mockData as [NSObject : AnyObject],
launchOptions: nil
)
let vc = UIViewController()
vc.view = rootView
self.present(vc, animated: true, completion: nil)
}
複製代碼
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
複製代碼
npm start
複製代碼
react-native run-ios
複製代碼
###真機運行
在真機上運行ReactNative項目有兩種方式,本文只說第二種
在iOS目錄建立release_ios文件夾,執行以下命令
react-native bundle --entry-file index.ios.js --platform ios --dev false --bundle-output release_ios/main.jsbundle --assets-dest release_ios/
複製代碼
會將js打包成main.jsbundle,將圖片等輸出到asset目錄。將這些內容拖入工程,修改加載React-Native代碼
let jsCodeLocation = Bundle.main.url(forResource: "main", withExtension: "jsbundle")
複製代碼
這樣就能夠直接在真機上運行了。
這方面的詳解我推薦necfol的方案,我就很少說廢話了,人家的圖那麼清晰,還有Demo,我只能推薦了。