ionic热更新的实现以及引导用户下载新版应用功能实现和注意事项

来源:互联网 发布:java processbuilder 编辑:程序博客网 时间:2024/05/01 15:55

在app上线的第一个版本中,就需要加入热更新和外壳更新功能,这样才能尽可能避免损失用户,热更新无需新的apk,直接更新web项目,而外壳更新,通过给用户友好提示,引导用户下载最新版本。两者结合其实是一个功能,两者缺一不可。
建议通读全文之后,再进行实践。

热更新实现步骤

  • 全局安装cordova-hot-code-push-cli插件:$npm install -g cordova-hot-code-push-cli

  • 在项目根目录下安装cordova-hot-code-push-plugin插件:$cordova plugin add cordova-hot-code-push-plugin

  • 在项目根目录下执行 $cordova-hcp server , 然后ctrl / command + z 结束服务器,我们不使用它的服务器来测试。只为了使用它生成的一个配置文件,名为:.chcpenv

  • 好的,我们现在可以开启一个本地服务器,随便找一个地方新建一个文件夹,然后在文件夹根目录下执行 $hs -o -p 1111, (备注,hs命令是全局安装了http-server之后才能使用,$npm i -g http-server), 这样我们可以通过访问 http://127.0.0.1:1111 来访问我们这个本地服务器了。我们在目录中建立几个文件夹目录结构如下:

    /update/hot/app1/update/hot/app2/update/apks

    说明,app1是你的一个项目用于放置热更新代码的文件夹,而app2则是另一个项目的文件夹,这里假设我们有很多个移动应用项目,而apks文件夹则用于放置我们所有应用的新版apk。(备注:这里的app1和下面用到的app1.apk都只做示例。)

  • 查看电脑ip地址,mac上使用ifconfig命令, windows上使用ipconfig命令,找到我们的电脑ip地址,比如是192.168.1.102, 此处 192.168.1.102127.0.0.1是等同的,但为了手机可访问必须使用192的地址。(手机和电脑需保持在同一个网段上)

  • 开始修改上面的.chcpenv文件,编辑如下:

    {  "content_url": "http://192.168.1.102:1111/update/hot/app1",  "config_url": "http://192.168.1.102:1111/update/hot/app1/chcp.json"}

    说明: 其中app1文件夹里的代码就是你将要放置的热更新后的代码,也就是我们本地项目中的www目录的代码,同样的,www目录中存在chcp.json文件,这个我们即将说道。

  • 我们在项目中新建一个cordova-hcp.json文件,这个文件是生成配置文件的模板,编辑如下:

    {    "autogenerated": true,    "content_url": "http://192.168.1.102:1111/update/hot/app1",    "min_native_interface": 1,    "update": "now",    "ios_identifier": ""}
  • 在项目根目录执行$cordova-hcp build, 这样就会按照上一步的cordova-hcp.json文件为模板在www目录中生成两个文件,chcp.json 和 chcp.manifest 两个文件。chcp.json 文件内容如下:

    {  "autogenerated": true,  "content_url": "http://192.168.1.102:1111/update/hot/app1",  "min_native_interface": 1,  "update": "now",  "ios_identifier": "",  "release": "2017.07.10-22.18.08"}

    chcp.json 文件就是按照上面cordova-hcp.json模板生成的。
    里面的字段分别都有意义的,我们在这里做下说明:
    ①. autogenerated 表示是否自动生成的配置
    ②. content_url 表示我们线上热更代码的文件目录
    ③. min_native_interface 表示目前外壳的最小版本号
    ④. update有三个值,分别是 :

    start - app启动时安装更新,默认值resume - app从后台切换过来的时候安装更新now - web内容下载完毕即安装更新

    ⑤. ios_identifier 则是ios在appStore的应用标识
    ⑥. release 则是build时的时间戳,用于对比更新时间

    chcp.manifest文件则是www项目中的每一个文件打下一个hash印记,如下:

    [  {    "file": "css/style.css",    "hash": "84a33cf00d95bc1e3617cc35262f7e94"  },  {    "file": "img/adam.jpg",    "hash": "b445da3cc203f97bce534fdad93b3931"  },  ...]

    用以区分改动的文件,通过对比不同hash值而拉下不同的文件,用以热更新。

  • 修改项目根目录中的config.xml文件,添加如下代码:

    <chcp> <native-interface version="1" /> <config-file url="http://192.168.1.102:1111/update/hot/app1/chcp.json" /></chcp>
  • 目前配置已经完成,开始打包一个新的apk安装到手机,然后修改我们的源码文件,用于标识改动,再次重新运行命令$cordova-hcp build, 将新生成的www目录中的代码放到http://192.168.1.102:1111/update/hot/app1,
    我们退出应用,重新打开后,就会出现闪一下的效果,然后就会看到修改后的代码。这就是热更新。(备注:确保手机和电脑在同一网段访问,使用192.168.1.102只是先作为测试使用)

