1. 程式人生 > >ionic4.0 詳細熱更新 自動模式以及手動模式--秒殺網上一切熱更新因為網上沒有手動更新的詳細程式碼 測試無誤上線釋出了的東西.

ionic4.0 詳細熱更新 自動模式以及手動模式--秒殺網上一切熱更新因為網上沒有手動更新的詳細程式碼 測試無誤上線釋出了的東西.

ionic4.0 詳細熱更新 自動模式以及手動模式(全)–純手打,獨一無二,絕對好用.

網上一大堆ionic 熱更新,但是都是說的最基本的自動更新操作,安裝幾個外掛,改幾個配置檔案,就草草了事,讓我真的很煩躁,通過自己不斷的查詢,終於守得雲開見月明,找到了手動熱更新操作,以及通過點選事件觸發,或者監聽事件觸發更新的方法…關鍵時刻還是要看官方文件,以及github網站.話不多說,接下來就上熱更新操作 **

自動以及手動模式步驟

**

**

熱更新外掛

熱更新前準備工作:當然是按照外掛了喲. ** 1.熱更新外掛安裝

ionic2.0安裝方式:(已安裝),我的是ionic

cordova plugin add cordova-hot
-code-push-plugin

ionic 4.0安裝方式,看自己版本

ionic cordova plugin add cordova-hot-code-push

ionic info 檢視自己的環境配置

熱更新步驟

1.cordova plugin add cordova-hot-code-push-plugin
2.cordova  plugin add cordova-hot-code-push-local-dev-addon
3.npm install -g cordova-hot-code-push-cli

上面三個,網上有的人說第二個不用安裝,我還是安了,因為不知道,所以大不了安裝了再解除安裝就是,

https://beta.ionicframework.com/docs/native/hot-code-push ionic 4.0官方外掛安裝文件 npm install –save @ionic-native/hot-code-push這個我沒有安裝,不過也沒報錯,也不知道有什麼用,估計是在本地熱匯入了熱更新外掛吧,哈哈哈,反正我沒有用


import { HotCodePush } from '@ionic-native/hot-code-push';

constructor(private hotCodePush: HotCodePush) { }

...

hotCodePush.fetchUpdate
(options).then(data => { console.log('Update available');
})

在專案根目錄下執行 $cordova-hcp server , 然後ctrl / command + z 結束伺服器,我們不使用它的伺服器來測試。只為了使用它生成的一個配置檔案,名為:.chcpenv

.chcpenv{ “content_url”: “http://192.168.131.2:1111/hot“, “config_url”: “http://192.168.131.2:1111/hot/chcp.json } 我們在專案APP根目錄下新建一個cordova-hcp.json檔案,這個檔案是生成配置檔案的模板,編輯如下 { “autogenerated”: true, “name”: “com.cqzuxia.zuxiaoa”, “min_native_interface”: 1, “content_url”: “http://192.168.131.2:1111/hot“, “update”: “start” } 在專案APP根目錄執行cordova-hcp build, 這樣就會按照上一步的cordova-hcp.json檔案為模板在www目錄中生成兩個檔案,chcp.json 和 chcp.manifest 兩個檔案。chcp.json 檔案內容 這裡寫圖片描述 ——————————–chcp.json配置————————————-

{
  "autogenerated": true,
  "name": "com.cqzuxia.zuxiaoa",
  "min_native_interface": 1,
  "content_url": "http://192.168.131.2:31284",
  "update": "now",
  "release": "2018.09.04-16.27.07"
}
.chcpenv{
  "content_url": "http://192.168.131.2:1111/hot",
  "config_url": "http://192.168.131.2:1111/hot/chcp.json
  }

——————————–.chcpenv配置————————————-

.chcpenv{
  "content_url": "http://192.168.131.2:1111/hot",
  "config_url": "http://192.168.131.2:1111/hot/chcp.json
  }

chcp.manifest 檔案內容是存的www檔案的hash值,以後就會根據這個值比較是否改變來確定是否更新.當然還有看chcp.json中的時間戳 release.

自建的本地伺服器

我們現在可以開啟一個本地伺服器,隨便找一個地方新建一個資料夾,然後在資料夾根目錄下執行 hs -o -p 1111 (備註,hs命令是全域性安裝了http-server之後才能使用,npm i -g http-server), http://192.168.131.2:31284/ 專案執行cordova-hcp server 後的伺服器地址,一般不用,用自己自建的本地伺服器,儘量不要和自己的專案衝突,後面會感覺很繞,不在專案中建伺服器

d:

cmd -> d: –> cd SVNfilenew -> cd hotcodedevelop -> d:\SVNfilenew\hotcodedevelop 對,就是這個目錄下執行:hs -o -p 1111 這裡寫圖片描述 D:\SVNfilenew\hotcodedevelop 如何啟動本地伺服器?? 關鍵命令列: hs -o -p 1111

啟動本地伺服器地址

cordova-hcp server 這樣我們可以通過訪問 http://127.0.0.1:1111 來訪問我們這個本地伺服器了。 ipconfig檢視本機IP:訪問本機本地伺服器

http://192.168.131.2:1111 這個本地伺服器就是儲存熱更新的程式碼的地方,也就是需要編譯ionic cordova run Android 生成後的www檔案存放地址.當然上線後就放在雲伺服器上相應的地址了. ——————————-config.xml—————————————–

 <chcp>
        <!-- 版本號 -->
        <native-interface version="1" />
        <!-- 伺服器地址 -->
        <config-file url="http://192.168.131.2:1111/hot/chcp.json" />
        <!-- 自動下載 -->
        <auto-download enabled="true" />
        <!-- 自動安裝 -->
         <auto-install enabled="true" />
    </chcp>

5.cordova-hcp build 在專案APP根目錄執行命令使用cordova-hcp build重新生成檔案的hash.這一步很容易被忽略 —->在足下校園APP目錄下執行 這裡寫圖片描述

再把www考到伺服器對應的www. 到此為止,熱更新的自動操作完成,每次開啟APP都會更新資源了,再也不需要手動去下載版本了,是不是挺爽.但是還遠遠不夠,達不到要求啊. 上面這些操作就是自動熱更新的步驟,只不過手動熱更新同樣要使用這些步驟.

手動更新開始:

手動更新,就意味著要控制更新的程式碼所執行方法 下面哈哈,請見證奇蹟的時刻 安裝步驟同上

—————–自動模式————–config.xml—————————————–

 <chcp>
        <!-- 版本號 -->
        <native-interface version="1" />手動配置這些都不需要了,會在程式碼中新增.
        <!-- 伺服器地址 -->
        <config-file url="http://192.168.131.2:1111/hot/chcp.json" />手動配置這些都不需要了,會在程式碼中新增.
        <!-- 自動下載 -->
        <auto-download enabled="false" />
        <!-- 自動安裝 -->
         <auto-install enabled="false" />
    </chcp>

—————-手動模式—————config.xml—————————————–

 <chcp>
        <!-- 自動下載 -->
        <auto-download enabled="false" />
        <!-- 自動安裝 -->
         <auto-install enabled="false" />
    </chcp>

主要講解ts模組內容 app.component.ts中 新增宣告declare var chcp :any; 這裡寫圖片描述

1.通過監聽更新,

  //程式在前臺切換到後臺
      document.addEventListener("pause", () => {
        console.log("後臺隱藏:");
        this.pause();
      }, false);

      //程式在後臺切換到前臺操作
      document.addEventListener("resume", () => {
        console.log("前臺顯示:");
        // this.CheckResource();
        this.resume();
      }, false);

2.通過APP登入後進入介面時更新控制

//資源包熱更新資訊檢測
      this.CheckResource();
// platform.resume.subscribe(() => this.fetchUpdate());
// 是否更新-----------------------------資源包熱更新
  //資源包熱更新資訊檢測
  CheckResource() {
    this.sys.CheckResourceVersion((isUpdate, type) => {

      console.log("是否有更新===="+isUpdate);
      console.log("更新型別為===="+type);
      if (isUpdate) {
        if (type == 0) {
          this.silentUpdate();
        } else if (type == 1) {
          this.hintUpdate(type);
        } else if (type == 2) {
          this.forceUpdate(type);
        }
      }
    });
  }
  // 靜默更新 -- 使用者不曉得更新了.
  silentUpdate() {
    console.log("靜默更新");
    this.fetchUpdate();
  }
  // 提示更新
  hintUpdate(type) {
    this.popConfirm(type);
  }
  // 強制更新 -- 使用者曉得更新了.
  forceUpdate(type) {
    this.popConfirm(type);
  }
  // 提示更新彈窗
  popConfirm(type) {
    let buttons = [{
      text: '現在更新',
      handler: () => {
        this.utils.showLoading('正在下載更新資源包...,下載完成後將自動重啟APP,請稍候...',20000);
        this.fetchUpdate();
      }
    }];
    let msg = "";
    if (type == 1) {
      msg = "是否立即更新?";
      buttons.unshift({
        text: '以後再說',
        handler: () => {
          AppConfig.updateModal.dismiss();
        }
      });
    }
    else if (type == 2) {
      msg = "(請現在下載更新後使用,必須更新)";
    }

    AppConfig.updateModal = this.alertCtrl.create({
      title: '升級提示',
      message: '【足下校園APP】發現有新資源包.' + msg,
      buttons: buttons
    });
    AppConfig.updateModal.onDidDismiss(() => {
      AppConfig.updateModal = null;
    });
    AppConfig.updateModal.present();
  }
 // 匹配更新
  fetchUpdate() {
    const options = {
      'config-file': 'http://192.168.131.2:1111/hot/chcp.json'
    };
    chcp.fetchUpdate(this.updateCallback, options);
  }

  updateCallback(error, data) {
    if (error) {
      console.log('Failed to load the update with error code: ' + error.code);
      console.log(error.description);
    } else {
      console.log('Update is loaded');
      chcp.installUpdate(error => {
        if (error) {
          console.log('Failed to install the update with error code: ' + error.code);
          console.log(error.description);
        } else {
          console.log('Update installed!');
        }
      });
    }
  }

一下是app.component.ts完整程式碼,以及韌體外殼更新程式碼.方法是CheckNewVersion()這個方法.這個比較簡單,直接跳轉下載

import { Component, ViewChild } from '@angular/core';
import { Platform, Nav, AlertController } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StartPage } from '../pages/start/start';
import { SystemService } from '../providers/system-service';
import { HttpService } from '../providers/HttpService';
import { UserInfoData } from '../model/UserInfoData';
import { StorageService } from '../providers/StorageService';
// import { BrowserService } from '../providers/BrowserService';
import { JPush } from '@jiguang-ionic/jpush';
import { Device } from "@ionic-native/device";
import { Autostart } from '@ionic-native/autostart';
import { TeacherEduHttpService } from '../providers/TeacherEduHttpService';
import { File } from '@ionic-native/file';
import { ImageData } from '../model/ImageModel';
import { BrowserService } from '../providers/BrowserService';
import { Keyboard } from "@ionic-native/keyboard";
import { AppConfig } from "./app.config";
import { commonUtils } from '../providers/common-utils';
// import { HotCodePush } from '@ionic-native/hot-code-push';
declare var chcp: any;


