ionic3热更新详细步骤

需要说明的是,ios已经申明禁止app中包含热更新插件。
2017年6月,AppStore审核团队针对AppStore中“热更新”的App开发者发送邮件,要求移除所有相关的代码、框架或SDK,并重新提交审核,否则就会在AppStore中下架该软件。

一、安装

npm install -g cordova-hot-code-push-cli
ionic cordova plugin add cordova-hot-code-push-plugin

网上还有教程建议安装本地测试插件,这里并没有使用。
ionic plugin add cordova-hot-code-push-local-dev-addon

二、配置config.xml

在widget闭合区域最底下,加上下面代码

<chcp>
    <native-interface version="1" />  # 你的app 的当前版本
    <auto-download enabled="false" />#默认是true,自动下载
    <auto-install enabled="true" />#默认是true,下载完成后自动安装,就是下载完成之后立即重新加载页面
    <config-file url="http://{你自己的服务器地址}/hotcode/chcp.json" /> #你服务器上面的地址
</chcp>

说明:
一般情况下,auto-downloadauto-install是设成false的,然后通过代码的方式调用,比如在设置功能中的检查更新,或者在应用启动后,如果有新的版本,给用户一个提示,是否安装新的更新(这个时候已经把改变的文件下载到本地了,插件会复制一份当前使用的 www 文件,然后把下载的增量文件复制到 www 中,然后把 webview 的地址指向这个新的)

三、项目根目录下新建两个文件:chcpbuild.options、cordova-hcp.json

chcpbuild.options

{
  "dev": {
    "config-file": "http://www.abc.com/eapp/www/chcp.json"
  },
  "production": {
    "config-file": "http://www.abc.com/eapp/www/chcp.json"
  },
  "QA": {
    "config-file": "http://www.abc.com/eapp/www/chcp.json"
  }
}

cordova-hcp.json

{
  "name": "App名字",
  "android_identifier":"",
  "ios_identifier": "",
  "min_native_interface": 1,//用于控制app的外壳版本;来判断当前app是直接下载web静态文件还是需要下载app进行外壳更新
  "update": "now",
// start(app启动的时候触发, 默认是start);resume(app从后台切换回来的时候触发);now (web内容下载完毕)
  "content_url": "http://www.abc.com/eapp/www"//配置你服务器的地址 用于后续 app触发更新时 和服务器上的文件进行比对 和下载更新用
}

四、生成热更新版本信息文件

corodva-hcp build

执行完上面命令,会在www目录下生成两个文件:chcp.json(当前版本信息)、chcp.manifest(当前版本,所有文件清单,每次更改文件执行完本命令,都会更新hash字符串)

{
  "name": "App名字",
  "android_identifier":"",
  "ios_identifier": "",
  "min_native_interface": 1,
  "update": "now",
  "content_url": "http://www.abc.com/eapp/www",
  "release":"2018.04.26-15.20.54"
}

如果仅改变release,则执行热更新;如果release、min_native_interface同时改变,则执行大版本更新。

五、将文件上传到服务器

http://www.abc.com/eapp/www
对应上面config.xml、cordova-hcp.json中的路径注:每次打包时,必须先执行cordova-hcp build,然后再执行打包命令,保证最终apk中热更新版本信息和www中一致

六、热更新web文件和自动检测版本,下载新版本安装

创建热更新服务,app-update.ts

import { Injectable } from '@angular/core';
import { AlertController, LoadingController } from 'ionic-angular';
import { File } from '@ionic-native/file';
import { FileOpener } from '@ionic-native/file-opener';
import { Platform } from 'ionic-angular';
declare var FileTransfer: any;
declare var cordova: any;
declare var chcp: any;
@Injectable()
export class AppUpdateProvider {
  public downloadProgress = 0;
  public LoadingProgress;
  constructor(private alertCtrl: AlertController, public fileOpener: FileOpener, public file: File, public plat: Platform, private loading: LoadingController) {
    this.bindEvents();
  }

