将RN內建到現有OC項目應該是最常見的,特别是已經有OC項目的,不太可能會去專門搞個純RN的項目。又因為RN不同版本,引用的依賴可能不盡相同,是以特别說明下,本文參考的文檔是React Native (0.57)相關文檔。
一、準備工作
本文示範項目基于如下版本:
"react": "16.5.0",
"react-native": "0.57.1"
1、RN搭建開發環境
如果你已經建立過RN項目,并且運作成功了,那麼你的環境配置應該是沒有問題的,但是如果你是第一次進行學習,那麼就要搭建開發環境了,具體的可以參考: React Native (0.57)開發環境搭建(過程記錄)
2、安裝CocoaPods
沒有安裝過CocoaPods的,可以參考:CocoaPods :為iOS程式提供依賴管理的工具(yoowei)
二、內建ReactNative
1、建立一個OC項目
任意地方,建立一個檔案夾“OC項目內建RN”,建立一個yooweiRN的OC項目,用為已有OC項目。如下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLxQDM3UDOwITOtkTOyQTM2MzNxkjM5ADOxAjMtMTM2EjM38CX5ADOxAjMvw1MxYTMyczLcd2bsJ2Lc12bj5ycn9Gbi52YugTMwIzZtl2Lc9CX6MHc0RHaiojIsJye.png)
2、終端指令 cd 到該項目跟目錄。建立檔案夾RNComponent (檔案夾名字可以自定義,主要用來存放RN相關的檔案)和配置檔案package.json
$ cd /Users/galahad/Desktop/ziliao/OC項目內建RN/RNComponent $ touch package.json package.josn 中的内容如下,其中name位App的名字,dependencies為react和react-native的版本,在建立這些資訊時,建議利用react-native init AwesomeProject建立新項目時會自動建立package.json,直接把檔案複制過來,更改name為自己的原生項目名,確定資訊為最新的,且不容易出錯。
3、安裝React Native依賴包 進入到RNComponent檔案夾下運作指令行,npm install。 $ cd /Users/galahad/Desktop/ziliao/OC項目內建RN/yooweiRN/RNComponent $ npm install 執行結束後項目中會多出一個node_modules檔案夾 使用鏡像檔案,執行很快 added 1033 packages from 527 contributors in 37.502s 4、建立入口檔案index.js、參考官方生成的RN項目裡面的檔案 $ cd /Users/galahad/Desktop/ziliao/OC項目內建RN/yooweiRN/RNComponent $ touch index.js $ touch App.js $ touch app.json
5. Cocoapods內建React Native
終端指令cd 到項目跟目錄
$ cd /Users/galahad/Desktop/ziliao/OC項目內建RN/yooweiRN 建立Podfile檔案: $ touch Podfile $ open -e podfile $ cd /Users/galahad/Desktop/ziliao/OC項目內建RN/yooweiRN $ pod install (1)在安裝的過程中遇到好多以前沒有遇到的問題,下面一一記錄下來,以供參考: [!] CocoaPods could not find compatible versions for pod "React/BatchedBridge": In Podfile: React/BatchedBridge (from `./RNComponent/node_modules/react-native`) None of your spec sources contain a spec satisfying the dependency: `React/BatchedBridge (from `./RNComponent/node_modules/react-native`)`. You have either: * out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`. * mistyped the name or version. * not added the source repo that hosts the Podspec to your Podfile. Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default. 然後我按照要求進行更新,更新的過程中又遇到了另外一個問題。(先透漏下,最終的原因不是因為沒有更新,後面會講到) $ pod repo update 遇到了一個問題 /usr/bin/git -C /Users/galahad/.cocoapods/repos/WYNetWorking fetch origin --progress remote: Repository not found. fatal: repository 'https://github.com/yoowei/WYNetWorking.git/' not found [!] CocoaPods was not able to update the `WYNetWorking` repo. If this is an unexpected issue and persists you can inspect it running `pod repo update --verbose` 這個是我原來自己建的庫,已經廢棄了,github上面的庫已經删除,是以此次報這個錯誤。進入這個/Users/galahad/.cocoapods/repos/WYNetWorking目錄下,将其删掉即可。 之後,還是報上面那個錯誤 [!] CocoaPods could not find compatible versions for pod "React/BatchedBridge": 那麼我就認為這個根本就不是什麼cocoapods 升不更新的問題,而是依賴存不存在的問題,是以在podfile 裡面直接将BatchedBridge 删掉,然後pod install 能夠成功。但是整個項目卻報一堆錯誤 Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_RCTDevMenuItem", referenced from: objc-class-ref in RCTPerfMonitor.o "facebook::react::parseTypeFromHeader(facebook::react::BundleHeader const&)", referenced from: +[RCTJavaScriptLoader attemptSynchronousLoadOfBundleAtURL:runtimeBCVersion:sourceLength:error:] in RCTJavaScriptLoader.o 。。。(省略) "_OBJC_CLASS_$_RCTInspectorDevServerHelper", referenced from: objc-class-ref in RCTBridge.o objc-class-ref in RCTDevSettings.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) 轉變思路,應該是引用的三方依賴庫檔案不對,這個時候,參考 https://reactnative.cn/docs/integration-with-existing-apps/
參考之後( 注意可能不同版本不一樣),編輯podfile 檔案,如下:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'
use_frameworks!
target 'yooweiRN' do
# 'node_modules'目錄一般位于根目錄中 。但是如果你的結構不同,那你就要根據實際路徑修改下面的`:path`
pod 'React', :path => './RNComponent/node_modules/react-native', :subspecs => [
'Core',
'ART',
'RCTActionSheet',
'RCTGeolocation',
'RCTImage',
'RCTNetwork',
'RCTPushNotification',
'RCTSettings',
'RCTText',
'RCTVibration',
'RCTWebSocket',
'RCTLinkingIOS',
'RCTAnimation',
'CxxBridge',
'DevSupport',
]
pod 'yoga', :path => './RNComponent/node_modules/react-native/ReactCommon/yoga'
pod 'DoubleConversion', :podspec => './RNComponent/node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
pod 'glog', :podspec => './RNComponent/node_modules/react-native/third-party-podspecs/glog.podspec'
pod 'Folly', :podspec => './RNComponent/node_modules/react-native/third-party-podspecs/Folly.podspec'
target 'yooweiRNTests' do
inherit! :search_paths
# Pods for testing
end
target 'yooweiRNUITests' do
inherit! :search_paths
# Pods for testing
end
end
然後pod install 又特麼出問題了 $ pod install Analyzing dependencies Fetching podspec for `DoubleConversion` from `./RNComponent/node_modules/react-native/third-party-podspecs/DoubleConversion.podspec` Fetching podspec for `Folly` from `./RNComponent/node_modules/react-native/third-party-podspecs/Folly.podspec` Fetching podspec for `React` from `./RNComponent/node_modules/react-native` Fetching podspec for `glog` from `./RNComponent/node_modules/react-native/third-party-podspecs/glog.podspec` Fetching podspec for `yoga` from `./RNComponent/node_modules/react-native/ReactCommon/yoga` Downloading dependencies Installing DoubleConversion (1.1.6) Installing Folly (2016.10.31.00) Using React (0.57.1) Installing boost-for-react-native (1.63.0) Installing glog (0.3.5) [!] /bin/bash -c set -e #!/bin/bash set -e PLATFORM_NAME="${PLATFORM_NAME:-iphoneos}" CURRENT_ARCH="${CURRENT_ARCH}" ......(省略) xcrun: error: SDK "iphoneos" cannot be located xcrun: error: SDK "iphoneos" cannot be located xcrun: error: SDK "iphoneos" cannot be located xcrun: error: unable to lookup item 'Path' in SDK 'iphoneos' /Users/galahad/Library/Caches/CocoaPods/Pods/External/glog/2263bd123499e5b93b5efe24871be317-e8acf/missing: Unknown `--is-lightweight' option Try `/Users/galahad/Library/Caches/CocoaPods/Pods/External/glog/2263bd123499e5b93b5efe24871be317-e8acf/missing --help' for more information configure: WARNING: 'missing' script is too old or missing configure: error: in `/Users/galahad/Library/Caches/CocoaPods/Pods/External/glog/2263bd123499e5b93b5efe24871be317-e8acf': configure: error: C compiler cannot create executables See `config.log' for more details 然後執行下面指令: $ sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer/ 輸入mac密碼 Password: 重新安裝 $ pod install 安裝沒有問題,工程運作OK .
三、項目處理
項目目錄:整個工程中建立一個檔案夾 RNComponent ,用來裝RN相關資料,顯得整潔,便于管理。
工程目錄結構:
注意工程目錄結構中并沒有将 RNComponent 拖進去,因為cocopods 已經引用過了相關的東西。 1、配置App Transport Security
在iOS 9以上的系統中,除非明确指明,否則應用無法通過http協定連接配接到localhost主機。 建議在Info.plist進行如下設定,否則會報Could not connect to development server錯誤。
2、添加RCTRootView 這裡隻是在ViewController中進行了測試,具體放在什麼地方,怎麼放置大家根據項目需求而定。
3、開啟RN本地服務(cd 到RNComponent目錄)
$ cd /Users/galahad/Desktop/ziliao/OC項目內建RN演練/yooweiRN/RNComponent
$ react-native start
不出意外的是下面這個場景
原因:列印日志看看
由于RN不同版本,入口檔案名不同,根據實際入口檔案名,修改之後。
模拟器展示如下:
4G真機上面運作失敗 :(正常現象)
Failed to load bundle(http://localhost:8081/index.bundle?platform=ios&dev=true) with error:(Could not connect to development server.
wifi真機上面運作失敗:
Ensure the following:
- Node server is running and available on the same network - run 'npm start' from react-native root
- Node server URL is correctly set in AppDelegate
- WiFi is enabled and connected to the same network as the Node Server
URL: http://localhost:8081/index.bundle?platform=ios&dev=true Could not connect to the server.)
打開偏好設定-網絡-檢視目前ip位址,将項目中的localhost改為目前ip(注意,手機的wifi應當和電腦連接配接的是同一個網絡才可以)
至此,将RN內建進OC項目中,并簡單的運作起來,告一段落。下面待續......
jsCodeLocation生成方式總結:
NSURL *jsCodeLocation;
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios&dev=true"];
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
另外實際項目中,還有如下寫法:
#ifdef DEBUG
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
#else
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"bundle/index.ios" withExtension:@"jsbundle"];
#endif
如果項目中使用了CodePush的話,還有如下寫法
#ifdef DEBUG
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
jsCodeLocation = [CodePush bundleURL];
#endif
說明:
上面的兩個例子,JS代碼包URL的擷取是通過RCTBundleProvider這個類實作的。JS代碼包的URL有兩種可能結果,一種是Packager Server URL,一種是本地JS代碼包的檔案路徑。通過
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
去擷取JS代碼包URL時,會首先檢查是否有正在運作的Packager Server,如果有則傳回相應Packager Server中JS代碼包的絕對路徑;如果沒有正在運作的Packager Server,則會傳回一個本地JS代碼包的檔案路徑,不傳遞
fallbackResource
參數時,預設傳回 本地
main.jsbundle
的檔案路徑。
轉載于:https://www.cnblogs.com/richard-youth/p/9724870.html