一汁掠、準(zhǔn)備工作
- 首先你需要一個 React Native 的應(yīng)用真屯,如果還沒有或許下面文章能幫到你
如何創(chuàng)建 React Native 應(yīng)用 - 如果你的電腦還沒有安裝 React Native 的開發(fā)環(huán)境逞盆, 那么這篇文章適合你
搭建 React Native 的開發(fā)環(huán)境 - 如果你是在源生項目中使用 React Native 那么這篇文章也行對你會有幫助
如何在源生項目中使用 React Native - 在 React Native 中我們把具有 package.json 的目錄稱之為 "應(yīng)用的根目錄"
React Native 如何真機(jī) release 模式運行 - 真機(jī) release 模式運行需要 jsbundle 的離線包等條件
此篇文章假設(shè)我們已經(jīng)滿足以上所有需要的準(zhǔn)備工作。
記得【關(guān)注】倔喂,感謝支持恢氯,后期還會有更新。
先上一張 gif 圖 ~~ 看看效果阱州。
二挑秉、安裝
-
在你項目的根目錄運行以下指令
// 這一句指令在每一臺電腦上只需要運行一次即可
$ npm install -g react-native-update-cli rnpm
-
如果你訪問速度過慢或者網(wǎng)絡(luò)鏈接失敗,請將鏡像源換成國內(nèi)鏡像源
$ npm config set registry https://registry.npm.taobao.org --global
$ npm config set disturl https://npm.taobao.rog/dist --global
-
安裝保存指定的版本到你的項目
$ npm install --save react-native-update@具體版本號參看下面表格;
// 例如
$ npm install --save react-native-update@4.x
-
鏈接
-
使用指令鏈接
-
$ react-native link react-native-update;
// 如果你安裝的 React Native 版本低于 0.29 則使用下面這條指令
$ npm link react-native-update
這時候如果 react-native link 成功的話 ( iOS 跟 Android 的工程中能夠看到依賴 )
如果指令鏈接失敗使用下面的手動鏈接
-
使用手動鏈接
-
iOS
- 在 Xcode 中打開你的項目苔货,選擇項目然后右鍵 Show in Finder 進(jìn)入項目的目錄
- 找到你的 React Native 安裝的位置犀概,也就是 node_modules 文件夾
- 進(jìn)入 node_modules 文件夾找到 react-native-update 里面的 ios 文件夾
- 將 RCTHotUpdate.xcodeproj 拖入到你的 Xcode 中
- 在項目的 Build Phases 找到 Link Binary With Libraries 點擊下方的 + 加號
- 依次添加
RCTHotUpdate.a
和libz.tbd
還有libbz2.1.0.tbd
- 完成后使用 Command + B 編譯之后不報錯就是 OK 啦
Snip20161208_38.png
-
Android
- 在 android/settings.gradle 中添加如下代碼:
-
include ':react-native-update' project(':react-native-update').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-update/android')
2. android/app/build.gradle 的 dependencies 部分增加如下代碼:
compile project(':react-native-update')
3. 檢查你的RN版本
// 如果是 0.29 及以上打開
android/app/src/main/java/[...]/MainApplication.java
// 否則打開
android/app/src/main/java/[...]/MainActivity.java
4. 在文件開頭增加
import cn.reactnative.modules.update.UpdatePackage;
在 getPackages() 方法中增加 new UpdatePackage() (注意ES5的話,函數(shù)與函數(shù)之間要加一個逗號)
三夜惭、配置Bundle URL 在源生代碼中使用
-
iOS
一般情況下是在 appDelegate 中 新增如下代碼
#import "RCTHotUpdate.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSURL *jsCodeLocation;
#if DEBUG
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
#else
jsCodeLocation=[RCTHotUpdate bundleURL];
#endif
// ... 其它代碼
}
-
Android
項目中 React Native 版本 >= 0.29 在你的 MainApplication
中增加如下代碼
// ... 其它代碼
import cn.reactnative.modules.update.UpdateContext;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected String getJSBundleFile() {
return UpdateContext.getBundleUrl(MainApplication.this);
}
// ... 其它代碼
}
}
項目中 React Native 版本 <= 0.28 在你的 MainActivity
中增加如下代碼:
// ... 其它代碼
import cn.reactnative.modules.update.UpdateContext;
public class MainActivity extends ReactActivity {
@Override protected String getJSBundleFile() {
return UpdateContext.getBundleUrl(this);
}
// ... 其它代碼
}
四姻灶、登錄與創(chuàng)建應(yīng)用登錄
-
注冊賬號
在 http://update.reactnative.cn 注冊賬號
-
登錄
在你項目的根目錄執(zhí)行登錄指令
$ pushy login
email: <你注冊時的郵箱>
password: <你的登錄密碼>
登錄成功之后會在你項目的根目錄創(chuàng)建一個 .update
文件
需要注意的是不要把這個文件上傳到 Git 中
你可以在 .gitignore
的末尾增加一行 .update
來忽略這個文件
-
創(chuàng)建應(yīng)用
$ pushy createApp --platform ios
App Name: <輸入你應(yīng)用的名字>
$ pushy createApp --platform android
App Name: <輸入你應(yīng)用的名字>
兩次輸入的名字可以相同,不會有任何影響
-
如果你在網(wǎng)頁端或者其他地方創(chuàng)建過應(yīng)用诈茧,可以直接選擇應(yīng)用
$ pushy selectApp --plateform ios
1) 微信
2) 微博
Total 2 ios apps
Enter appId: <輸入應(yīng)用前面的編號>
選擇完應(yīng)用之后木蹬,會在你的根目錄創(chuàng)建一個 update.json 的文件,其內(nèi)容類似如下形式
{
"ios": {
"appId" : "1",
"appKey" : "一串隨機(jī)字符串",
},
"android": {
"appId" : "2",
"appKey" : "一串隨機(jī)字符串",
},
}
你可以把 update.json
文件上傳到 Git 服務(wù)器若皱,與你的團(tuán)隊共享這個文件
當(dāng)然他們在使用任何功能時,都必須使用 pushy loagin
進(jìn)行登錄
五尘颓、使用熱更新功能
- 獲取 appKey
檢查更新時必須提供你的 appKey 這個值保存在你項目的 update.json 文件中走触,并且根據(jù)平臺不同而不同
你可以使用如下代碼進(jìn)行獲取相對應(yīng)的 appKey
import {
Platform,
} from 'react-native';
//------------------------- 華麗的分割線 -------------------------
import _updateConfig from './update.json';
const {appKey} = _updateConfig[Platform.OS];
- 檢查更新、下載更新
- 異步函數(shù) checkUpdate 可以檢查當(dāng)前版本是否需要更新
checkUpdate(appKey)
.then(info =>{
// 返回的 info 有三種情況
// 1. {upToDate: true} 當(dāng)前已經(jīng)更新到最新版本疤苹,無需進(jìn)行更新
// 2. {expired: true} 該應(yīng)用包(源生應(yīng)用)已經(jīng)過期互广,需要前往應(yīng)用市場下載新版
// 3. {update: true} 當(dāng)前有新版本可以更新
})
info 的 name
description
字段可 以用于提示用戶
而 metaInfo
字段則可以根據(jù)你的需求自定義其它屬性(如是否靜默更新、 是否強(qiáng)制更新等等)卧土。
另外還有幾個字段惫皱,包含了完整更新包或補(bǔ)丁包的下載地址 ,
react-native-update
會首先嘗試耗費流量更少的更新方式尤莺。
將 info 對象傳遞給 downloadUpdate
作為參數(shù)即可旅敷。
-
切換版本
downloadUpdate 的返回值是一個hash
字符串,它是當(dāng)前版本的唯一標(biāo)識颤霎。
你可以使用 switchVersion
函數(shù)立即切換版本(此時應(yīng)用會立即重新加載)媳谁,
或者選擇調(diào)用 switchVersionLater
讓應(yīng)用在下一次啟動的時候再加載新的版本。
-
首次啟動友酱、回滾
在每次更新完畢后的首次啟動時 isFirstTime
常量會為 true
你必須在應(yīng)用退出前的任何時機(jī)晴音,
調(diào)用 markSuccess
否則應(yīng)用下一次啟動的時候?qū)M(jìn)行回滾操作。
這一機(jī)制稱作 “反觸發(fā)”缔杉,這樣當(dāng)你應(yīng)用啟動初期即遭遇問題的時候锤躁,也能在下一次啟動時恢復(fù)運作。
你可以通過 isFirstTime
來獲知這是當(dāng)前版本的首次啟動或详,
也可以通過 isRolledBack
來獲知應(yīng)用剛剛經(jīng)歷了一次回滾操作系羞。 你可以在此時給予用戶合理的提示郭计。
-
完整的示例
import React, {
Component,
} from 'react';
//------------------------- 華麗的分割線 -------------------------
import {
AppRegistry,
StyleSheet,
Platform,
Text,
View,
Alert,
TouchableOpacity,
Linking,
} from 'react-native';
//------------------------- 華麗的分割線 -------------------------
import {
isFirstTime,
isRolledBack,
packageVersion,
currentVersion,
checkUpdate,
downloadUpdate,
switchVersion,
switchVersionLater,
markSuccess,
} from 'react-native-update';
//------------------------- 華麗的分割線 -------------------------
import _updateConfig from './update.json';
const {appKey} = _updateConfig[Platform.OS];
//------------------------- 華麗的分割線 -------------------------
class ChiefSteward extends Component {
componentWillMount(){
if (isFirstTime) {
Alert.alert('提示', '這是當(dāng)前版本第一次啟動,是否要模擬啟動失敗?失敗將回滾到上一版本', [
{text: '是', onPress: ()=>{throw new Error('模擬啟動失敗,請重啟應(yīng)用')}},
{text: '否', onPress: ()=>{markSuccess()}},
]);
} else if (isRolledBack) {
Alert.alert('提示', '剛剛更新失敗了,版本被回滾.');
}
}
doUpdate = info => {
downloadUpdate(info).then(hash => {
Alert.alert('提示', '下載完畢,是否重啟應(yīng)用?', [
{text: '是', onPress: ()=>{switchVersion(hash);}},
{text: '否',},
{text: '下次啟動時', onPress: ()=>{switchVersionLater(hash);}},
]);
}).catch(err => {
Alert.alert('提示', '更新失敗.');
});
};
checkUpdate = () => {
checkUpdate(appKey).then(info => {
if (info.expired) {
Alert.alert('提示', '您的應(yīng)用版本已更新,請前往應(yīng)用商店下載新的版本', [
{text: '確定', onPress: ()=>{info.downloadUrl && Linking.openURL(info.downloadUrl)}},
]);
} else if (info.upToDate) {
Alert.alert('提示', '您的應(yīng)用版本已是最新.');
} else {
Alert.alert('提示', '檢查到新的版本'+info.name+',是否下載?\n'+ info.description, [
{text: '是', onPress: ()=>{this.doUpdate(info)}},
{text: '否',},
]);
}
}).catch(err => {
Alert.alert('提示', '更新失敗.');
});
};
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
歡迎使用熱更新服務(wù)
</Text>
<Text style={styles.instructions}>
這是版本二 {'\n'}
當(dāng)前包版本號: {packageVersion}{'\n'}
當(dāng)前版本Hash: {currentVersion||'(空)'}{'\n'}
</Text>
<TouchableOpacity onPress={this.checkUpdate}>
<Text style={styles.instructions}>
點擊這里檢查更新
</Text>
</TouchableOpacity>
</View>
);
}
}
//------------------------- 華麗的分割線 -------------------------
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
//------------------------- 華麗的分割線 -------------------------
AppRegistry.registerComponent('ChiefSteward', () => ChiefSteward);
現(xiàn)在,你的應(yīng)用已經(jīng)可以通過 update
服務(wù)檢查版本并進(jìn)行更新了觉啊。
六拣宏、發(fā)布與更新
-
首先需要注意的是
從 update
上傳發(fā)布版本到發(fā)布版本正式上線期間,不要修改任何腳本和資源杠人,
這會影響 update
獲取本地代碼勋乾,從而導(dǎo)致版本不能更新。
如果在發(fā)布之前修改了腳本或資源嗡善,請在網(wǎng)頁端刪除之前上傳的版本并重新上傳辑莫。
-
發(fā)布 iOS 應(yīng)用
首先確保你的應(yīng)用
release
模式下 能夠在真機(jī)上使用離線包。如果不能下面的文章也許是你需要的
React Native 在 release 模式真機(jī)運行然后點擊菜單罩引,按照正常的發(fā)布流程打一個 ipa 的包
在 Xcode 中運行設(shè)備選真機(jī)
或Generic iOS Device
然后菜單中選擇Product-Archive
然后在你項目的根目錄運行如下命令
$ pushy uploadIpa <把你打的 ipa 的包拖拽到這里>
此處上傳 ipa 是為了后續(xù)版本對比之用各吨。
-
發(fā)布 Android 應(yīng)用
首先參考 文檔-生成已簽名的APK 設(shè)置簽名,然后在 android 文件夾下運行
./gradlew assembleRelease
你就可以在 android/app/build/outputs/apk/app-release.apk
中找到你的應(yīng)用包袁铐。
然后運行如下命令
$ pushy uploadApk android/app/build/outputs/apk/app-release.apk
即可上傳 apk
以供后續(xù)版本比對之用揭蜒。
隨后你可以選擇往應(yīng)用市場發(fā)布這個版本,也可以先往設(shè)備上直接安裝這個 apk
文件以進(jìn)行測試剔桨。
-
發(fā)布新的熱更新版本
你可以嘗試修改一行代碼(譬如將版本一修改為版本二)屉更,然后生成新的熱更新版本。
$ pushy bundle --platform <ios|android>Bundling with React Native version: 0.22.2
<各種進(jìn)度輸出>
Bundled saved to: build/output/android.1459850548545.ppk
Would you like to publish it?(Y/N)
如果想要立即發(fā)布洒缀,此時輸入 Y
當(dāng)然瑰谜,你也可以在將來使用 pushy publish --platform <ios|android> <ppkFile>
來發(fā)布版本。
然后你會看到
Uploading [========================================================] 100% 0.0s
Enter version name: <輸入版本名字树绩,如1.0.0-rc>
Enter description: <輸入版本描述>
Enter meta info: {"ok":1}
Ok.
Would you like to bind packages to this version?(Y/N)
此時版本已經(jīng)提交到 update
服務(wù)器萨脑,但用戶暫時看不到此更新。
你需要先將特定的 應(yīng)用包的版本
與此 熱更新版本包
進(jìn)行綁定饺饭。
此時輸入Y
立即綁定
你也可以在將來使用 pushy update --platform <ios | android>
來使得對應(yīng)包版本的用戶更新渤早。
除此以外,你還可以在網(wǎng)頁端操作瘫俊,簡單的將對應(yīng)的包版本拖到此版本下即可蛛芥。
Offset 0
1) FvXnROJ1 1.0.1 (no package)
2) FiWYm9lB 1.0 [1.0]
Enter versionId or page Up/page Down/Begin(U/D/B) <輸入序號,U/D翻頁,B回到開始,序號就是上面列表中)前面的數(shù)字>
1) 1.0(normal) - 3 FiWYm9lB (未命名)
Total 1 packages.
Enter packageId: <輸入包版本序號军援,序號就是上面列表中)前面的數(shù)字>
來一張完成的圖
版本綁定完畢后仅淑,客戶端就應(yīng)當(dāng)可以檢查到更新并進(jìn)行更新了。
恭喜你胸哥,至此為止涯竟,你已經(jīng)完成了植入代碼熱更新的全部工作。