  updateLoadFailed(eventData: any) {
    const error = eventData.detail.error;
    // 当检测出内核版本过小
    if (error && error.code == chcp.error.APPLICATION_BUILD_VERSION_TOO_LOW) {
      // iOS端 直接弹窗提示升级,点击ok后自动跳转
      if (this.plat.is('ios')) {
        chcp.requestApplicationUpdate("有新的版本,请下载更新", this.userWentToStoreCallback, this.userDeclinedRedirectCallback);
      } else if (this.plat.is('android')) {
        let alert = this.alertCtrl.create({
          title: '有新的版本,请下载更新',
          enableBackdropDismiss: false,
          // message: '发现新版本,是否下载新版本',
          buttons: [
            {
              text: '下次再说',
              role: 'cancel',
              handler: () => {
              }
            },
            {
              text: '立即升级',
              handler: () => {
                alert.dismiss().then(() => {
                  this.alertLoad();
                });
              }
            }
          ]
        });
        alert.present().then();
      }
    } else {
      // alert('是新版本');
    }
  }

  alertLoad() {
    this.LoadingProgress = this.loading.create({
      content: "正在下载:" + this.downloadProgress + "%"
    });
    this.LoadingProgress.present();
    this.downloadfile();
  }

  downloadfile() {
    //下载代码
    var fileTransfer = new FileTransfer();
    const fs: string = cordova.file.externalRootDirectory;
    this.file.createDir(fs, 'eschool', true).then((dir: any) => {
      fileTransfer.download("http://www.abc.com/eapp/apk/123.apk", dir.nativeURL + '123.apk', (entry) => {
        // 打开下载下来的APP
        this.fileOpener.open(entry.toURL(), 'application/vnd.android.package-archive')
          .then((data: any) => {
            // console.log('open file success');
          })
          .catch(err => {
            // console.log('open file error' + err);
            console.log('打开安装包失败!');
          });
      }, function (err) {
        console.log('下载失败');
        this.LoadingProgress.dismiss();
      }, true);
    }).catch(err => {
      console.log('创建目录失败');
      this.LoadingProgress.dismiss();
    });
    fileTransfer.onprogress = (progressEvent) => {
      this.downloadProgress = Math.floor((progressEvent.loaded / progressEvent.total) * 100);
    };
    let timer = window.setInterval(() => {
      // this.LoadingProgress.setContent("正在下载:" + this.downloadProgress + "%");
      window.setInterval(() => {
        let loadingcontent = this.LoadingProgress.pageRef().nativeElement.querySelector(".loading-content");
        loadingcontent.innerHTML = "正在下载:" + this.downloadProgress + "%"
      }, 300);
      if (this.downloadProgress > 99) {
        window.clearInterval(timer);
        this.LoadingProgress.dismiss();
      }
    }, 1000);
  }

  bindEvents() {
    console.log('----------进入更新模块---------');
    document.addEventListener('chcp_updateLoadFailed', (eventData: any) => {
      this.updateLoadFailed(eventData)
    }, false);

    document.addEventListener('deviceready', () => {
      chcp.fetchUpdate(this.fetchUpdateCallback);
    }, false);

    // //没有更新
    // document.addEventListener('chcp_nothingToUpdate', function (eventData) {
    //   alert('是新版本');
    // }, false);
    // /!*插件开始在外部存储上安装应用程序资产之前立即调度事件*!/
    // document.addEventListener('chcp_beforeAssetsInstalledOnExternalStorage', function (eventData) {
    //   alert('chcp_beforeAssetsInstalledOnExternalStorage');
    // }, false);
    // /!*插件无法拷贝app内置的web内容到外置存储中时触发. *!/
    // document.addEventListener('chcp_assetsInstallationError', function (eventData) {
    //   alert('chcp_assetsInstallationError');
    // }, false);
    // document.addEventListener('chcp_assetsInstalledOnExternalStorage', function (eventData) {
    //   alert('chcp_assetsInstalledOnExternalStorage');
    // }, false);
    // /!*web内容已经下载并可以安装时触发.*!/
    // document.addEventListener('chcp_updateIsReadyToInstall', function (eventData) {
    //   alert('chcp_updateIsReadyToInstall');
    // }, false);
    // document.addEventListener('chcp_beforeInstall', function (eventData) {
    //   alert('chcp_beforeInstall');
    // }, false);
    // document.addEventListener('chcp_updateInstallFailed', function (eventData) {
    //   alert('chcp_updateInstallFailed');
    // }, false);
    // document.addEventListener('chcp_updateInstalled', function (eventData) {
    //   alert('chcp_updateInstalled');
    // }, false);
    // document.addEventListener('chcp_nothingToInstall', function (eventData) {
    //   alert('chcp_nothingToInstall');
    // }, false);
  }

