返回文章

CodePush 热更新配置及使用

1. 安装 CodePush :npm install g code push cli 2. 登陆:code push login 3. 注销:code push logout 4. ...

基本使用命令


  1. 安装 CodePush :npm install -g code-push-cli

  2. 登陆:code-push login

  3. 注销:code-push logout

  4. 添加项目:code-push app add [app名称]

  5. 删除项目:code-push app remove [app名称]

  6. 列出账号下的所有项目:code-push app list

  7. 打包命令:react-native bundle —platform 平台 —entry-file 启动文件 —bundle-output 打包js输出文件 —assets-dest 资源输出目录 —dev 是否调试

    注:

    此处的 --bundle-output--assets-dest 的路径建议使用同一路径,否则在使用 CodePush 进行更新版本后会出现本地资源文件加载不到的现象

  8. 发布更新命令:code-push release <应用名称> <Bundles所在目录> <对应的应用版本> —deploymentName 更新环境 —description 更新描述 —mandatory 是否强制更新

    注:

    1. 此处的 对应的应用版本app 对应的版本 否则不提示更新
    2. 此处的 Bundles所在目录 为 js 打包命令中对应的输出目录,即--bundle-output 后紧跟的路径
    3. 此处的 deploymentName 的默认值为 Staging ,若需更新 Staging 版本时可不填写,对应值为 StagingProduction
    4. 此处的 mandatory 为是否强制更新选项,对应值为 truefalse,设置为 false 时程序会在更新后在下次进入时显示新版本内容,若设置为 true 则会在更新后立即重启应用并显示新版本内容
  9. 修改更新:code-push patch [—label

    注:

    1. —label, -l 指定标签版本更新,默认最新版本 [string] [默认值: null]
    2. —description, —des 描述 [string] [默认值: null]
    3. —disabled, -x 是否禁用该更新 [boolean] [默认值: null]
    4. —mandatory, -m 是否强制更新 [boolean] [默认值: null]
    5. —rollout, -r 此更新推送用户的百分比,此值仅可以从先前的值增加。 [string] [默认值: null]
  10. 回滚更新:code-push rollback [—targetRelease ]

    注:

    —targetRelease, -r 指定回归到哪个标签,默认是回滚到上一个更新 [string] [默认值: null]

  11. 查看历史版本:code-push deployment history (Production 或者 Staging)

  12. 清除历史版本:code-push deployment clear

集成配置信息(android)


Js 部分配置

更新模式分为自动模式与手动模式两种

  • 自动模式 CodePush.sync()

CodePush.sync() 函数为 sync(options?: SyncOptions, syncStatusChangedCallback?: SyncStatusChangedCallback, downloadProgressCallback?: DowloadProgressCallback)

  1. SyncOptions 内包含有 deploymentKeyinstallModemandatoryInstallModeminimumBackgroundDurationupdateDialog 属性,此处属性的对应介绍可见其源码注释部分,很详细
  2. SyncStatusChangedCallback 为更新的状态回调方法,可通过添加此方法来监听更新的状态,如检查到更新、更新完成、更新失败等状态,对应代码为
codePushStatusDidChange(syncStatus) {
        switch(syncStatus) {
            case CodePush.SyncStatus.CHECKING_FOR_UPDATE:
                console.log("更新===检查更新中");
                break;
            case CodePush.SyncStatus.DOWNLOADING_PACKAGE:
                console.log("更新===下载更新包");
                break;
            case CodePush.SyncStatus.AWAITING_USER_ACTION:
                console.log("更新===检查到新版本,等待用户操作");
                break;
            case CodePush.SyncStatus.INSTALLING_UPDATE:
                console.log("更新===正在安装更新");
                break;
            case CodePush.SyncStatus.UP_TO_DATE:
                console.log("更新===已是最新版本");
                break;
            case CodePush.SyncStatus.UPDATE_IGNORED:
                console.log("更新===用户取消更新");
                break;
            case CodePush.SyncStatus.UPDATE_INSTALLED:
                console.log("更新===已安装更新,将在重新启动时应用");
                break;
            case CodePush.SyncStatus.UNKNOWN_ERROR:
                console.log("更新===发生了一个未知错误");
                break;
        }
    }
  1. DowloadProgressCallback 为更新下载进度的回调方法,可通过添加此方法监听下载的进度, 其属性值为 totalBytestotalBytes, 分别为更新包的总大小与当先下载进度

具体使用示例:

CodePush.sync(
        { 
            installMode: CodePush.InstallMode.ON_NEXT_RESTART,
            updateDialog: {
                appendReleaseDescription: true,
                descriptionPrefix:'更新内容:\n',
                title:'更新',
                mandatoryUpdateMessage:' ',
                mandatoryContinueButtonLabel:'更新',
            },
        },
        this.codePushStatusDidChange.bind(this),
        this.codePushDownloadDidProgress.bind(this)
    );
    
    // 也可以直接使用 CodePush.sync() 方法进行更新

注:

在程序的入口处需添加以下代码

let codePushOptions = { checkFrequency: CodePush.CheckFrequency.MANUAL };
<填写该类名> = CodePush(codePushOptions)(<填写该类名>);

AppRegistry.registerComponent('<填写此处为创建时的应用名>', () => <填写该类名>);

手动模式暂时未研究 具体 API 可参见官方文档

原生部分设置

  • build.gradle

此处分两种情况,一种为不需要改动 CodePush 原生代码; 另一种为需要改动 CodePush 的原生代码,此时如果该项目是插件类型的话还需要将改动后的 CodePush 的代码上传到私库,否则通过远程库的引用方式无法引用到该部分代码,若不使用远程库引用的话只需拷贝代码即可,此处需要注意的是其源码内 codepush.gradle 文件必须调用,否则打包后 CodePush 会因查找不到 CODE_PUSH_APK_BUILD_TIME 此字段而导致程序停止运行;若是该程序只是一个普通的项目的话则没有这些顾虑,尽管改就可以了

此处指的是 app 下面的 build.gradle

添加配置代码:

apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"

Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())