@Component({
  templateUrl: 'app.html',

})
export class MyApp {
  @ViewChild('mynav') nav: Nav;
  rootPage;
  loginInfo: UserInfoData;

  msgCount: 0;

  constructor(
    private context: TeacherEduHttpService,
    private platform: Platform,
    statusBar: StatusBar,
    splashScreen: SplashScreen,
    private sys: SystemService,
    private st: StorageService,
    private file: File,
    private httpService: HttpService,
    private autostart: Autostart,
    private jp: JPush,
    private device: Device,
    private bs: BrowserService,
    private alertCtrl: AlertController,
    private keyboard: Keyboard,
    public utils: commonUtils,
    // private hotCodePush: HotCodePush
  ) {
    platform.ready().then(() => {

      AppConfig.platformType = this.platform.is("ios") ? 'ios' : 'android';

      var type = this.st.read<number>("login_type");
      if (type != null) {
        AppConfig.lastLoginType = type;
      }
      //manual mode. remove this for automatic mode
      // platform.resume.subscribe(() => this.fetchUpdate());
      statusBar.styleDefault();
      splashScreen.hide();
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      // statusBar.styleDefault();
      // statusBar.overlaysWebView(true);
      // statusBar.hide();
      splashScreen.hide();

      this.keyboard.hideKeyboardAccessoryBar(false);

      this.nav.rootParams = {
        selectedIndex: 1,
        msgCount: 0
      };

      this.StartJpush();

      this.setBadge();

      this.resetImage();

      this.rootPage = StartPage;
      //設定為自啟動
      if (this.device.platform == "Android") {

        this.autostart.enable();
      }
      //資源包熱更新資訊檢測
      this.CheckResource();

      //外殼版本資訊檢測
      this.sys.CheckNewVersion((hasNewVersion) => {
        console.log("外殼版本資訊檢測");
        if (hasNewVersion) {
          this.presentConfirm();
        }
      });
      //程式在前臺切換到後臺
      document.addEventListener("pause", () => {
        console.log("後臺隱藏:");
        this.pause();
      }, false);

      //程式在後臺切換到前臺操作
      document.addEventListener("resume", () => {
        console.log("前臺顯示:");
        // this.CheckResource();
        this.resume();
      }, false);
    });
  }

