本文共 9571 字,大约阅读时间需要 31 分钟。
先上一张 gif 图 ~~ 看看效果。
// 这一句指令在每一台电脑上只需要运行一次即可$ npm install -g react-native-update-cli rnpm
$ 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 的工程中能够看到依赖 )
如果指令链接失败使用下面的手动链接
RCTHotUpdate.a
和 libz.tbd
还有 libbz2.1.0.tbd
在 android/settings.gradle 中添加如下代码:
include ':react-native-update' project(':react-native-update').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-update/android')
android/app/build.gradle 的 dependencies 部分增加如下代码:
compile project(':react-native-update')
检查你的RN版本
// 如果是 0.29 及以上打开android/app/src/main/java/[...]/MainApplication.java// 否则打开android/app/src/main/java/[...]/MainActivity.java
import cn.reactnative.modules.update.UpdatePackage;在 getPackages() 方法中增加 new UpdatePackage() (注意ES5的话,函数与函数之间要加一个逗号)
#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 // ... 其它代码}
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); } // ... 其它代码}
在 注册账号
在你项目的根目录执行登录指令
$ pushy loginemail: <你注册时的邮箱> password: <你的登录密码>你的登录密码> 你注册时的邮箱>
登录成功之后会在你项目的根目录创建一个 .update
文件
需要注意的是不要把这个文件上传到 Git 中
你可以在 .gitignore
的末尾增加一行 .update
来忽略这个文件
$ pushy createApp --platform iosApp Name: <输入你应用的名字> $ pushy createApp --platform androidApp Name: <输入你应用的名字>输入你应用的名字> 输入你应用的名字>
两次输入的名字可以相同,不会有任何影响
$ pushy selectApp --plateform ios1) 微信2) 微博Total 2 ios appsEnter appId: <输入应用前面的编号>输入应用前面的编号>
选择完应用之后,会在你的根目录创建一个 update.json 的文件,其内容类似如下形式
{ "ios": { "appId" : "1", "appKey" : "一串随机字符串", }, "android": { "appId" : "2", "appKey" : "一串随机字符串", },}
你可以把 update.json
文件上传到 Git 服务器,与你的团队共享这个文件
当然他们在使用任何功能时,都必须使用 pushy loagin
进行登录
获取 appKey
检查更新时必须提供你的 appKey 这个值保存在你项目的 update.json 文件中,并且根据平台不同而不同
你可以使用如下代码进行获取相对应的 appKey
import { Platform,} from 'react-native';//------------------------- 华丽的分割线 -------------------------import _updateConfig from './update.json';const {appKey} = _updateConfig[Platform.OS];
检查更新、下载更新
checkUpdate(appKey).then(info =>{ // 返回的 info 有三种情况 // 1. {upToDate: true} 当前已经更新到最新版本,无需进行更新 // 2. {expired: true} 该应用包(源生应用)已经过期,需要前往应用市场下载新版 // 3. {update: true} 当前有新版本可以更新})info 的
name
description
字段可 以用于提示用户metaInfo
字段则可以根据你的需求自定义其它属性(如是否静默更新、 是否强制更新等等)。react-native-update
会首先尝试耗费流量更少的更新方式。downloadUpdate
作为参数即可。 downloadUpdate 的返回值是一个hash
字符串,它是当前版本的唯一标识。
你可以使用 switchVersion
函数立即切换版本(此时应用会立即重新加载),
或者选择调用 switchVersionLater
让应用在下一次启动的时候再加载新的版本。
在每次更新完毕后的首次启动时 isFirstTime
常量会为 true
你必须在应用退出前的任何时机,
调用 markSuccess
否则应用下一次启动的时候将会进行回滚操作。
这一机制称作 “反触发”,这样当你应用启动初期即遭遇问题的时候,也能在下一次启动时恢复运作。
你可以通过 isFirstTime
来获知这是当前版本的首次启动,
也可以通过 isRolledBack
来获知应用刚刚经历了一次回滚操作。 你可以在此时给予用户合理的提示。
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('提示', '这是当前版本第一次启动,是否要模拟启动失败?失败将回滚到上一版本', [ { text: '是', onPress: ()=>{ throw new Error('模拟启动失败,请重启应用')}}, { text: '否', onPress: ()=>{markSuccess()}}, ]); } else if (isRolledBack) { Alert.alert('提示', '刚刚更新失败了,版本被回滚.'); } } doUpdate = info => { downloadUpdate(info).then(hash => { Alert.alert('提示', '下载完毕,是否重启应用?', [ { text: '是', onPress: ()=>{switchVersion(hash);}}, { text: '否',}, { text: '下次启动时', onPress: ()=>{switchVersionLater(hash);}}, ]); }).catch(err => { Alert.alert('提示', '更新失败.'); }); }; checkUpdate = () => { checkUpdate(appKey).then(info => { if (info.expired) { Alert.alert('提示', '您的应用版本已更新,请前往应用商店下载新的版本', [ { text: '确定', onPress: ()=>{info.downloadUrl && Linking.openURL(info.downloadUrl)}}, ]); } else if (info.upToDate) { Alert.alert('提示', '您的应用版本已是最新.'); } else { Alert.alert('提示', '检查到新的版本'+info.name+',是否下载?\n'+ info.description, [ { text: '是', onPress: ()=>{ this.doUpdate(info)}}, { text: '否',}, ]); } }).catch(err => { Alert.alert('提示', '更新失败.'); }); }; render() { return (); }}//------------------------- 华丽的分割线 -------------------------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); 欢迎使用热更新服务 这是版本二 {'\n'} 当前包版本号: {packageVersion}{'\n'} 当前版本Hash: {currentVersion||'(空)'}{'\n'} 点击这里检查更新
现在,你的应用已经可以通过 update
服务检查版本并进行更新了。
从 update
上传发布版本到发布版本正式上线期间,不要修改任何脚本和资源,
这会影响 update
获取本地代码,从而导致版本不能更新。
如果在发布之前修改了脚本或资源,请在网页端删除之前上传的版本并重新上传。
首先确保你的应用 release
模式下 能够在真机上使用离线包。如果不能下面的文章也许是你需要的
然后点击菜单,按照正常的发布流程打一个 ipa 的包
在 Xcode 中运行设备选 真机
或 Generic iOS Device
然后菜单中选择 Product-Archive
然后在你项目的根目录运行如下命令
$ pushy uploadIpa <把你打的 ipa 的包拖拽到这里>把你打的>
此处上传 ipa 是为了后续版本对比之用。
首先参考 设置签名,然后在 android 文件夹下运行
./gradlew assembleRelease
你就可以在 android/app/build/outputs/apk/app-release.apk
中找到你的应用包。
然后运行如下命令
$ pushy uploadApk android/app/build/outputs/apk/app-release.apk
即可上传 apk
以供后续版本比对之用。
随后你可以选择往应用市场发布这个版本,也可以先往设备上直接安装这个 apk
文件以进行测试。
你可以尝试修改一行代码(譬如将版本一修改为版本二),然后生成新的热更新版本。
$ pushy bundle --platformBundling with React Native version: 0.22.2 <各种进度输出> Bundled saved to: build/output/android.1459850548545.ppkWould you like to publish it?(Y/N) 各种进度输出>
如果想要立即发布,此时输入 Y
当然,你也可以在将来使用 pushy publish --platform <ios|android> <ppkFile>
来发布版本。
然后你会看到
Uploading [========================================================] 100% 0.0sEnter 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) 输入版本描述> 输入版本名字,如1.0.0-rc>
此时版本已经提交到 update
服务器,但用户暂时看不到此更新。
你需要先将特定的 应用包的版本
与此 热更新版本包
进行绑定。
此时输入Y
立即绑定
你也可以在将来使用 pushy update --platform <ios | android>
来使得对应包版本的用户更新。
除此以外,你还可以在网页端操作,简单的将对应的包版本拖到此版本下即可。
Offset 01) 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回到开始,序号就是上面列表中)前面的数字> 1) 1.0(normal) - 3 FiWYm9lB (未命名)Total 1 packages.Enter packageId: <输入包版本序号,序号就是上面列表中)前面的数字>输入包版本序号,序号就是上面列表中)前面的数字> 输入序号,u>
来一张完成的图
版本绑定完毕后,客户端就应当可以检查到更新并进行更新了。
恭喜你,至此为止,你已经完成了植入代码热更新的全部工作。
转载地址:http://jqhni.baihongyu.com/