RN热更新——codepush

一、安装注册code-push

1.安装code-push
$ npm install -g code-push-cli
2.注册账号
$ code-push register

这时候会自动启动浏览器打开网页并提供一个codePush AccessKey,然后命令行里出现需要输入access key

Enter your access key:

输入access key�登录

3.添加一个CodePush应用(myProject是应用名字)
$ code-push app add �myProject

出现

||     name    || Deployment Key ||
|| Production  || (一串37位的key) ||
|| Staging     || (一串37位的key) ||

如上有两个发布键值。一个Production是对应生产环境的,二Staging是对应开发环境的。当然我们还可以添加其他的发布键值。
这个值在后面我们集成工程里面要用到。

二、react-native应用接入code-push

1.安装react-native-code-push

在项目根目录运行

$ npm install react-native-code-push --save
2.cocoapods导入code-push
  • ios

修改Podfile文件,添加:

  pod 'CodePush', :path => './node_modules/react-native-code-push'

运行

  $ pod install
  • android

  • RNPM
    安装 RNPM(依次运行)
    如果 React Native 版本 >= 0.27 (因为 rnpm link 已经被合并到React Native CLI)

     $ react-native link react-native-code-push
    

否则
$ npm i -g rnpm
$ rnpm link react-native-code-push

  • 手动
    在android/settings.gradle文件里添加
    include ':app'
    include ':react-native-code-push'
    project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')
    在android/app/build.gradle文件里添加
    dependencies {
    ...
    compile project(':react-native-code-push')
    }
    在android/app/build.gradle文件里添加
    ...
    apply from: "../../node_modules/react-native/react.gradle"
    apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
    ...
    修改MainApplication.java文件
    ...
    // 1. Import the plugin class.
    import com.microsoft.codepush.react.CodePush;

     // public class MainActivity extends ReactActivity {                                     // For React Native v0.19 - v0.28
     public class MainApplication extends Application implements ReactApplication {        // For React Native >= 0.29
    
         private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
             ...
             // 2. Override the getJSBundleFile method in order to let
             // the CodePush runtime determine where to get the JS
             // bundle location from on each app start
             @Override protected String getJSBundleFile() {
                 return CodePush.getJSBundleFile();
             }
    
             @Override protected List<ReactPackage> getPackages() {
                 // 3. Instantiate an instance of the CodePush runtime and add it to the list of
                 // existing packages, specifying the right deployment key. If you don't already
                 // have it, you can run "code-push deployment ls <appName> -k" to retrieve your key.
                 return Arrays.<ReactPackage>asList(
                     new MainReactPackage(),
                     new CodePush("deployment-key-here", MainApplication.this, BuildConfig.DEBUG)
                 );
             }
         };
     }
    

在android/app/build.gradle文件中(应用版本codepush需要三位数)
android{
defaultConfig{
versionName "1.0.0"
}
}
Background React Instances
This section is only necessary if you're explicitly launching a React Native instance without an Activity
(for example, from within a native push notification receiver). For these situations, CodePush must be told how to find your React Native instance.*
In order to update/restart your React Native instance, CodePush must be configured with a ReactInstanceHolder
before attempting to restart an instance in the background. This is usually done in your Application
implementation.
修改MainApplication.java文件
// For React Native >= v0.29
...
// 1. Declare your ReactNativeHost to extend ReactInstanceHolder.
// ReactInstanceHolder is a subset of ReactNativeHost, so no additional implementation is needed.
import com.microsoft.codepush.react.ReactInstanceHolder;
public class MyReactNativeHost extends ReactNativeHost implements ReactInstanceHolder {
// ... usual overrides
}
// 2. Provide your ReactNativeHost to CodePush.
public class MainApplication extends Application implements ReactApplication {

        private final MyReactNativeHost mReactNativeHost = new MyReactNativeHost(this);

        @Override public void onCreate() {
            CodePush.setReactInstanceHolder(mReactNativeHost);
            super.onCreate();
        }
    }

    // For React Native v0.19 - v0.28
    // 1. Provide your ReactNativeHost to CodePush.
    public class MainApplication extends Application {
        // ... initialize your instance holder
        @Override public void onCreate() {
            CodePush.setReactInstanceHolder(mReactNativeHost);
            super.onCreate();
        }
    }

以上的操作,即可成功集成CodePush。

3.配置相关文件
  • IOS
1.修改js程序入口文件

RN应用是appDelegate.m
原生应用是ReactView.m

  #ifdef DEBUG
      jsCodeLocation = [NSURL URLWithString:@"http://192.168.1.103:8081/index.ios.bundle?platform=ios"];
  #else
      jsCodeLocation = [CodePush bundleURLForResource:@"index"];
  #endif
2.修改info.plist文件
  <key>CodePushDeploymentKey</key>
  <string>前面添加应用得到的发布key(注意这里要选择是正式版的key还是测试版的key,不是发布到appstore可以用Staging的key)</string>

命令行里面输入

$ code-push

可以看到code-push各个命令

三、更新策略(js)

1、导入react-native-code-push

import codePush from "react-native-code-push";

2、策略

默认情况下,CodePush会在app每次启动的时候去检测是否有更新,如果有,app会自动下载并在下次打开app时安装

class MyApp extends Component {}
MyApp = codePush(MyApp);

// For ES7
import codePush from "react-native-code-push";

@codePush
class MyApp extends Component {}

每次打开app时检测更新并下载,下次打开app时安装

// Sync for updates everytime the app resumes.
class MyApp extends Component {}
MyApp = codePush({
    checkFrequency: codePush.CheckFrequency.ON_APP_RESUME,
    installMode: codePush.InstallMode.ON_NEXT_RESUME
})(MyApp);