  // 是否更新-----------------------------資源包熱更新
  //CheckResourceVersion這個是後臺調介面方法,用於判斷是否更新,以及哪種更新方式等.isUpdate更新為true,不更新為false
type:1.靜默更新,2,提示更新,3,強制更新
  //資源包熱更新資訊檢測
  CheckResource() {
    this.sys.CheckResourceVersion((isUpdate, type) => {
      console.log("是否有更新===="+isUpdate);
      console.log("更新型別為===="+type);
      if (isUpdate) {
        if (type == 0) {
          this.silentUpdate();
        } else if (type == 1) {
          this.hintUpdate(type);
        } else if (type == 2) {
          this.forceUpdate(type);
        }
      }
    });
  }
  // 靜默更新 -- 使用者不曉得更新了.
  silentUpdate() {
    console.log("靜默更新");
    this.fetchUpdate();
  }
  // 提示更新
  hintUpdate(type) {
    this.popConfirm(type);
  }
  // 強制更新 -- 使用者曉得更新了.
  forceUpdate(type) {
    this.popConfirm(type);
  }
  // 提示更新彈窗
  popConfirm(type) {
    let buttons = [{
      text: '現在更新',
      handler: () => {
        this.utils.showLoading('正在下載更新資源包...,下載完成後將自動重啟APP,請稍候...',20000);
        this.fetchUpdate();
      }
    }];
    let msg = "";
    if (type == 1) {
      msg = "是否立即更新?";
      buttons.unshift({
        text: '以後再說',
        handler: () => {
          AppConfig.updateModal.dismiss();
        }
      });
    }
    else if (type == 2) {
      msg = "(請現在下載更新後使用,必須更新)";
    }

    AppConfig.updateModal = this.alertCtrl.create({
      title: '升級提示',
      message: '【足下校園APP】發現有新資源包.' + msg,
      buttons: buttons
    });
    AppConfig.updateModal.onDidDismiss(() => {
      AppConfig.updateModal = null;
    });
    AppConfig.updateModal.present();
  }

