APP 版本更新方法

作为 APP 开发者,都会碰到 APP 更新,即在 APP 发布之后,由于增加功能,优化体验,修复 Bug 等情况需要不断更新版本,除非这个项目不再维护(基本上很少出现这种情况); 为了给用户提供最好的体验, 往往希望新版本上架后所有的用户都能以最快的速度体验到最新的版本,这就涉及到 APP 版本更新通知。



APP 版本更新大致分为四大类:

  • APP 静默升级(通过手机自带的应用商店实现)
  • APP 通过检查平台或商店的新版本并跳到应用商店中去升级
  • APP 通过第三方平台实现版本检测与更新(如:百度、友盟、应用宝的版本检测与更新)
  • APP 和服务器联合实现版本检测测与更新(自己实现版本更新)方案

当然,不同的平台会有所不同,如 Androd & iOS 的实现方式会存在一些差异。


一、APP 静默升级(通过手机自带的应用商店实现)

Android:

iOS:


APP 静默升级,即只要 APP 新版本审核通过,在手机自带的应用商店中,就会有红点标记。通过设置,即可实现 APP 静默升级。这种方式,APP 中不需要做任何处理,靠应用商店自己的自动更新机制更新,这个是苹果提倡的升级机制,但是不管是 Android 还是 iOS,几乎都不采用。

二、APP 通过检查平台或商店的新版本并跳到应用商店中去升级

Android:



iOS:



注意: 苹果审核时是不允许 APP 内有任何提示版本更新的内容, 否则会拒绝上架

2.1 iOS 平台

在 APP 启动的时候比较 APP Store 中版本的版本号与本地 APP 的版本号的大小,如果 APP Store 中的版本号大于本地 APP 版本号,提示版本更新,否则不提示版本更新; 由于开发完一个新版本,会修改一个版本号,提交苹果审核的时候,版本号一定是大于 APP Store 中的版本号的,所以苹果的审核人员在审核时是不会看到版本更新提示的,而一旦上架成功,由于 APP Store 中最新的版本号大于用户已安装的版本的版本号,自然就看得到版本更新提示,用户可以直接点击立即更新,然后直接跳转到 APP Store 中此 APP 的详情页面,点击更新就可以了。

2.2 Android 平台

在用户启动 APP 或者进入主菜单界面,读取私有云上自定义的 APP 版本版号(版本审核通过后要手动修改私有云的版本号配置),云服务返回的结果中包含版本号及更新信息,APP 需要比较云端配置的 APP 版本号与本地 APP 的版本号的大小,若是本地 APP 的版本号比较小,则一般立刻弹出提示模态对话框让用户选择操作。

若是要求强制升级,则只能跳转到 私有云返回的新版本链接(某应用商店中的应用地址)中去下载,只有两版本号一致,方可进入 APP 主界面或进行操作。
若是非强制升级,则可以取消升级提示框,用户要是想升级,则跳转到 私有云返回的新版本链接(某应用商店中的应用地址)中去下载。

详细步骤:

  • 请求后台数据,根据返回版本号对比判断应用是否需要进行更新操作

  • 若不需要,跳转到登录或应用主界面,若需要进行弹框,让用户选择是否进行更新操作

  • 若用户选择取消更新,则跳转到登录或应用主界面

  • 若用户选择更新,则判断手机内是否安装需要进入的应用市场 APP

  • 如果已安装,那么根据包名直接进入应用市场的详情页面下载 APK

  • 如果未安装,那么根据后台返回的地址,用浏览器打开进行下载

这种方式只需要在 APP 及私有云上做些简单的配置或修改就可以实现,不用考虑 APP 文件的存放及并发下载的负载。


以下两种方式只针对 Android 平台(虽然 iOS 的企业包也可以做到,测试阶段时可以,但所有的 APP 最终还是需要提交上架审核)

三、APP 通过第三方平台实现版本检测与更新(如:百度、友盟、应用宝的版本检测与更新)




第三方平台实现版本检测与更新 应该算为 PUSH 信息版本更新,属于运行时版本更新(通常只包括强制更新)的一种,当用户在使用时,应用有新版本上架(准确的说是服务器数据库中对应应用版本号更新),平台就会推送更新消息。

以 百度平台 为例:

3.1 APP 新版本需要在 百度移动开发平台 进行注册,创建应用,提交应用,过百度的审核

3.2 导入 百度升级 SDK

在 project 下的 build.gradle 文件中:

    //导入智能更新SDK 的AAR 文件
    implementation(name: 'autoupdatesdk-release', ext: 'aar')

3.3 配置 AndroidManifest

在 AndroidManifest.xml 中添加如下字段

    <meta-data
        android:name="BDAPPID"
        android:value="11397**"/>
    <meta-data
        android:name="BDAPPKEY"
        android:value="K6pP2cRMAlRTvXC2TbNedbmMBpZ8****"/>

3.4 编写更新方法

注册 百度升级 回调

    private void checkUpdata() {
        if (AppUtil.isNetworkConnected()) {// by xmamiga
            logShow("UPDATE_IS_UPDATE: " + CGenieApplication.getInstance().isUPDATE_IS_UPDATE());
            if (CGenieApplication.getInstance().isUPDATE_IS_UPDATE()) {
                BDAutoUpdateSDK.cpUpdateCheck(this, new MyCPCheckUpdateCallback());
                CGenieApplication.getInstance().setUPDATE_IS_UPDATE(false);
            }
        } else {
            logShow("isNetworkConnected is null");
        }
    }

编写 百度升级 回调

   private class MyCPCheckUpdateCallback implements CPCheckUpdateCallback {

        @Override
        public void onCheckUpdateCallback(AppUpdateInfo arg0, AppUpdateInfoForInstall arg1) {
            if (arg0 != null) {
                logShow("arg0.getAppVersionName(): " + arg0.getAppVersionName());
                logShow("AppUtil.getVersion(): " + AppUtil.getVersion());
            } else {
                logShow("AppUpdateInfo is null");
            }
            if (!arg0.getAppVersionName().equals(AppUtil.getVersion())) {
                appUpdateInfo = arg0;
                Intent it = new Intent(MainActivity.this,
                        UpdateDialogActivity.class);
                it.putExtra(Constants.INTENT_UPDATE_INFO, appUpdateInfo);
                startActivity(it);
                CGenieApplication.getInstance().setAPKUpdate(true);
            }
        }
    }

如果 APP Store 中的版本号大于本地 APP 版本号,提示版本更新,否则不提示版本更新;

如果本地 APP 版本号小于 百度升级SDK 返回的版本号,则提示更新,下载文件。

下载文件(百度升级SDK)

private class MyCPUpdateDownloadCallback implements
            CPUpdateDownloadCallback {

        @Override
        public void onDownloadComplete(String arg0) {
            apkPath = arg0;
        }

        @Override
        public void onFail(Throwable arg0, String arg1) {
            ToastUI.showShort(R.string.update_load_fail);
        }

        @Override
        public void onPercent(int arg0, long arg1, long arg2) {
            pb_progress.setProgress(arg0);
            mTv_percent.setText(getString(R.string.download_percent)+arg0+"%");
            Log.e("baidu", arg0 + "");
        }

        @Override
        public void onStart() {

        }

        @Override
        public void onStop() {
            // TODO Auto-generated method stub
            tv_title.setVisibility(View.GONE);
            mTv_progress_title.setText(R.string.tip_downloaded);
            mLl_progress.setVisibility(View.VISIBLE);
            tv_size.setVisibility(View.VISIBLE);
            viewLine.setVisibility(View.VISIBLE);
            lay_btn.setVisibility(View.VISIBLE);
            tv_cancel.setText(R.string.cancel);
            tv_done.setText(R.string.tip_install);
            isFinish = true;
            installApk();
        }

    }

APP 开发者不需要考虑并发及负载问题,背靠大树。

四、APP 和服务器联合实现多版本检测测与更新(自己实现版本更新)方案

开发商自已实现 APP 的版本更新,本质上 跟第三方推送差不多,区别在于 APP 自已要去服务端(开发者自已部署服务器或FTP服务器)读取版本信息,然后作比较,当判断有新版本的时候,需要自已写 APK 下载,然后安装。

云端配置信息:

      {
        "project": "CHome",
        "versionCode": "45",
        "versionName": "1.4.5",
        "file": "/CHome/CHome_V1.4.5_03281521.apk",
        "description": "优化UI",
        "md5":"3a3c04661be71008c8c84cda70cb2deb"
      },

这种方式需要开发者考虑下载时并发请求,若是用户量大的时候,服务器负载是否能够撑得住,否则就得升级服务器。