实时检测更新并下载,下载完成后立即安装

// Active update, which lets the end user know
// about each update, and displays it to them
// immediately after downloading it
class MyApp extends Component {}
MyApp = codePush({
    updateDialog: true,
    installMode: codePush.InstallMode.IMMEDIATE
})(MyApp);

记录app检测、下载、安装的状态(可以实现进度条当做友好提示)

// Make use of the event hooks to keep track of
// the different stages of the sync process.
class MyApp extends Component {
    codePushStatusDidChange(status) {
        switch(status) {
            case codePush.SyncStatus.CHECKING_FOR_UPDATE:
                console.log("Checking for updates.");
                break;
            case codePush.SyncStatus.DOWNLOADING_PACKAGE:
                console.log("Downloading package.");
                break;
            case codePush.SyncStatus.INSTALLING_UPDATE:
                console.log("Installing update.");
                break;
            case codePush.SyncStatus.UP_TO_DATE:
                console.log("Installing update.");
                break;
            case codePush.SyncStatus.UPDATE_INSTALLED:
                console.log("Update installed.");
                break;
        }
    }
    codePushDownloadDidProgress(progress) {
        console.log(progress.receivedBytes + " of " + progress.totalBytes + " received.");
    }
}
MyApp = codePush(MyApp);
CodePushOptions
  • checkFrequency (codePush.CheckFrequency) - 检测更新的时机
方法 描述
ON_APP_START(0) app启动后
ON_APP_RESUME(1) app从后台切换过来时
ON_APP_MANUAL(2) 不能自动检测,只有在调用 codePush.sync()时触发
  • deploymentKey (String) - 部署key,可以在js里动态修改
  • installMode (codePush.InstallMode) - 安装时机
方法 描述
IMMEDIATE(0) 立即安装并重启app
ON_NEXT_RESTART(1) 下次启动app时安装
ON_NEXT_RESUME(2) app从后台切换过来时安装
  • mandatoryInstallMode (codePush.InstallMode) - 同codePush.InstallMode.IMMEDIATE
  • minimumBackgroundDuration (Number) - app在后台切换过来安装的最小秒数,配合installMode.ON_NEXT_RESUME使用
  • updateDialog (UpdateDialogOptions) - 对话框
属性 描述
appendReleaseDescription(Boolean) 是否发送通知消息显示给用户,默认为false
descriptionPrefix(String) 描述的前缀,默认为“Description:”
mandatoryContinueButtonLabel(String) 强制更新下的继续按钮的文本,默认为“Continue”
mandatoryUpdateMessage(String) 强制更新的通知消息文本,默认为“An update is available that must be installed.”
optionalIgnoreButtonLabel(String) 忽略按钮的文本,默认为“Ignore”
optionalUpdateMessage(String) 通知消息文本,默认为“An update is available. Would you like to install it?”
title(String) 对话框的标题,默认为“Update available”
optionalUpdateMessage 通知消息文本

codePushStatusDidChange

用于监听检测、下载、安装的状态——SyncStatus

方法 描述
CHECKING_FOR_UPDATE (0) 查询更新
AWAITING_USER_ACTION (1) 有更新并且有对话框显示给最终用户(这只是适用updateDialog时使用)
DOWNLOADING_PACKAGE (2) 正在下载
INSTALLING_UPDATE (3) 正在安装
UP_TO_DATE (4) 更新完成
UPDATE_IGNORED (5) 提示更新后,用户选择了忽视(这只是适用updateDialog时使用)
UPDATE_INSTALLED (6) 已经安装,并将运行syncStatusChangedCallback函数返回后立即或下次启动更新,在InstallMode SyncOptions中指定。
SYNC_IN_PROGRESS (7) 有一个正在进行的同步操作运行,防止当前的调用被执行。
UNKNOWN_ERROR (-1) 同步操作遇到了一个未知错误。

codePushDownloadDidProgress

下载进度

返回参数 描述
totalBytes (number) 预计大小
receivedBytes(number) 已下载大小

disallowRestart/allowRestart

class OnboardingProcess extends Component {
  ...
  componentWillMount() {
    // Ensure that any CodePush updates which are
    // synchronized in the background can't trigger
    // a restart while this component is mounted. codePush.disallowRestart();
  }
  componentWillUnmount() {
    // Reallow restarts, and optionally trigger
    // a restart if one was currently pending.
    codePush.allowRestart();
  }
  ...
}

四、发布版本

1、打包
$ code-push release myProject ./bundle/index.jsbundle 1.20.1 --mandatory true

myProject代表我们要更新的项目名称,就是前面我们注册的index.jsbundle是我们要更新的内容,1.20.1是我们在appstore发布的版本号,注意这个地方是我们程序二进制文件的版本号,其实这句命令就是:更新myProject 1.20.1的版本二进制文件,只有1.20.1的版本才能收到更新。最后面的参数是是否强制更新。这段命令没有指定更新的环境是正式环境还是测试环境,默认的是测试环境,如果要发布到正式环境需要指定一下

 code-push release wanna ./bundle/index.jsbundle 1.20.1 -d "Production" --mandatory true。 

后面还可以在后面添加参数比如1.20.1版本的多少用户可以更新–rollout 20,代表百分之20的myProject 1.20.1的用户可以收到这个更新

2、修改发布后版本的参数

比如上面,我们发布更新到了1.20.1的测试版本,更新百分之20的用户,可是我们发布完成之后,想更新百分之30的用户:

$ code-push patch wanna 1.20.1 --rollout 20

code-push for redux -- react-native-code-push-saga

注意:

  • 苹果不允许应用内有弹框提示更新
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容