  // 匹配更新 ----------這裡是核心程式碼.
  //官網地址:
  //
  https://github.com/ralscha/blog/blob/master/hotcodepush/src/app/app.component.ts
//
https://golb.hplar.ch/2017/01/Hot-deploy-updates-with-the-cordova-hot-code-push-plugin.html
fetchUpdate() {
    const options = {
      'config-file': 'http://192.168.131.2:1111/hot/chcp.json'
    };
    chcp.fetchUpdate(this.updateCallback, options);
  }

  updateCallback(error, data) {
    if (error) {
      console.log('Failed to load the update with error code: ' + error.code);
      console.log(error.description);
    } else {
      console.log('Update is loaded');
      chcp.installUpdate(error => {
        if (error) {
          console.log('Failed to install the update with error code: ' + error.code);
          console.log(error.description);
        } else {
          console.log('Update installed!');
        }
      });
    }
  }

  //重置未載入的圖片資料
  resetImage() {
    var images = this.st.read<Array<ImageData>>("image_data");
    images = images ? images : [];

    var dataDir = this.file.dataDirectory;
    images = images.filter(image => {
      if (image.stats == 1) {
        this.file.removeFile(dataDir + image.local, image.name);
        return false;
      }
      else if (image.stats == 2) {
        return true;
      }
    });

    this.st.write("image_data", images);
  }


  //初始化訊息推送


  StartJpush() {
    this.jp.init().then(() => {
    });
    // this.jp.resumePush();
    // let page=this;
    document.addEventListener('jpush.receiveRegistrationId', function (event) {
      console.log(event)
    }, false);
    this.jp.isPushStopped().then((value) => {

      if (value == 0) {
        // 開啟
      } else {
        // alert("你已經關閉訊息推送");
      }
    });


    // //應用程式處於後臺時
    // document.addEventListener("jpush.backgroundNotification", function (event) {
    //   var alertContent
    //   if(page.device.platform == "Android") {
    //     alertContent = event["alert"]
    //   } else {
    //     alertContent = event["aps"]["alert"]
    //   }
    //   // page.setBadge();

    //   console.log("backgroundNotification")
    // }, false)
    // //應用程式處於前臺時
    // document.addEventListener("jpush.receiveNotification", function (event) {
    //   page.nav.rootParams.selectedIndex = 0;

    //   var alertContent
    //   if(page.device.platform == "Android") {
    //     alertContent = event["alert"]
    //   } else {
    //     alertContent = event["aps"]["alert"]

    //   }
    //   // page.setBadge();

    //   console.log(event);
    //   // alert("receiveNotification")
    // }, false)
    // //點選通知啟動或喚醒應用程式時
    // document.addEventListener("jpush.openNotification", function (event) {
    //   page.nav.rootParams.selectedIndex = 0;

    //   var alertContent
    //   if(page.device.platform == "Android") {
    //     alertContent = event["alert"]
    //   } else {
    //     alertContent = event["aps"]["alert"]
    //   }
    //   console.log(event);
    //   // page.setBadge();

    //    alert("openNotification")
    //   page.setBadge();

    // }, false)
    // //收到應用內訊息時
    // document.addEventListener("jpush.receiveMessage", function (event) {
    //   var message
    //   if(page.device.platform == "Android") {
    //     message = event["message"];
    //   } else {
    //     message = event["content"];


    //   }
    //   alert("receiveMessage")

    //   page.setBadge();

    // }, false)
  }

  setBadge() {
    var page = this;
    page.sys.getAppversion().getVersionNumber().then((ver) => {
      page.context.GetOverviewMessage({ appVersion: ver.toString() }, (res) => {
        if (res.Success) {
          page.msgCount = 0;
          res.Data.forEach(m => {
            page.msgCount += m.MsgCount;
          });
          page.jp.setApplicationIconBadgeNumber(page.msgCount);
          page.jp.setBadge(page.msgCount);

          page.nav.rootParams.msgCount = page.msgCount > 99 ? 99 : page.msgCount;
        }
      }, null);
    });
  }



