Flutter項目之app升級方案

題接上篇的文章的項目,仍是那個空貨管理app。本篇文章用於講解基於Flutter的app項目的升級方案。此文只有安卓版。vue

在我接觸Flutter以前,作過一個比較失敗的基於DCloud的HTML5+技術的app,作過幾個RN項目。在這兩種不一樣機制的app升級方案中,RN採用的是微軟的CodePush技術。而那個比較失敗的項目採用的是檢查版本號,下載安裝包的方法。而在這個Flutter項目中,我在寫app更新方法時,查資料的時候查到一篇文章,文章大概意思講解了一下Flutter實行CodePush的可能性。可是,我並未找到可能實現的方法。所以,採用了簡單粗暴的進行app升級。java

服務器的操做

爲了檢驗版本號和下載app安裝包,咱們在服務器某文件夾下放置兩個文件,第一個爲version.json文件,內容爲:android

{
    "android": "1.0.1"
}
複製代碼

這個文件用於保存版本號,咱們能夠寫一個讀取方法來讀取這個版本號:vuex

Future<bool> checkNewVersion() async {
  try {
    final res = await http.get(downLoadUrl + '/version.json');
    if (res.statusCode == 200) {
      final Map<String, dynamic> body = json.decode(res.body);
      if (defaultTargetPlatform == TargetPlatform.android) {
        final packageInfo = await PackageInfo.fromPlatform();
        final newVersion = body['android'];
        return (newVersion.compareTo(packageInfo.version) == 1);
      }
    }
  } catch (e) {
    return false;
  }
  return false;
}
複製代碼

第二個文件爲app安裝包,用來下載以後安裝。json

app端的操做

在app端須要增長的方法比較多,有須要處理app的權限和處理版本號讀取以及app安裝包下載和安裝等方法。安全

權限的獲取

targetSdkVersion < 24以前,咱們能夠經過在AndroidManifest.xml這個文件中寫入獲取讀寫權限:服務器

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
複製代碼

可是當Flutter更新到1.0.0版本以後,現階段的targetSdkVersion爲27。API 23以前的版本都是自動獲取權限,而從 Android 6.0 開始添加了權限申請的需求,更加安全。所以,咱們須要作一下額外的才作來獲取權限。app

我在stackoverflow上找到了一篇文章瞭解了一下這個問題的解決方案。這篇文章中贊最高的方法比較負責,由於時間比較短,暫時沒有研究,不過項目組大佬說若是要完美地解決這個問題仍是要會過來研究一下。async

我在本次項目中採用了第二種方法,在MainActivity.java的onCreate方法中添加ui

StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
複製代碼

而後引入simple_permissions這個依賴查詢app的權限和詢問是否開啓權限。具體方法爲:

//是否有權限
  Future<bool> checkPermission() async {
    bool res = await SimplePermissions.checkPermission(
        Permission.WriteExternalStorage);
    return res;
  }

  //打開權限
  Future<PermissionStatus> requestPermission() async {
    return SimplePermissions.requestPermission(Permission.WriteExternalStorage);
  }
複製代碼

版本號的獲取

咱們在服務器上放置了一個名爲version.json的文件,咱們能夠獲取一下這個文件的內容訪問寫在裏面的版本號:

Future<bool> checkNewVersion() async {
  try {
    final res = await http.get(downLoadUrl + '/version.json');
    if (res.statusCode == 200) {
      final Map<String, dynamic> body = json.decode(res.body);
      if (defaultTargetPlatform == TargetPlatform.android) {
        // 獲取此時版本
        final packageInfo = await PackageInfo.fromPlatform();
        final newVersion = body['android'];
        // 此處比較版本
        return (newVersion.compareTo(packageInfo.version) == 1);
      }
    }
  } catch (e) {
    return false;
  }
  return false;
}
複製代碼

由於這個項目是基於安卓7.0的手持終端的項目,此處作了是否爲安卓的查詢處理。

安裝包下載

在下載安裝包這個功能中,咱們安裝了flutter_downloader這個依賴。先獲取一下下載地址,在下載安裝包:

// 獲取安裝地址
Future<String> get _apkLocalPath async {
  final directory = await getExternalStorageDirectory();
  return directory.path;
}
// 下載
Future<void> executeDownload() async {
  final path = await _apkLocalPath;
  //下載
  final taskId = await FlutterDownloader.enqueue(
      url: downLoadUrl + '/app-release.apk',
      savedDir: path,
      showNotification: true,
      openFileFromNotification: true);
  FlutterDownloader.registerCallback((id, status, progress) {
    // 當下載完成時,調用安裝
    if (taskId == id && status == DownloadTaskStatus.complete) {
      _installApk();
    }
  });
}
// 安裝
Future<Null> _installApk() async {
  // XXXXX爲項目名
  const platform = const MethodChannel(XXXXX);
  try {
    final path = await _apkLocalPath;
    // 調用app地址
    await platform.invokeMethod('install', {'path': path + '/app-release.apk'});
  } on PlatformException catch (_) {}
}
複製代碼

安裝完成。

總結

以上爲Flutter項目的更新步驟。在以上步驟中比較坑人的部分時權限獲取至一塊中,若是不設置,則會沒法成功下載安裝包。相信在不久的未來,Flutter可能也會用上CodePush。

順便說一下那個被我稱爲失敗的項目,我去那個項目組的時候這個項目已經作了一半了。而讓我十分震驚的是做爲一個基於vue的項目,項目進行了一多半還沒人使用狀態管理,vuex引入了,可是沒人用。嗯,強行carray,發現carry不動。只能盡力補救以後,眼睜睜地看着這個項目走向深淵。當時我仍是個萌新,想進去學技術的,結果發現一羣自稱三年經驗以上的人還須要我和另外一個剛進公司的同事帶。當時仍是很絕望的,只能一邊絕望一邊帶着他們加班。如今以爲項目組的水平和氛圍真的重要!!!

image
相關文章
相關標籤/搜索