用了兩天才搞定了這些瑣碎的操作,從真機調試到利用CodePush進行熱更新。。。知道最后才發現一個血的教訓:即使用了CodePush,本地也必須要有一個離線包才行,即本地需要打包一個main.jsbundle放進項目中,才可以成功運行。
首先,講React Native的發布更新,這就涉及到React Native的熱更新主要是怎么工作的,關鍵在于bundle的更新。
我們先來看看ReactNative是怎么處理bundle文件(bundle文件用于資源管理)的。可以有如下兩種方式:
1、app發版時,將bundle文件內置到app中,同時將圖片和js文件內置到app中(Android和iOS處理的不同)
2、app在合適的時機,加載服務端最新的bundle文件
下面一張流程圖簡單介紹ReactNative的熱更新機制:
(參考自:http://blog.csdn.net/codetomylaw/article/details/52115704)
一、打離線包(打包bundle文件內置到app中)
離線包即本地存著一個離線包,保證沒有網絡的時候程序不會報錯。
1、將js代碼打包到jsbundle文件中。
在index.ios.js所在目錄下,執行以下命令(文件名自定義,使用codepush的時候最好命名為默認的main.jsbundle):
// 無圖片資源等
react-native bundle --entry-file index.ios.js --platform ios --bundle-output main.jsbundle
// 有圖片資源
react-native bundle --entry-file index.ios.js --platform ios --bundle-output index.ios.bundle --platform ios --dev false --assets-dest ./
// 或者放bundle文件夾里(注意要先保證bundle文件夾存在!?。。?
react-native bundle –entry-file index.ios.js –bundle-output ./bundle/iosBundle/index.ios.jsbundle –platform ios –assets-dest ./bundle/iosBundle –dev false
/*
entry-file: RN的入口文件
bundle-out: 輸出bundle文件的輸出路徑(bundle文件名和oc里面的代碼要對應)
asset-dest:輸出的asset資源目錄
*/
2、添加到項目中。
在xcode中添加assets【必須用Create folder references的方式,添加完是藍色文件夾圖標】和index.ios.jsbundle(或者main.jsbundle、命名不同)
網上參考的放bundle文件夾的目錄結構和項目結構如下:
個人利用第一句命令創建的包,目錄如下:
3、修改AppDelegate.m文件(只使用離線包不使用熱更新的情況)
// URLForResource根據第一步對應的名字對應修改
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"index.ios" withExtension:@"jsbundle"];
4、模擬器或者真機調試都沒有問題。
順帶列舉下ios打包可能遇到的問題(雖然我都沒遇到哈):
1)離線包如果開啟了chrome調試,會訪問調試服務器,而且會一直loading出不來。
2)如果bundle的名字是main.jsbundle,app會一直讀取舊的,改名就好了。。。非常奇葩的問題,我重新刪了app,clean工程都沒用,就是不能用main.jsbundle這個名字。
3)必須用Create folder references【藍色文件夾圖標】的方式引入圖片的assets,否則引用不到圖片
4)執行bundle命令之前,要保證相關的文件夾都存在
二、使用CodePush實現熱更新
1. 環境準備(Mac)
1)安裝Code-push cli
$ npm install -g code-push-cli
2) 注冊CodePush賬戶
$ code-push register
執行以上命令將會自動打開如下圖所示的注冊頁面:
可以使用github或者Microsoft帳戶注冊(本文使用GitHub賬戶進行注冊),注冊成功后將會生成如下圖所示相應的access token:
按照提示在終端輸入剛生成的access token(會自動登錄):
3)添加CodePush應用
$ code-push app add XXX //xxx 為你要熱部署的app name
結果如下:
2. 安裝CodePush
在項目更目錄(或者說package.json所在目錄)執行以下語句安裝CodePush,會自動對應修改package.json內容。
npm install --save react-native-code-push
效果如下:
3. 集成code-push 到工程文件
CodePush集成到項目中,一般有三種方法:
RNPM、CocoaPods 、"Manual"
詳細可參考CodePush的Github:
https://github.com/Microsoft/react-native-code-push
下文分別對其接入方法進行簡單介紹:
個人感覺按情況分,如果是將React Native集成到原生項目中的項目,因為本身應該有用到cocoaPods,所以推薦使用cocoaPods接入,比較方便簡單。
如果是純React Native項目,則可以考慮手動接入。
(因為我測試用的是原生集成項目,所以就使用了cocoaPods)
方式一:cocoaPods接入
1)修改Podfile文件:(自己注意路徑哈)
pod 'CodePush', :path => './node_modules/react-native-code-push'
2)執行命令行更新pod:
pod install
// 或者
pod install --verbose --no-repo-update
方式二:手動接入
1)將react-native-code-push文件夾中 CodePush.xcodeproj 直接拉入項目中Libraries中
2)在Link Binary With Libraries中添加Libraries/CodePush.xcodeproj /Products中的libCodePush.a以及libz.tbd。
3)在Build Settings的Header Search Paths那一項中加入(路徑要注意)
$(SRCROOT)/../node_modules/react-native-code-push
方式三:RNPM接入
好像是官方推薦使用最簡單的方式,不過沒有試過哈
1)安裝rnpm
$ npm -g install rnpm xcode
2)使用
$ rpm link
4. 修改項目配置
1)在命令行下使用code-push deployment ls <AppName> --displayKeys 查出Staging的值,在info.plist文件中添加CodePushDeploymentKey并且把Staging的值填入。
2)在Info.plist中將Bundle versions string, short的值修改為1.0.0(或者其它,結構一樣為x.x.x,且和之后code push更新的版本要對應)
5. 修改OC代碼和JS代碼
1)在加載 js bundle的類中 修改代碼
a)首先,引入頭文件:
#import "CodePush.h"
b)然后修改jsCodeLocation值:
//該文章是討論在Release下進行相關的操作,如果是debug版本加上如下代碼,系統在運行時候會自動切換。
NSURL *jsCodeLocation;
#ifdef DEBUG
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
#else
jsCodeLocation = [CodePush bundleURL];
#endif
//如果本地js離線包不是命名main.jsbundle,需要對CodePush進行相應設置
jsCodeLocation = [CodePush bundleURLForResource:@"index"];
2)在js文件中(該項目文件是index.ios.js) 修改代碼
a)引入對應頭文件
import codePush from "react-native-code-push";
b)在componentDidMount調用sync方法,當你的App啟動的時候會在后臺更新
componentDidMount(){
codePush.sync();
}
6. 發布更新
1)發布更新 (JavaScript-only)
當你修改js文件的時候,并且想立刻發布。則僅僅需要以下的操作:
- 將你修改的js文件(當前文件是index.ios.js)打包為二進制文件,放入指定的地方(當前位置為根目錄)。
react-native bundle --platform ios --entry-file index.ios.js --bundle-output codepush.js --dev false
- 將二進制文件push到staging 環境中
code-push release [--deploymentName ] [--description ] [--mandatory]
eg:
code-push release NativeTest codepush.js 1.0.0
// 上面代碼運行有問題的話,試試把codepush.js后綴改成codepush.jsbundle。。好像目前版本和我上年底的要求不同了
2)發布更新 (JavaScript + images)
- –assets-dest 就是你放圖片的位置(當前僅僅是做測試,實際上最好建個文件夾專門存入相關圖片)
react-native bundle --platform ios --entry-file index.ios.js --bundle-output ./main.jsbundle --assets-dest ./<img 地址>
// main.jsbundle 為自定義名字的bundle名
- push bundle文件
code-push <release/debug> <projectName(與注冊的app同名)><bundle文件名> <版本號>
eg:
code-push release NativeTest main.jsbundle 1.0.0
到這一步的時候,正常來說,該配置的都配置了,試著更新一個版本push到codepush上,運行下項目,就會出現效果。
注意:如果出現找不到main.jsbundle的報錯,很大的原因就是沒有在本地打個離線包,詳細參考這篇文章的第一部分。(曾經因為這個原因,我看著報錯發呆了好久,上網也找不到任何說法??)
Q&A
-
CodePush更新規則
CodePush更新規則.png - 更新后都需要重啟才能看到最新的變化 再次進入后要等一會。TODO:還要驗證后確定穩定時機。
- 查看歷史上傳過的版本:
code-push deployment history NativeTest Staging
更多的CodePush相關命令推薦參考以下幾篇文章:
Code Push 熱更新使用詳細說明和教程
app實現熱更新codepush
以及CodePush的Github:
https://github.com/Microsoft/react-native-code-push