  pause() {

  }

  resume() {
    let page = this;

    this.jp.resumePush();

    page.sys.CheckNewVersion(function (hasNewVersion, isForce) {
      if (hasNewVersion) {
        page.presentConfirm(isForce);
      }
    });

    this.loginInfo = this.st.read<UserInfoData>("logindata");
    if (this.loginInfo)
      this.autoLogin(this.loginInfo);
  }

  presentConfirm(isForce: boolean = false) {
    if (AppConfig.updateModal) {
      // this.tipspage.dismiss();
      // this.tipspage = null;
      return;
      // this.tipspage.present();
    }

    let buttons = [{
      text: '現在更新',
      handler: () => {
        this.bs.goDownload();
      }
    }];

    let msg = "";
    if (isForce) {
      msg = "(必須更新)";
    }
    else {
      msg = "是否跳轉下載更新?";
      buttons.unshift({
        text: '以後再說',
        handler: () => {
          AppConfig.updateModal.dismiss();
        }
      });
    }
    AppConfig.updateModal = this.alertCtrl.create({
      title: '系統提示',
      message: '【足下校園APP】發現有新版本.' + msg,
      enableBackdropDismiss: !isForce,
      buttons: buttons
    });
    AppConfig.updateModal.onDidDismiss(() => {
      AppConfig.updateModal = null;
    });
    AppConfig.updateModal.present();
  }

  autoLogin(data) {
    var st = this.st;
    //學生登入
    if (this.loginInfo.type == 0) {
      var postdata = {
        client_id: 'f458da7b85b14452',
        client_secret: 'ea2dfee53ab440e08451375a834841cf',
        scope: 'accounts menus roles',
        grant_type: 'password',
        username: data.LoginID,
        password: data.LoginPwd
      };
      this.httpService.httpPostNoAuth('http://learning.cqzuxia.com/oauth/token', postdata, function (res) {
        res.userType = 0;
        data.UserToken = res.access_token;
        st.write("logindata", data);
        st.write('authData', res);
        st.write("username", data.LoginID);
        st.write("password", data.LoginPwd);
        st.write("lastusername", data.LoginID);
        st.write("lastpassword", data.LoginPwd);
        console.log(res);
      }, function (err) {

      });
    } else {
      //老師登入
      postdata = {
        client_id: 'i5g0n1MUJ0YwGZnG',
        client_secret: 'gP90SCHhow3KE4fFwuOfiM5cghmNM9TV',
        scope: 'accounts menus roles',
        grant_type: 'password',
        username: data.LoginID,
        password: data.LoginPwd
      };
      this.httpService.httpPostNoAuth('http://passport.cqzuxia.com/oauth/token', postdata, function (res) {

        res.userType = 1;
        st.write('authData', res);
        st.write("logindata", data);

      }, function (err) {

      });

    }
  }

}

資源包更新和外殼更新調介面方法

