天天看點

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

将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項目。如下:

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

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為自己的原生項目名,確定資訊為最新的,且不容易出錯。  

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

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

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結
将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結
将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

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/  

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

  參考之後( 注意可能不同版本不一樣),編輯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相關資料,顯得整潔,便于管理。

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

  工程目錄結構:

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

  注意工程目錄結構中并沒有将 RNComponent 拖進去,因為cocopods 已經引用過了相關的東西。   1、配置App Transport Security

在iOS 9以上的系統中,除非明确指明,否則應用無法通過http協定連接配接到localhost主機。 建議在Info.plist進行如下設定,否則會報Could not connect to development server錯誤。

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

2、添加RCTRootView 這裡隻是在ViewController中進行了測試,具體放在什麼地方,怎麼放置大家根據項目需求而定。  

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

3、開啟RN本地服務(cd 到RNComponent目錄)

$ cd /Users/galahad/Desktop/ziliao/OC項目內建RN演練/yooweiRN/RNComponent 

$ react-native start

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

不出意外的是下面這個場景

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

原因:列印日志看看

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

由于RN不同版本,入口檔案名不同,根據實際入口檔案名,修改之後。

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

模拟器展示如下:

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

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應當和電腦連接配接的是同一個網絡才可以) 

将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結
将React Native 內建進現有OC項目中(過程記錄) 、jsCodeLocation 生成方式總結

至此,将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

繼續閱讀