flutter 優雅的版本更新處理


本人掘金文章

思路步驟:

  1.  獲取后台接口返回的最新版本的 vsersion 值! (這需要每次APP發版提審后,同時更新后台數據庫App version);
  2.  使用 package_info 插件獲取項目當前APP運行的 的版本號 version
  3.  后台返回的版本 version 大於 package_info 獲取的 version!則彈出提示更新;
  4.  ios 跳轉 AppStore 進行更新; android 則App內下載更新

說明:

  1.  android 版本的 apk 上傳到公司 oss, 生成的鏈接就是下載鏈接
  2.  可能存在的坑有, 本地開發模式下 android 下載好的apk安裝不了, 提示應用簽名不一致! (原因 本地開發模式並沒有走 keystore簽名;但是apk有; 用戶從應用商店下載不會出現這情況; 或者你通過apk安裝應用,在走流程測試就不會了)
  3.  使用的第三方插件有 package_info 用於獲取當前版本號;flutter_xupdate 用於 android App內下載更新;
  4.  效果圖見尾部

具體代碼:

注: android 實現 App 內下載更新,我選用的是 flutter_xupdate插件並且使用的是自定義JSON的格式(靈活性較好); 插件使用方式請點擊 flutter_xupdate

homePage.dart 文件
 import './CheckUpdate.dart';
    CheckUpdate checkUpdate = CheckUpdate();
  
    // 獲取版本
    Future<dynamic> initPackageInfo () async {
      PackageInfo packageInfo = await PackageInfo.fromPlatform();
      version = packageInfo.version;
    }
    
     // 檢查是否需要版本更新
    void _checkUpdateVersion () async {
      await initPackageInfo();
      try {
        var response = await HttpUtil().post("app/version/detail?", 'mobile', 'json', false);
        if (response["code"] != 0) {
          setState(() {
            versionData = response["data"];
          });
          // 后台返回的版本號是帶小數點的(2.8.1)所以去除小數點用於做對比
          var targetVersion = response["data"]["versionCode"].replaceAll('.', '');
          // 當前App運行版本
          var currentVersion = version.replaceAll('.', '');
          if (int.parse(targetVersion) > int.parse(currentVersion)) {
            if (Platform.isAndroid) { // 安卓彈窗提示本地下載, 交由flutter_xupdate 處理,不用我們干嘛。
              await checkUpdate.initXUpdate();
              checkUpdate.checkUpdateByUpdateEntity(versionData); // flutter_xupdate 自定義JSON 方式, 
            } else if (Platform.isIOS) { // IOS 跳轉 AppStore
              showIOSDialog(); // 彈出ios提示更新框
            }
          }
        }
      } catch (e) {
        print(e);
      }
    }
CheckUpdate.dart 文件
import 'dart:convert';
import 'package:flutter_xupdate/flutter_xupdate.dart';

class CheckUpdate{
  // 將自定義的json內容解析為UpdateEntity實體類
  UpdateEntity customParseJson(String json) {
    AppInfo appInfo = AppInfo.fromJson(json);
    return UpdateEntity(
      isForce: appInfo.isForce, // 是否強制更新
      hasUpdate: appInfo.hasUpdate, // 是否需要更新  默認true, 手動自行判斷
      isIgnorable: appInfo.isIgnorable, // 是否顯示 “忽略該版本”
      versionCode: appInfo.versionCode, // 新版本號
      versionName: appInfo.versionName, // 新版名稱
      updateContent: appInfo.updateLog, // 新版更新日志
      downloadUrl: appInfo.apkUrl, // 新版本下載鏈接
      apkSize: appInfo.apkSize); // 新版本大小
  }
    // 自定義JSON更新
  checkUpdateByUpdateEntity(Map jsonData) async {
    var versionCode = jsonData["versionCode"].replaceAll('.', '');
    var updateText = jsonData["updateLog"].split('');
    var updateLog = '';
    updateText.forEach((t) {
      updateLog += '\r\n$t';
    });
    var rusultJson = {
      "isForce": jsonData["isForce"] == 1,
      "hasUpdate": true,
      "isIgnorable": false,
      "versionCode": int.parse(versionCode),
      "versionName": jsonData["versionName"],
      "updateLog": updateLog,
      "apkUrl": jsonData["apkUrl"],
      "apkSize":jsonData["apkSize"]
    };
    FlutterXUpdate.updateByInfo(updateEntity: customParseJson(json.encode(rusultJson)));
  }

  // 初始化插件
  Future<dynamic> initXUpdate () async {
    FlutterXUpdate.init(
      //是否輸出日志
      debug: true,
      //是否使用post請求
      isPost: false,
      //post請求是否是上傳json
      isPostJson: false,
      //是否開啟自動模式
      isWifiOnly: false,
      ///是否開啟自動模式
      isAutoMode: false,
      //需要設置的公共參數
      supportSilentInstall: false,
      //在下載過程中,如果點擊了取消的話,是否彈出切換下載方式的重試提示彈窗
      enableRetry: false)
    .then((value) {
      print("初始化成功: $value");
    }).catchError((error) {
      print(error);
    });
    FlutterXUpdate.setUpdateHandler(
      onUpdateError: (Map<String, dynamic> message) async {
        print("初始化成功: $message");
      }, onUpdateParse: (String json) async {
        //這里是自定義json解析
        return customParseJson(json);
      });
  }
}

// 使用Dart Data Class Generator插件進行創建  使用命令: Generate from JSON
class AppInfo {
  final bool isForce;
  final bool hasUpdate;
  final bool isIgnorable;
  final int versionCode;
  final String versionName;
  final String updateLog;
  final String apkUrl;
  final int apkSize;

  AppInfo({
    this.isForce,
    this.hasUpdate,
    this.isIgnorable,
    this.versionCode,
    this.versionName,
    this.updateLog,
    this.apkUrl,
    this.apkSize,
  });

  Map<String, dynamic> toMap() {
    return {
      'isForce': isForce,
      'hasUpdate': hasUpdate,
      'isIgnorable': isIgnorable,
      'versionCode': versionCode,
      'versionName': versionName,
      'updateLog': updateLog,
      'apkUrl': apkUrl,
      'apkSize': apkSize,
    };
  }

  static AppInfo fromMap(Map<String, dynamic> map) {
    if (map == null) return null;

    return AppInfo(
      isForce: map['isForce'],
      hasUpdate: map['hasUpdate'],
      isIgnorable: map['isIgnorable'],
      versionCode: map['versionCode']?.toInt(),
      versionName: map['versionName'],
      updateLog: map['updateLog'],
      apkUrl: map['apkUrl'],
      apkSize: map['apkSize']?.toInt(),
    );
  }

  String toJson() => json.encode(toMap());

  static AppInfo fromJson(String source) => fromMap(json.decode(source));

  @override
  String toString() {
    return 'AppInfo isForce: $isForce, hasUpdate: $hasUpdate, isIgnorable: $isIgnorable, versionCode: $versionCode, versionName: $versionName, updateLog: $updateLog, apkUrl: $apkUrl, apkSize: $apkSize';
  }
}

有疑問歡迎留言

效果圖: 左邊2張為 android, 右邊為 ios

                 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM