RN开发-使用pushy进行热更新

3,535 阅读5分钟

本文由我们团队的丁武龙组内分享总结

前言

随着react-native的出现,让移动开发出现了更加便捷的方式,由于react-native使用的是脚本语言编写,实现了解释运行的方式,这种执行方式只需要替换脚本文件就可以了,不需要再次发布应用程序,极大的节省了发布时间和方便了迭代开发,本文主要讲述的热更新组件是国内开发的组件pushy,其功能类似于CodePush,但由于codePush是国外的,在国内访问的速度比较慢,pushy支持增量更新,最大化的降低更新的数据量,节约流量。

操作流程

1.要想使用pushy,那就先创建一个RN项目,终端输入

react-native init projectName --version 0.55.4 //指定0.55.4版本

2.安装update工具,因为pushy热更新需要uodate配合使用

npm install -g react-native-update-cli  //每台电脑只需要运行一次即可

3.安装pushy组件,这里使用的是yarn方式,也可以使用npm方式

//yarn 方式
yarn add react-native-update
//npm 方式
npm install react-native-update --save
//link到项目中
react-native link react-native-update

配置Bundle URL

  1. 在iOS工程目录下,首先在工程target的Build Phases->Link Binary with Libraries中加入libz.tbd、libbz2.1.0.tbd
    2.然后再AppDelegate.m文件下添加以下代码
...省略代码
#import "RCTHotUpdate.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  NSURL *jsCodeLocation;


#if DEBUG
  jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
  // 非DEBUG情况下启用热更新
  jsCodeLocation=[RCTHotUpdate bundleURL];
#endif
......
}

3.iOS外的白名单配置

从iOS9开始,苹果要求以白名单的形式在Info.plist中列出外部的非https接口,以督促开发者部署https协议。在我们的服务部署https协议之前,请在Info.plist中添加如下例外

4.登录与创建应用

1.首先需要在update.reactnative.cn注册一个账号,然后cd到项目根目录下,执行命令

pushy login
email: <注册邮箱>
password: <密码>

执行完了之后会在项目根目录下自动生成一个.update文件,注(不要把这个文件上传到Git等CVS系统上。你可以在.gitignore末尾增加一行.update来忽略这个文件)登录完成之后即可创建安卓或者ios应用程序(每个账号不超过3个应用),两端程序需要分别创建

//ios
pushy createApp --platform ios
App Name: <输入应用名字>
//an
pushy createApp --platform android
App Name: <输入应用名字>

创建完应用之后,即可在项目里看到update.json文件,内容形式如下

{
    "ios": {
        "appId": 14954,
        "appKey": "OEKJy0mUCcbaFR9UJrMFrEOH-k89FX44"
    }
}

可以把update.json上传到Git等CVS系统上,与你的团队共享这个文件,它不包含任何敏感信息。当然,他们在使用任何功能之前,都必须首先输入pushy login进行登录。
以上步骤完成之后,现在下面给给项目添加热更新功能代码

热更新功能实现

获取Appkey

检查更新是必须提供appkey,创建应用的时候都会生成一个appkey,这个值保存在update.json文件中,可以在App.js文件获取appkey

import {Platform,} from 'react-native';
import updateConfig from './update.json';
const {appKey} = updateConfig[Platform.OS];

检查更新/下载更新内容

使用异步函数checkUpdate可以检测当前版本是否需要更新

checkUpdate(appKey)
    .then(info => {
    })

返回的info有一下几类情况
1.{expired: true}:该应用包(原生部分)已过期,需要去应用市场下载更新应用程序
2.{upToDate: true} 当前版本已经是最新版本,无需更新
3.{update: true} 表示有新的版本可以更新了。info的name、description字段可 以用于提示用户,而metaInfo字段则可以根据你的需求自定义其它属性(如是否静默更新、 是否强制更新等等)。另外还有几个字段,包含了完整更新包或补丁包的下载地址, react-native-update会首先尝试耗费流量更少的更新方式。将info对象传递给downloadUpdate作为参数即可。

切换版本

downloadUpdate返回的是一个hash字符串,是当前版本的唯一字符串.
可以使用switchVersion函数来快速切换版本,应用程序会立即加载,代码如下

import React, {Component} from 'react'
import {
  Platform,
  View,
  Alert,
} from 'react-native'
import {
  isFirstTime,
  isRolledBack,
  checkUpdate,
  downloadUpdate,
  switchVersion,
  switchVersionLater,
  markSuccess,
} from 'react-native-update'

...
componentWillMount() {
    if (isFirstTime) {
      Alert.alert('提示', '这是当前版本第一次启动,是否要模拟启动失败?失败将回滚到上一版本', [
        {text: '是', onPress: () => { throw new Error('模拟启动失败,请重启应用') }},
        {text: '否', onPress: () => { markSuccess() }},
      ])
    } else if (isRolledBack) {
      Alert.alert('提示', '刚刚更新失败了,版本被回滚.')
    }
    this.checkUpdate()
  }
...
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) => {
        // alert(info.upToDate)
        if (info.expired) {
          Alert.alert('提示', '您的应用版本已更新,请前往应用商店下载新的版本', [
            {text: '确定', onPress: () => {}},
          ])
        } else if (info.upToDate) {
          Alert.alert('提示', '您的应用版本已是最新.')
        } else {
          Alert.alert('提示', `检查到新的版本${info.name},是否下载?\n${info.description}`, [
            {text: '是', onPress: () => { this.doUpdate(info) }},
            {text: '否'},
          ])
        }
      }).catch((err) => {
        Alert.alert('提示', '更新失败.')
      })
    }

...

现在可以通过update服务检查版本是否有更新了,

发布应用包和版本

注意 从发布版本到正式上线期间,不要更改脚本文件和资源,如果修改,可能会造成脚本出现问题,导致无法更新。

1.在真机模式或者Generic iOS Device模式下对项目打包,Product-Archive,打包完成之后,生成一个IPA文件,上传到分发平台进行下载测试,执行命令

pushy uploadIpa  ipa路径

发布热更新包

修改一行代码(比如在App.js文件增加一个弹框),然后生成新的热更新版本。

pushy bundle --platform ios Bundling with React Native version:  0.55.4
.....
Would you like to publish it?(Y/N)

如果想要立即发布,输入Y即可,

Uploading [========================================================] 100% 0.0s
Enter version name: 1.100
Enter description: update 
Enter meta info: {"ok":1}
Version published: 42053
Would you like to bind packages to this version?(Y/N)

此时版本已经提交到update服务,但用户暂时看不到此更新,你需要先将特定的包版本绑定到此热更新版本上
输入Y进行绑定

Y
21144(出现的这串数字要记住,下面要用到)) 1.1(normal) (newest)
Total 1 packages.
Enter packageId: 21144
Ok.

至此,热更新集成完成,