ionic3熱更新詳細(xì)步驟

需要說明的是淤年,ios已經(jīng)申明禁止app中包含熱更新插件。
2017年6月葵擎,AppStore審核團(tuán)隊(duì)針對(duì)AppStore中“熱更新”的App開發(fā)者發(fā)送郵件谅阿,要求移除所有相關(guān)的代碼、框架或SDK酬滤,并重新提交審核签餐,否則就會(huì)在AppStore中下架該軟件。

一盯串、安裝

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

網(wǎng)上還有教程建議安裝本地測(cè)試插件氯檐,這里并沒有使用。
ionic plugin add cordova-hot-code-push-local-dev-addon

二体捏、配置config.xml

在widget閉合區(qū)域最底下冠摄,加上下面代碼

<chcp>
    <native-interface version="1" />  # 你的app 的當(dāng)前版本
    <auto-download enabled="false" />#默認(rèn)是true,自動(dòng)下載
    <auto-install enabled="true" />#默認(rèn)是true几缭,下載完成后自動(dòng)安裝,就是下載完成之后立即重新加載頁(yè)面
    <config-file url="http://{你自己的服務(wù)器地址}/hotcode/chcp.json" /> #你服務(wù)器上面的地址
</chcp>

說明:
一般情況下河泳,auto-downloadauto-install是設(shè)成false的,然后通過代碼的方式調(diào)用年栓,比如在設(shè)置功能中的檢查更新拆挥,或者在應(yīng)用啟動(dòng)后,如果有新的版本某抓,給用戶一個(gè)提示纸兔,是否安裝新的更新(這個(gè)時(shí)候已經(jīng)把改變的文件下載到本地了惰瓜,插件會(huì)復(fù)制一份當(dāng)前使用的 www 文件,然后把下載的增量文件復(fù)制到 www 中汉矿,然后把 webview 的地址指向這個(gè)新的)

三崎坊、項(xiàng)目根目錄下新建兩個(gè)文件: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的外殼版本负甸;來(lái)判斷當(dāng)前app是直接下載web靜態(tài)文件還是需要下載app進(jìn)行外殼更新
  "update": "now",
// start(app啟動(dòng)的時(shí)候觸發(fā)流强, 默認(rèn)是start);resume(app從后臺(tái)切換回來(lái)的時(shí)候觸發(fā))呻待;now (web內(nèi)容下載完畢)
  "content_url": "http://www.abc.com/eapp/www"http://配置你服務(wù)器的地址 用于后續(xù) app觸發(fā)更新時(shí) 和服務(wù)器上的文件進(jìn)行比對(duì) 和下載更新用
}

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

corodva-hcp build