android {
    ...
    
    buildTypes {
        // 此处需注意CodePush不支持在DeBug模式下使用
        releaseStaging {
            ...
            buildConfigField "String", "CODEPUSH_KEY", '"'+properties.getProperty("code_push_key_staging")+'"'
            ...
        }

        releaseProduction {
            ...
            buildConfigField "String", "CODEPUSH_KEY", '"'+properties.getProperty("code_push_key_production")+'"'
            ...
        }
    }
    
}
  • local.properties

项目最外层该文件下添加一下两个属性值

code_push_key_production=该应用的 production 版本的Key
code_push_key_staging=该应用的 staging 版本的Key
  • MainApplication

public class MainApplication extends Application implements ReactApplication {
    
    
    private static final String code_push_key_production="zYDSBi96YCB7fISlK9wJTanpbcnFd4eb246d-c057-4aa7-8dfd-a6f32494bd71";
    private static final String code_push_key_staging="g5e_Ttrw183uWyZRuVP4VUzAXlTvd4eb246d-c057-4aa7-8dfd-a6f32494bd71";
    // 这两个值也可以通过读取 local.properties 文件获得
    
    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {

        @Override
        protected String getJSBundleFile() {
            return CodePush.getJSBundleFile();
        }

        @Override
        public boolean getUseDeveloperSupport() {
            return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
            return Arrays.<ReactPackage>asList(
                    new MainReactPackage(),
                    new CodePush(code_push_key_production, getApplicationContext())
            );
        }
    };

    @Override
    public ReactNativeHost getReactNativeHost() {
        return mReactNativeHost;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        SoLoader.init(this, /* native exopackage */ false);
    }
    
}

还有一种情况,那就是不定义 Application 的情况下使用,此时则可以在 MainActivity 中如下配置:

public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {

    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        CodePush codePush = new CodePush(code_push_key_production,this);
        mReactRootView = new ReactRootView(this);
        mReactInstanceManager = ReactInstanceManager.builder()
                .setApplication(getApplication())
                .setBundleAssetName("index.android.bundle")
                
                ...
                
                .setJSBundleFile(codePush.getJSBundleFile("index.android.bundle"))
                .addPackage(codePush)
                
                ...
                
                .setUseDeveloperSupport(true)
                .setInitialLifecycleState(LifecycleState.RESUMED)
                .build();


        mReactRootView.startReactApplication(mReactInstanceManager, "<对应RN中注册的名字>", null);
        setContentView(mReactRootView);

        mReactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() {
            @Override
            public void onReactContextInitialized(ReactContext context) {
                reactContext = context;
            }
        });
    }
    
    ...
    
}

至此大功告成。