1. 程式人生 > >ionic3 實現app版本更新下載並開啟進行安裝(包括android7+無法自動安裝apk問題的解決方法)

ionic3 實現app版本更新下載並開啟進行安裝(包括android7+無法自動安裝apk問題的解決方法)

記錄一下實現app版本一鍵更新下載的功能。
我的專案的總體的檔案:
這裡寫圖片描述
使用的外掛列表如下:
這裡寫圖片描述
需要純實現該功能用到的基本上是除了後三個。

首先,安裝這些外掛,在app.component.ts頁面上加入

import { Component, ViewChild } from '@angular/core';
import { Platform, ToastController, Nav, IonicApp } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import
{ SplashScreen } from '@ionic-native/splash-screen'; import { AppVersion } from '@ionic-native/app-version'; import { SharedDataService } from "./../providers/SharedDataService"; import { File } from '@ionic-native/file'; import { Device } from '@ionic-native/device'; import { HomeService } from "./../pages/home/HomeService"
; declare var cordova: any; @Component({ templateUrl: 'app.html', providers: [ Device,AppVersion,HomeService,File ] }) export class MyApp { rootPage:any = "AdvertPage"; backButtonPressed: boolean = false; //用於判斷返回鍵是否觸發 @ViewChild('myNav') nav: Nav; constructor( private device
: Device, public ionicApp: IonicApp, private appVersion: AppVersion, private file: File, public platform: Platform, public statusBar: StatusBar, public toastCtrl: ToastController, splashScreen: SplashScreen, private homeService: HomeService, private Share: SharedDataService) { /*SharedDataService是一個存放公共變數的地方 * */ platform.ready().then(() => { /*儲存版本資訊及判斷儲存路徑開始*/ // 讀取所用的平臺 //獲取當前平臺資訊 this.device.platform this.appVersion.getVersionNumber().then(data => { //當前app版本號 data,儲存該版本號 this.Share.appVersion = data; }, error => console.error(error => { //獲取當前版本號失敗進行的操作 })); this.appVersion.getPackageName().then(data => { //當前應用的packageName:data,儲存該包名 this.Share.packageName = data; }, error => console.error(error => { //獲取該APP id 失敗 })); this.Share.platform = this.device.platform; this.Share.savePath = this.Share.platform == 'iOS' ? this.file.documentsDirectory : this.file.externalDataDirectory; //儲存的沙盒地址:this.Share.savePath /*儲存版本資訊及判斷儲存路徑結束*/ }); } //提示彈窗 alertToast(msg){ let toast = this.toastCtrl.create({ message: msg, cssClass:'detailToast', duration: 2000 }); toast.present(); } }

傳送獲取app資訊介面的請求寫在:

public getUpdateInfo(uuid, showLoading) {
        if (showLoading) {
            this.loading.presentLoadingDefault();
        }
        var url = "此地址獲取app資訊的介面地址" + uuid;//此處是我們專案介面所需把本地app的資訊包名傳到介面
        return this.http.get(url).toPromise()
            .then(res => {
                if (this.loading) {
                    this.loading.dismissLoadingDefault();
                }
                return res.json();
            })
            .catch(err => {
                this.handleError(err);
            });
    }

在相應的service(MeService.ts)裡面寫這樣的方法:

getUpdate(showLoading: boolean) {
      return this.httpService.getUpdateInfo(this.Share.packageName, showLoading);
}

在需要的頁面me.ts檔案中程式碼如下,然後在頁面中直接呼叫update()方法即可:

import { Component, ViewChild } from '@angular/core';
import { NavController,IonicPage,ActionSheetController,AlertController } from 'ionic-angular';
import { SharedDataService } from "./../../providers/SharedDataService";
import { App,ViewController } from 'ionic-angular'; 
import { MeService } from "./MeService";
import { FileTransfer, FileTransferObject } from '@ionic-native/file-transfer';
import { FileOpener } from '@ionic-native/file-opener';
import { LoadingService } from "./../../providers/LoadingService";

@IonicPage()
@Component({
  selector: 'page-me',
  templateUrl: 'me.html',
  providers: [FileOpener, FileTransfer, AlertController, MeService]
})
export class MePage {
  constructor(public navCtrl: NavController,
                        public Share: SharedDataService,
                        private app:App,
                    private fileOpener: FileOpener,
                    private transfer: FileTransfer,
//                  private file: File,
                    private alertCtrl: AlertController,
                    private loadingService: LoadingService,
                        public actionSheetCtrl: ActionSheetController,
                    private meService: MeService,
                        public viewCtrl: ViewController) {

  }

  //退出到登入頁
  exitTo(){
        this.app.getRootNav().setRoot("LoginPage");
        delete (<any>window).launchURL;
  }


  update() {
    this.meService.getUpdate(true).then(data => {
      console.log(data);
      // 判斷當前版本號否大於伺服器的版本號
      var serveVersion = data && data.appList && data.appList.group && data.appList.group.app && data.appList.group.app.version;
      console.log(serveVersion);
      console.log(this.Share.appVersion);
      if (this.versionfunegt(serveVersion, this.Share.appVersion)) {
        console.log("檢查到新版本,是否更新APP");

        let alert1 = this.alertCtrl.create({
          title: '版本更新',
          message: '檢查到最新版本,是否進行更新',
          buttons: [
            {
              text: '否',
              role: 'cancel',
              handler: () => {
                console.log('不進行更新');
              }
            },
            {
              text: '是',
              handler: () => {
                console.log('更新APP');
                var url = data && data.appList && data.appList.group && data.appList.group.app && data.appList.group.app.url;
                console.log(url);
                if (this.Share.platform == 'iOS') {
                  console.log('開啟iOS下載地址----------------------------');
                  window.location.href = 'itms-services://?action=download-manifest&url=' + url;
                } else {
                  console.log('開始下載Android程式碼----------------------------');
                  const fileTransfer: FileTransferObject = this.transfer.create();
                  fileTransfer.onProgress(progressEvent => {
                    var present = new Number((progressEvent.loaded / progressEvent.total) * 100);
                    console.log('當前進度為:' + present.toFixed(0));
                    var presentInt = present.toFixed(0);
                    this.loadingService.presentProgress(presentInt);
                  });

                  var savePath = this.Share.savePath + 'android.apk';
                  fileTransfer.download(encodeURI(url), savePath).then((entry) => {
                      console.log('儲存apk包的地址為: ' + this.Share.savePath + 'Ceshiname.apk');
                      console.log('download complete: ' + entry.toURL());
                      console.log("下載成功");

                      this.fileOpener.open(entry.toURL(), "application/vnd.android.package-archive")
                        .then(() => console.log('開啟apk包成功!'))
                        .catch(e => console.log('開啟apk包失敗!', e));
                    }, (error) => {
                      console.log("下載失敗");
                      this.loadingService.presentTip('操作提醒', '由於部分手機出現異常,請您進入手機設定-應用管理-Ceshiname-許可權,將儲存許可權開啟後再進行升級,由此給您帶來的不便,敬請諒解。');
                      for(var item in error) {
                        console.log(item + ":" + error[item]);
                      }
                    });
                    }
              }
            }
          ]
        });
        alert1.present();
      } else {
        this.loadingService.presentMsg("已是最新版本!");
      }
    });
  }

  // 比較版本號
  versionfunegt (a, b) {
        var _a = this.toNum(a), _b = this.toNum(b);   
        if(_a == _b) {
            console.log("版本號相同!版本號為:"+a);
            return false;
        } else if(_a > _b) {
            console.log("版本號"+a+"是新版本!"); 
            return true;
        } else {
            console.log("版本號"+b+"是新版本!"); 
            return false;
        }
    }

  toNum (a) {
        var a = a.toString();
        //也可以這樣寫 var c=a.split(/\./);
        var c = a.split('.');
        var num_place = ["","0","00","000","0000"], r = num_place.reverse();
        for (var i = 0; i< c.length; i++){ 
            var len = c[i].length;       
            c[i] = r[len] + c[i];  
        } 
        var res = c.join(''); 
        return res; 
    } 


  //字型
  changeFont() {
    let actionSheet = this.actionSheetCtrl.create({
      title: '設定字型大小',
      buttons: [
        {
          text: '小',
          role: 'destructive',
          handler: () => {
            this.Share.fontSize = 'small';
          }
        },
        {
          text: '中',
          handler: () => {
            this.Share.fontSize = 'normal';
          }
        },{
          text: '大',
          handler: () => {
            this.Share.fontSize = 'large';
          }
        },
        {
          text: '取消',
          role: 'cancel',
          handler: () => {
            console.log('Cancel clicked');
          }
        }
      ]
    });

    actionSheet.present();
  }

}

公共變數的存放區域為SharedDataService.ts:

import { Injectable } from '@angular/core';
import { HttpService } from "./HttpService";
import { LoadingService } from "./LoadingService";

@Injectable()
export class SharedDataService {

    platform: string; //平臺
    savePath: string; //儲存路徑

    packageName: string;  //包名
    appVersion: string = '1.0.18';  //版本號
    //。。。寫其他需要全域性呼叫的變數。。。
    constructor() {}
}

注:程式碼中用的外掛是cordova-plugin-file-transfer,打包完成後會發現在android7版本上沒有問題,但是到android7以上的版本就有問題,可以下載到本地,但是沒有辦法在更新下載完成時,讓自動安裝,這個問題的解決辦法如下:
首先,新增完平臺:cordova platform add android時,開啟platform資料夾找到AndroidManifest.xml檔案,如下圖:
這裡寫圖片描述
修改為:

<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />

再進行打包即可。