執(zhí)行完上面命令队腐,會(huì)在www目錄下生成兩個(gè)文件:chcp.json(當(dāng)前版本信息)蚕捉、chcp.manifest(當(dāng)前版本,所有文件清單柴淘,每次更改文件執(zhí)行完本命令迫淹,都會(huì)更新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,則執(zhí)行熱更新为严;如果release敛熬、min_native_interface同時(shí)改變,則執(zhí)行大版本更新第股。

五应民、將文件上傳到服務(wù)器

http://www.abc.com/eapp/www
對(duì)應(yīng)上面config.xml、cordova-hcp.json中的路徑
注:每次打包時(shí)夕吻,必須先執(zhí)行cordova-hcp build诲锹,然后再執(zhí)行打包命令,保證最終apk中熱更新版本信息和www中一致

六涉馅、熱更新web文件和自動(dòng)檢測(cè)版本归园,下載新版本安裝

創(chuàng)建熱更新服務(wù),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;
    // 當(dāng)檢測(cè)出內(nèi)核版本過小
    if (error && error.code == chcp.error.APPLICATION_BUILD_VERSION_TOO_LOW) {
      // iOS端 直接彈窗提示升級(jí)稚矿,點(diǎn)擊ok后自動(dòng)跳轉(zhuǎn)
      if (this.plat.is('ios')) {
        chcp.requestApplicationUpdate("有新的版本,請(qǐng)下載更新", this.userWentToStoreCallback, this.userDeclinedRedirectCallback);
      } else if (this.plat.is('android')) {
        let alert = this.alertCtrl.create({
          title: '有新的版本,請(qǐng)下載更新',
          enableBackdropDismiss: false,
          // message: '發(fā)現(xiàn)新版本,是否下載新版本',
          buttons: [
            {
              text: '下次再說',
              role: 'cancel',
              handler: () => {
              }
            },
            {
              text: '立即升級(jí)',
              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) => {
        // 打開下載下來(lái)的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('創(chuàng)建目錄失敗');
      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('----------進(jìn)入更新模塊---------');
    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);
    // /!*插件開始在外部存儲(chǔ)上安裝應(yīng)用程序資產(chǎn)之前立即調(diào)度事件*!/
    // document.addEventListener('chcp_beforeAssetsInstalledOnExternalStorage', function (eventData) {
    //   alert('chcp_beforeAssetsInstalledOnExternalStorage');
    // }, false);
    // /!*插件無(wú)法拷貝app內(nèi)置的web內(nèi)容到外置存儲(chǔ)中時(shí)觸發(fā). *!/
    // document.addEventListener('chcp_assetsInstallationError', function (eventData) {
    //   alert('chcp_assetsInstallationError');
    // }, false);
    // document.addEventListener('chcp_assetsInstalledOnExternalStorage', function (eventData) {
    //   alert('chcp_assetsInstalledOnExternalStorage');
    // }, false);
    // /!*web內(nèi)容已經(jīng)下載并可以安裝時(shí)觸發(fā).*!/
    // 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);
  }

  //檢測(cè)更新后的回調(diào)
  fetchUpdateCallback(error, data) {
    if (error) {
      // alert('Failed to load the update with error code: ' + error.code);
    } else {
      chcp.installUpdate(this.installationCallback);
    }
  }

  //安裝后回調(diào)
  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內(nèi)容,具體原因不清楚碉渡。
親測(cè)結(jié)果:
如果alertLoad()在addEventListener監(jiān)聽中被觸發(fā)執(zhí)行聚谁,則setContent無(wú)效;
如果不是在監(jiān)聽中被觸發(fā)執(zhí)行滞诺,則setContent有效形导;

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

app.component.ts中調(diào)用

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

到這里就完工了环疼。。朵耕。 炫隶。。阎曹。

(特別注意)

1伪阶、Android8以后 app自己下載的apk是需要用戶信任;建議加上這個(gè)

<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自安裝的時(shí)候會(huì)報(bào)錯(cuò)打不開
需要修改platform/android/mainfest.xml中修改uses-sdk的值,其中android:targetSdkVersion最大 值不能超過23,否則會(huì)出錯(cuò).

<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",

測(cè)試過程栅贴,如果直接線上做測(cè)試,文件上傳替換可能會(huì)有些麻煩熏迹,建議在手機(jī)設(shè)置代理檐薯,結(jié)合局域網(wǎng)站點(diǎn)host配置,做本地測(cè)試注暗。
別忘了iis中mime添加類型:.json|application/x-javascript ?? .apk|application/vnd.android.package-archive
手機(jī)端用域名訪問局域網(wǎng)站點(diǎn)

可用事件
chcp_updateIsReadyToInstall - web內(nèi)容已經(jīng)下載并可以安裝時(shí)觸發(fā).
chcp_updateLoadFailed - 插件無(wú)法下載web更新時(shí)觸發(fā). 詳細(xì)錯(cuò)誤信息在事件參數(shù)里.
chcp_nothingToUpdate - 無(wú)可用更新下載時(shí)觸發(fā).
chcp_updateInstalled - web內(nèi)容安裝成功時(shí)觸發(fā).
chcp_updateInstallFailed - web內(nèi)容安裝失敗時(shí)觸發(fā). 詳細(xì)錯(cuò)誤信息在事件參數(shù)里.
chcp_nothingToInstall -無(wú)可用更新安裝時(shí)觸發(fā).
chcp_assetsInstalledOnExternalStorage - 插件成功把a(bǔ)pp內(nèi)置的web內(nèi)容拷貝到外置存儲(chǔ)中時(shí)觸發(fā). 你可能需要開發(fā)調(diào)試時(shí)用到這個(gè)事件坛缕,也許不會(huì).
chcp_assetsInstallationError -插件無(wú)法拷貝app內(nèi)置的web內(nèi)容到外置存儲(chǔ)中時(shí)觸發(fā). 如果此事件發(fā)生了 - 插件不再工作. 也許是設(shè)備沒有足夠的存儲(chǔ)空間導(dǎo)致. 詳細(xì)錯(cuò)誤信息在事件參數(shù)里.

事件監(jiān)聽
document.addEventListener("chcp_updateLoadFailed",(event:any)={... ...},false);

參考文檔
ionic3 熱更新 填坑過程
【Ionic】Ionic實(shí)現(xiàn)iOS與Android端代碼『熱更新』與android升級(jí)下載功能 ( v1.3.x版本 )
Cordova Hot Code Push插件實(shí)現(xiàn)自動(dòng)更新App的Web內(nèi)容

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市捆昏,隨后出現(xiàn)的幾起案子赚楚,更是在濱河造成了極大的恐慌,老刑警劉巖骗卜,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宠页,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡膨俐,警方通過查閱死者的電腦和手機(jī)勇皇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)焚刺,“玉大人敛摘,你說我怎么就攤上這事∪橛洌” “怎么了兄淫?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蔓姚。 經(jīng)常有香客問我捕虽,道長(zhǎng),這世上最難降的妖魔是什么坡脐? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任泄私,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘晌端。我一直安慰自己捅暴,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布咧纠。 她就那樣靜靜地躺著蓬痒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪漆羔。 梳的紋絲不亂的頭發(fā)上梧奢,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音演痒,去河邊找鬼亲轨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鸟顺,可吹牛的內(nèi)容都是我干的瓶埋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼诊沪,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了曾撤?” 一聲冷哼從身側(cè)響起端姚,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎挤悉,沒想到半個(gè)月后渐裸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡装悲,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年昏鹃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诀诊。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洞渤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出属瓣,到底是詐尸還是另有隱情载迄,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布抡蛙,位于F島的核電站护昧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏粗截。R本人自食惡果不足惜惋耙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绽榛,春花似錦湿酸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至冲粤,卻和暖如春美莫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背梯捕。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工厢呵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人傀顾。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓襟铭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親短曾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子寒砖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容