用了兩天才搞定了這些瑣碎的操作钧椰,從真機(jī)調(diào)試到利用CodePush進(jìn)行熱更新。杏瞻。所刀。知道最后才發(fā)現(xiàn)一個(gè)血的教訓(xùn):即使用了CodePush,本地也必須要有一個(gè)離線包才行伐憾,即本地需要打包一個(gè)main.jsbundle放進(jìn)項(xiàng)目中勉痴,才可以成功運(yùn)行赫模。
首先树肃,講React Native的發(fā)布更新,這就涉及到React Native的熱更新主要是怎么工作的瀑罗,關(guān)鍵在于bundle的更新胸嘴。
我們先來(lái)看看ReactNative是怎么處理bundle文件(bundle文件用于資源管理)的雏掠。可以有如下兩種方式:
1劣像、app發(fā)版時(shí)乡话,將bundle文件內(nèi)置到app中,同時(shí)將圖片和js文件內(nèi)置到app中(Android和iOS處理的不同)
2凹联、app在合適的時(shí)機(jī)慧耍,加載服務(wù)端最新的bundle文件
下面一張流程圖簡(jiǎn)單介紹ReactNative的熱更新機(jī)制:
(參考自:http://blog.csdn.net/codetomylaw/article/details/52115704)
一锥惋、打離線包(打包bundle文件內(nèi)置到app中)
離線包即本地存著一個(gè)離線包,保證沒(méi)有網(wǎng)絡(luò)的時(shí)候程序不會(huì)報(bào)錯(cuò)闸婴。
1、將js代碼打包到j(luò)sbundle文件中芍躏。
在index.ios.js所在目錄下邪乍,執(zhí)行以下命令(文件名自定義,使用codepush的時(shí)候最好命名為默認(rèn)的main.jsbundle):
// 無(wú)圖片資源等
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文件夾存在6钥ⅰ1永恪!)
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里面的代碼要對(duì)應(yīng))
asset-dest:輸出的asset資源目錄
*/
2否纬、添加到項(xiàng)目中吕晌。
在xcode中添加assets【必須用Create folder references的方式,添加完是藍(lán)色文件夾圖標(biāo)】和index.ios.jsbundle(或者main.jsbundle烦味、命名不同)
網(wǎng)上參考的放bundle文件夾的目錄結(jié)構(gòu)和項(xiàng)目結(jié)構(gòu)如下:
個(gè)人利用第一句命令創(chuàng)建的包聂使,目錄如下:
3、修改AppDelegate.m文件(只使用離線包不使用熱更新的情況)
// URLForResource根據(jù)第一步對(duì)應(yīng)的名字對(duì)應(yīng)修改
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"index.ios" withExtension:@"jsbundle"];
4谬俄、模擬器或者真機(jī)調(diào)試都沒(méi)有問(wèn)題柏靶。
順帶列舉下ios打包可能遇到的問(wèn)題(雖然我都沒(méi)遇到哈):
1)離線包如果開啟了chrome調(diào)試,會(huì)訪問(wèn)調(diào)試服務(wù)器溃论,而且會(huì)一直loading出不來(lái)屎蜓。
2)如果bundle的名字是main.jsbundle,app會(huì)一直讀取舊的,改名就好了。钥勋。炬转。非常奇葩的問(wèn)題,我重新刪了app算灸,clean工程都沒(méi)用扼劈,就是不能用main.jsbundle這個(gè)名字。
3)必須用Create folder references【藍(lán)色文件夾圖標(biāo)】的方式引入圖片的assets菲驴,否則引用不到圖片
4)執(zhí)行bundle命令之前荐吵,要保證相關(guān)的文件夾都存在
二、使用CodePush實(shí)現(xiàn)熱更新
1. 環(huán)境準(zhǔn)備(Mac)
1)安裝Code-push cli
$ npm install -g code-push-cli
2) 注冊(cè)CodePush賬戶
$ code-push register
執(zhí)行以上命令將會(huì)自動(dòng)打開如下圖所示的注冊(cè)頁(yè)面:
可以使用github或者M(jìn)icrosoft帳戶注冊(cè)(本文使用GitHub賬戶進(jìn)行注冊(cè)),注冊(cè)成功后將會(huì)生成如下圖所示相應(yīng)的access token:
按照提示在終端輸入剛生成的access token(會(huì)自動(dòng)登錄):
3)添加CodePush應(yīng)用
$ code-push app add XXX //xxx 為你要熱部署的app name
結(jié)果如下:
2. 安裝CodePush
在項(xiàng)目更目錄(或者說(shuō)package.json所在目錄)執(zhí)行以下語(yǔ)句安裝CodePush先煎,會(huì)自動(dòng)對(duì)應(yīng)修改package.json內(nèi)容贼涩。
npm install --save react-native-code-push
效果如下:
3. 集成code-push 到工程文件
CodePush集成到項(xiàng)目中,一般有三種方法:
RNPM薯蝎、CocoaPods 遥倦、"Manual"
詳細(xì)可參考CodePush的Github:
https://github.com/Microsoft/react-native-code-push
下文分別對(duì)其接入方法進(jìn)行簡(jiǎn)單介紹:
個(gè)人感覺(jué)按情況分,如果是將React Native集成到原生項(xiàng)目中的項(xiàng)目占锯,因?yàn)楸旧響?yīng)該有用到cocoaPods袒哥,所以推薦使用cocoaPods接入,比較方便簡(jiǎn)單消略。
如果是純React Native項(xiàng)目统诺,則可以考慮手動(dòng)接入。
(因?yàn)槲覝y(cè)試用的是原生集成項(xiàng)目疑俭,所以就使用了cocoaPods)
方式一:cocoaPods接入
1)修改Podfile文件:(自己注意路徑哈)
pod 'CodePush', :path => './node_modules/react-native-code-push'
2)執(zhí)行命令行更新pod:
pod install
// 或者
pod install --verbose --no-repo-update
方式二:手動(dòng)接入
1)將react-native-code-push文件夾中 CodePush.xcodeproj 直接拉入項(xiàng)目中Libraries中
2)在Link Binary With Libraries中添加Libraries/CodePush.xcodeproj /Products中的libCodePush.a以及l(fā)ibz.tbd粮呢。
3)在Build Settings的Header Search Paths那一項(xiàng)中加入(路徑要注意)
$(SRCROOT)/../node_modules/react-native-code-push
方式三:RNPM接入
好像是官方推薦使用最簡(jiǎn)單的方式,不過(guò)沒(méi)有試過(guò)哈
1)安裝rnpm
$ npm -g install rnpm xcode
2)使用
$ rpm link
4. 修改項(xiàng)目配置
1)在命令行下使用code-push deployment ls <AppName> --displayKeys 查出Staging的值钞艇,在info.plist文件中添加CodePushDeploymentKey并且把Staging的值填入啄寡。
2)在Info.plist中將Bundle versions string, short的值修改為1.0.0(或者其它,結(jié)構(gòu)一樣為x.x.x哩照,且和之后code push更新的版本要對(duì)應(yīng))
5. 修改OC代碼和JS代碼
1)在加載 js bundle的類中 修改代碼
a)首先挺物,引入頭文件:
#import "CodePush.h"
b)然后修改jsCodeLocation值:
//該文章是討論在Release下進(jìn)行相關(guān)的操作,如果是debug版本加上如下代碼飘弧,系統(tǒng)在運(yùn)行時(shí)候會(huì)自動(dòng)切換识藤。
NSURL *jsCodeLocation;
#ifdef DEBUG
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
#else
jsCodeLocation = [CodePush bundleURL];
#endif
//如果本地js離線包不是命名main.jsbundle,需要對(duì)CodePush進(jìn)行相應(yīng)設(shè)置
jsCodeLocation = [CodePush bundleURLForResource:@"index"];
2)在js文件中(該項(xiàng)目文件是index.ios.js) 修改代碼
a)引入對(duì)應(yīng)頭文件
import codePush from "react-native-code-push";
b)在componentDidMount調(diào)用sync方法,當(dāng)你的App啟動(dòng)的時(shí)候會(huì)在后臺(tái)更新
componentDidMount(){
codePush.sync();
}
6. 發(fā)布更新
1)發(fā)布更新 (JavaScript-only)
當(dāng)你修改js文件的時(shí)候次伶,并且想立刻發(fā)布痴昧。則僅僅需要以下的操作:
- 將你修改的js文件(當(dāng)前文件是index.ios.js)打包為二進(jìn)制文件,放入指定的地方(當(dāng)前位置為根目錄)冠王。
react-native bundle --platform ios --entry-file index.ios.js --bundle-output codepush.js --dev false
- 將二進(jìn)制文件push到staging 環(huán)境中
code-push release [--deploymentName ] [--description ] [--mandatory]
eg:
code-push release NativeTest codepush.js 1.0.0
// 上面代碼運(yùn)行有問(wèn)題的話赶撰,試試把codepush.js后綴改成codepush.jsbundle。柱彻。好像目前版本和我上年底的要求不同了
2)發(fā)布更新 (JavaScript + images)
- –assets-dest 就是你放圖片的位置(當(dāng)前僅僅是做測(cè)試豪娜,實(shí)際上最好建個(gè)文件夾專門存入相關(guān)圖片)
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(與注冊(cè)的app同名)><bundle文件名> <版本號(hào)>
eg:
code-push release NativeTest main.jsbundle 1.0.0
到這一步的時(shí)候,正常來(lái)說(shuō)哟楷,該配置的都配置了瘤载,試著更新一個(gè)版本push到codepush上,運(yùn)行下項(xiàng)目卖擅,就會(huì)出現(xiàn)效果鸣奔。
注意:如果出現(xiàn)找不到main.jsbundle的報(bào)錯(cuò)坟冲,很大的原因就是沒(méi)有在本地打個(gè)離線包,詳細(xì)參考這篇文章的第一部分溃蔫。(曾經(jīng)因?yàn)檫@個(gè)原因,我看著報(bào)錯(cuò)發(fā)呆了好久琳猫,上網(wǎng)也找不到任何說(shuō)法??)
Q&A
-
CodePush更新規(guī)則
- 更新后都需要重啟才能看到最新的變化 再次進(jìn)入后要等一會(huì)伟叛。TODO:還要驗(yàn)證后確定穩(wěn)定時(shí)機(jī)。
- 查看歷史上傳過(guò)的版本:
code-push deployment history NativeTest Staging
更多的CodePush相關(guān)命令推薦參考以下幾篇文章:
Code Push 熱更新使用詳細(xì)說(shuō)明和教程
app實(shí)現(xiàn)熱更新codepush
以及CodePush的Github:
https://github.com/Microsoft/react-native-code-push