  //检测更新后的回调
  fetchUpdateCallback(error, data) {
    if (error) {
      // alert('Failed to load the update with error code: ' + error.code);
    } else {
      chcp.installUpdate(this.installationCallback);
    }
  }

  //安装后回调
  installationCallback(error) {
    if (error) {
      // alert('Failed to install the update with error code: ' + error.code);
    } else {
      // alert('Update installed!');
    }
  }

  userWentToStoreCallback() {
    //user went to the store from the dialog
  }
  userDeclinedRedirectCallback() {
    // User didn't want to leave the app.
    // Maybe he will update later.
  }
}

注意:下载过程不可以直接使用下面代码更新百分比,只能使用原生this.LoadingProgress.pageRef().nativeElement.querySelector获取dom后,操作dom内容,具体原因不清楚。亲测结果:
如果alertLoad()在addEventListener监听中被触发执行,则setContent无效;
如果不是在监听中被触发执行,则setContent有效;

this.LoadingProgress.setContent("正在下载:" + this.downloadProgress + "%");

app.component.ts中调用

//版本更新
new AppUpdateProvider(alertCtrl, fileOpener, file, platform, loading);

到这里就完工了。。。 。。。

(特别注意)

1、Android8以后 app自己下载的apk是需要用户信任;建议加上这个

<platform name="android">
        <config-file parent="/manifest" target="AndroidManifest.xml" xmlns:android="http://schemas.android.com/apk/res/android">
            <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
        </config-file>
</platform>

2、再就是apk自安装的时候会报错打不开
需要修改platform/android/mainfest.xml中修改uses-sdk的值,其中android:targetSdkVersion最大 值不能超过23,否则会出错.

<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
注:用到的插件清单
<plugin name="cordova-hot-code-push-plugin" spec="^1.5.3" />
<plugin name="cordova-plugin-file-opener2" spec="^2.1.4" />
<plugin name="cordova-plugin-file-transfer" spec="^1.7.1" />
<plugin name="cordova-plugin-device" spec="^2.0.2" />
注:用到的npm安装包清单
"cordova-hot-code-push-plugin": "^1.5.3",
"cordova-plugin-device": "^2.0.2",
"cordova-plugin-file": "^6.0.1",
"cordova-plugin-file-opener2": "^2.1.4",
"cordova-plugin-file-transfer": "^1.7.1",

测试过程,如果直接线上做测试,文件上传替换可能会有些麻烦,建议在手机设置代理,结合局域网站点host配置,做本地测试。
别忘了iis中mime添加类型:.json|application/x-javascript    .apk|application/vnd.android.package-archive手机端用域名访问局域网站点

可用事件chcp_updateIsReadyToInstall - web内容已经下载并可以安装时触发.chcp_updateLoadFailed - 插件无法下载web更新时触发. 详细错误信息在事件参数里.chcp_nothingToUpdate - 无可用更新下载时触发.chcp_updateInstalled - web内容安装成功时触发.chcp_updateInstallFailed - web内容安装失败时触发. 详细错误信息在事件参数里.chcp_nothingToInstall -无可用更新安装时触发.chcp_assetsInstalledOnExternalStorage - 插件成功把app内置的web内容拷贝到外置存储中时触发. 你可能需要开发调试时用到这个事件,也许不会.chcp_assetsInstallationError -插件无法拷贝app内置的web内容到外置存储中时触发. 如果此事件发生了 - 插件不再工作. 也许是设备没有足够的存储空间导致. 详细错误信息在事件参数里.

事件监听
document.addEventListener("chcp_updateLoadFailed",(event:any)={... ...},false);

参考文档ionic3 热更新 填坑过程【Ionic】Ionic实现iOS与Android端代码『热更新』与android升级下载功能 ( v1.3.x版本 )Cordova Hot Code Push插件实现自动更新App的Web内容

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT飞牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值