public CheckNewVersion(callback) {
    let thispage = this;

    if(AppConfig.lastLoginType != undefined) {  //如果從未登入過,則不推送
      this.http.httpGetNoAuth("http://app.cqzuxia.com/api/Values/GetCampusAppVersionNewWithType", {}, function (res) {
        let serverversion = res;

        let isForce: boolean = false;
        if(AppConfig.lastLoginType == 0) {
          isForce = serverversion.Data.force.student;
        }
        else if(AppConfig.lastLoginType == 1) {
          isForce = serverversion.Data.force.teacher;
        }

        // thispage.appversion.getVersionNumber().then((appres) => {
          let serverMuberarry = [];
          if (thispage._device.platform.toLowerCase() == "android") {
            if (!serverversion.Data.android) { return }
            if(AppConfig.lastLoginType == 0) {  //學生
              serverMuberarry = serverversion.Data.android.student.toString().split('.');
            }
            else if(AppConfig.lastLoginType == 1) {  //老師
              serverMuberarry = serverversion.Data.android.teacher.toString().split('.');
            }
          }
          else if (thispage._device.platform.toLowerCase() == "ios") {
            if (!serverversion.Data.ios) { return }
            if(AppConfig.lastLoginType == 0) {  //學生
              serverMuberarry = serverversion.Data.ios.student.toString().split('.');
            }
            else if(AppConfig.lastLoginType == 1) {  //老師
              serverMuberarry = serverversion.Data.ios.teacher.toString().split('.');
            }
          }

          let mersionmuberarry = AppConfig.localVersion().split(".");

          let len = Math.min(serverMuberarry.length, mersionmuberarry.length);
          for (let i = 0; i < len; i++) {
            //如果本地小於伺服器,肯定要升級;如果本地大於伺服器,證明伺服器在降級,也需要升級(降級)
            if (mersionmuberarry[i] < serverMuberarry[i] || mersionmuberarry[i] > serverMuberarry[i]) {
              callback(true, isForce);
              return;
            }
          }

          callback(false, isForce);
        // });
      });
    }
  }
  public getAppversion() {
    return this.appversion;
  }

  public CheckResourceVersion(callback: Function) {
    let thispage = this;

    if(AppConfig.lastLoginType != undefined) {  //如果從未登入過,則不推送
      this.http.httpGetNoAuth("http://app.cqzuxia.com/api/Values/GetCampusAppResourceVersion", {}, function (res) {
        let serverversion = res;
        let type: number = 0;
        // thispage.appversion.getVersionNumber().then((appres) => {
          let serverMuberarry = [];
          if (thispage._device.platform.toLowerCase() == "android") {
            if (!serverversion.Data.android) { return }
            if(AppConfig.lastLoginType == 0) {  //學生
              serverMuberarry = serverversion.Data.android.student.toString().split('.');
              type = serverversion.Data.android.studentType;
            }
            else if(AppConfig.lastLoginType == 1) {  //老師
              serverMuberarry = serverversion.Data.android.teacher.toString().split('.');
              type = serverversion.Data.android.teacherType;
            }
          }
          else if (thispage._device.platform.toLowerCase() == "ios") {
            if (!serverversion.Data.ios) { return }
            if(AppConfig.lastLoginType == 0) {  //學生
              serverMuberarry = serverversion.Data.ios.student.toString().split('.');
              type = serverversion.Data.android.studentType;
            }
            else if(AppConfig.lastLoginType == 1) {  //老師
              serverMuberarry = serverversion.Data.ios.teacher.toString().split('.');
              type = serverversion.Data.android.teacherType;
            }
          }

          let mersionmuberarry = AppConfig.localResourceVersion().split(".");

          let len = Math.min(serverMuberarry.length, mersionmuberarry.length);
          for (let i = 0; i < len; i++) {
            //如果本地小於伺服器,肯定要升級;如果本地大於伺服器,證明伺服器在降級,也需要升級(降級)
            if (mersionmuberarry[i] < serverMuberarry[i] || mersionmuberarry[i] > serverMuberarry[i]) {
              callback(true, type);//type=0靜默更新=1提示更新.=2強制更新
              return;
            }
          }

          callback(false);
        // });
      });
    }
  }

—————熱更新嘗試-以及中途遇到的問題—————- 1. 配置熱更新在啟動的時候.

安裝 cordova plugin add cordova-android-support-gradle-release rm後可以打包,successful

3.新增去重複的程式碼 4.platforms/android/build.gradle中新增程式碼,這段程式碼有用,寫上去就不報錯

configurations.all {
    // OkHttp 3.5.0+ includes the websockets API, so we need this to prevent a conflict
    exclude module: 'okhttp-ws'
} 
5.compile "com.android.support:support-v4:23.1.0"
project.properties中
# cordova.system.library.5=com.android.support:support-v4:24.1.1+

//6.不新增以下程式碼也可以打包,successful

  d