外壳更新实现步骤

  • 为什么要进行外壳更新,比如我们新功能需要加入一些新的cordova插件,而这些插件是内置于apk中的,并非基于www目录,不能进行热更新,新的基于cordova插件的应用逻辑不能被用于旧的apk上,如果强制更新,则会
    出现严重的错误,所以我们需要引导用户下载新的apk或引导用户进入appStore更新应用。

  • 安装必要的cordova插件,如下:

    • $cordova plugin add cordova-hot-code-push-plugin
    • $cordova plugin add cordova-plugin-file-opener2
    • $cordova plugin add cordova-plugin-file-transfer
    • 备注:cordova-plugin-file-transfer安装的过程中会同时安装cordova-plugin-file插件
  • 原理说明:通过min_native_interface属性的设置,如果插件检查发现用户安装的外壳app版本比服务端新的web内容要求的版本要低,就会触发错误事件,错误码:chcp.error.APPLICATION_BUILD_VERSION_TOO_LOW 通过这个错误码可通过弹窗提示用户去升级,跳转到AppStore或下载新安装包

  • 编写引导用户更新,下载逻辑,作为一项服务,包含引导提示界面,和下载功能。

      .factory('setHotPush', [      '$ionicPopup',      '$ionicLoading',      '$timeout',      'setUtils',      function($ionicPopup, $ionicLoading, $timeout, setUtils) {          var AppUpdate = function() {};          AppUpdate.prototype = {              // Application Constructor              initialize: function() {                  this.bindEvents();              },              // Bind any events that are required.              // Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modules              bindEvents: function() {                  document.addEventListener('chcp_updateLoadFailed', this.onUpdateLoadError, false);              },              onUpdateLoadError: function(eventData) {                  var error = eventData.detail.error;                  // 当检测出内核版本过小                  if (error && error.code === chcp.error.APPLICATION_BUILD_VERSION_TOO_LOW) {                      var dialogMessage = '有新的版本,请下载更新!';                      // iOS端 直接弹窗提示升级,点击ok后自动跳转                      if (ionic.Platform.isIOS()) {                          chcp.requestApplicationUpdate(dialogMessage, this.userWentToStoreCallback, this.userDeclinedRedirectCallback);                          // Android端 提示升级下载最新APK文件                      } else if (ionic.Platform.isAndroid()) {                          var confirmPopup = $ionicPopup.confirm({                              title: '版本更新',                              template: '<span class="updatePopup">' + dialogMessage + '</span>',                              cssClass: 'popup',                              cancelText: '取消',                              okText: '<span class="ionicPopupUpdateBtn">' + '升级' + '</span>'                          });                          confirmPopup.then(function(res) {                              if (res) {                                  $ionicLoading.show({                                      template: "已经下载:0%"                                  });                                  window.resolveLocalFileSystemURL(cordova.file.externalRootDirectory, function(fileEntry) {                                      fileEntry.getDirectory("com.xxx.app1", {                                          create: true,                                          exclusive: false                                      }, function(fileEntry) {                                          //下载代码                                          var fileTransfer = new FileTransfer();                                          fileTransfer.download("http://192.168.1.102:1111/update/hot/app1/app1.apk", fileEntry.toInternalURL() + "app1.apk", function(entry) {                                              // 打开下载下来的APP                                              cordova.plugins.fileOpener2.open(                                                  entry.toInternalURL(), //下载文件保存地址                                                  'application/vnd.android.package-archive', { //以APK文件方式打开                                                      error: function(err) {                                                          setUtils.tips('下载失败!', 1);                                                      },                                                      success: function() {                                                          setUtils.tips('下载成功,请安装后重新打开应用!', 1);                                                      }                                                  });                                          }, function(err) {}, true);                                          fileTransfer.onprogress = function(progressEvent) {                                              $timeout(function() {                                                  var downloadProgress = (progressEvent.loaded / progressEvent.total) * 100;                                                  $ionicLoading.show({                                                      template: "已经下载:" + Math.floor(downloadProgress) + "%"                                                  });                                                  if (downloadProgress > 99) {                                                      $ionicLoading.hide();                                                  }                                              });                                          };                                      }, function(err) {                                          setUtils.tips("创建目录失败原因:" + err, 1)                                      });                                  });                              }                          });                      }                  }              },              userWentToStoreCallback: function() {                  // user went to the store from the dialog              },              userDeclinedRedirectCallback: function() {                  // User didn't want to leave the app.                  // Maybe he will update later.              }          };          return new AppUpdate();      }  ]);

    说明,其中setUtils是自己实现的一些通用的函数封装,setUtils.tips则是封装了$cordovaToast服务的提示功能,可自己进行实现。下载文件夹的创建目录com.xxx.app1可以用公司名称的倒序然后加上apk的名称,也可自定义。上文中还加入了一些自定义的样式用于修改提示组件。

  • 将此项服务在应用run方法中注入,并调用上面的initialize方法,下面我们来开始测试。

  • 执行cordova-hcp build 命令,然后安装应用到手机,此处作为原始apk。

  • 修改项目根目录下的cordova-hcp.json文件中的min_native_interface属性,其值加1。

  • 修改项目根目录下的config.xml文件中,找到native-interface标记,其属性version值加1。

  • 修改项目源码,做个标记,然后再次执行cordova-hcp build 命令, 将新的www目录源码更新到http://192.168.1.102:1111/update/hot/app1 目录中,打包新的apk,放到http://192.168.1.102:1111/update/apks中。

  • 打开旧的应用,就会出现提示信息,确认下载,则会走进度条,下载完成则会提示您安装,安装好之后,则更新完毕。

更换线上服务器和安全问题

  • 将上述步骤中的所有192.168.1.102的相关配置替换成自己的服务器地址,请注意访问目录。

  • 热更新和外壳更新是同一项功能,打包apk之前确保两者都可用。

  • 设置服务器访问权限,目录可访问,但替换和删除则需要密码,以确保安全。

  • 在此用linux服务器举例,在更新www目录中的源码时需要删除之前的代码, 在服务端上的相应目录执行rm -rf * 删除服务器上热更新上的所有文件。

  • 然后在上传新的热更新代码, 本地cd到www目录,然后执行scp -r * hot@xxx.xxx.xxx.xxx:update/hot/app1 此处只是作为举例,hot是你服务器上的用户名,xxx.xxx.xxx.xxx代表服务器ip,使用该命令将所有新的代码部署到服务端。

注意事项

  • 在上述测试时,请保持手机和电脑保持在同一网段,确保可访问。

  • 命令cordova-hcp build可以在自定义目录中生成配置文件,如cordova-hcp build www 也可用其他目录,但没有必要,我们使用的就是www目录。

  • 注意开发环境和生产环境的区别,注意src和www的不同,注意结合构建过程。

  • 项目中没有用到 cordova-hot-code-push-local-dev-addon 测试插件,这个只作为测试使用,实际上没有什么价值。

不足之处

  • 在热更新的时候,闪一下之后,原来基于cookie的存储全部被删除,一些数据的存储尽量不要使用cookie,可以使用PouchDBSQLite
  • 在项目运行时安装新的apk,没有重新打开,而是退出了,需要手动重新打开应用,这时候会看到新的内容被更新了。

目前环境

在项目根目录下执行$ ionic info 之后

 global packages:     @ionic/cli-plugin-proxy : 1.3.1     @ionic/cli-utils        : 1.4.0     Gulp CLI                : CLI version 3.9.1 Local version 3.9.1     Ionic CLI               : 3.4.0 local packages:     @ionic/cli-plugin-gulp   : 1.0.1     @ionic/cli-plugin-ionic1 : 2.0.0     Ionic Framework          : 1.3.2 System:     Node       : v7.2.1     OS         : OS X El Capitan     Xcode      : Xcode 8.2.1 Build version 8C1002     ios-deploy : 1.8.6     ios-sim    : 5.0.8     npm        : 4.3.0

参考博客

  • http://blog.csdn.net/hu764525403/article/details/53085280
  • http://kaibin.me/2016/07/17/ionic-hotcode/
  • 这两篇博客较旧,并没有针对 .chcpenv 的配置,而本文也只针对现在的环境来写的,因为版本不同,所以仅供参考。

官方文档参考

  • https://github.com/nordnet/cordova-hot-code-push
  • https://github.com/nordnet/cordova-hot-code-push/wiki/Fetch-update
  • https://github.com/nordnet/cordova-hot-code-push/wiki/Application-config
  • https://github.com/nordnet/cordova-hot-code-push/wiki/Local-Development-Plugin
  • https://github.com/nordnet/cordova-hot-code-push/issues/223
阅读全文
0 0
原创粉丝点击