Flutter下載更新 App

破森圖發表於2019-07-16

1. 說明

  1. iOS 和Android 更新是完全不一樣的。

  2. iOS 只能跳轉到 AppStore,比較好實現

  3. Android則需要下載apk包,由於Android機型較多,這裡我們用 dart 連線第三方的原生 Android 下載庫。

  4. 更新介面和下載更新分開處理的。

  5. iOS 沒得下載進度這一說,Android 則有。

screen

2. 程式碼

2.1 iOS 直接採用url_launcher開啟 AppStore就可以了

if (Platform.isIOS) {
  final url = "https://itunes.apple.com/cn/app/id1380512641"; // id 後面的數字換成自己的應用 id 就行了
  if (await canLaunch(url)) {
    await launch(url, forceSafariVC: false);
  } else {
    throw 'Could not launch $url';
  }
}
複製程式碼

2.1 Android實現

2.1.1 在 android/app/build.gradle 檔案新增下載庫
dependencies {
    // 只複製這一行
    implementation 'com.king.app:app-updater:1.0.4-androidx'
}
複製程式碼
2.1.2 在 AndroidManifest.xml新增儲存許可權
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
複製程式碼
2.1.3 在 Android 專案中編寫外掛
package com.iwubida.flutter_yuedu.plugins;

import android.content.Context;
import android.util.Log;

import com.king.app.updater.AppUpdater;
import com.king.app.updater.callback.UpdateCallback;


import java.io.File;
import java.util.HashMap;
import java.util.Map;

import io.flutter.plugin.common.EventChannel;

import io.flutter.plugin.common.PluginRegistry.Registrar;

/** UpdateVersionPlugin */
public class UpdateVersionPlugin implements EventChannel.StreamHandler {

  private static String TAG = "MY_UPDATE";
  private static Context context;

  public UpdateVersionPlugin(Context context) {
    this.context = context;
  }

  /** Plugin registration. */
  public static void registerWith(Registrar registrar) {
    final EventChannel channel = new EventChannel(registrar.messenger(), "plugins.iwubida.com/update_version");
    channel.setStreamHandler(new UpdateVersionPlugin(registrar.context()));
  }


  @Override
  public void onListen(Object o, EventChannel.EventSink eventSink) {

    if (o.toString().length() < 5) {
      eventSink.error(TAG, "URL錯誤", o);
      return;
    }
    if (!o.toString().startsWith("http")){
      eventSink.error(TAG, "URL錯誤", o);
    }

    AppUpdater update = new AppUpdater(context,o.toString()).setUpdateCallback(new UpdateCallback() {

      Map data = new HashMap<String, Object>();

      // 傳送資料到 Flutter
      private  void sendData() {
        eventSink.success(data);
      }

      @Override
      public void onDownloading(boolean isDownloading) {

      }

      @Override
      public void onStart(String url) {
        data.put("start", true);
        data.put("cancel", true);
        data.put("done", true);
        data.put("error", false);
        data.put("percent", 1);
        sendData();
      }

      @Override
      public void onProgress(int progress, int total, boolean isChange) {
        int percent = (int)(progress * 1.0 / total * 100);
        if (isChange && percent > 0) {
          data.put("percent", percent);
          sendData();
        }
      }

      @Override
      public void onFinish(File file) {
        data.put("done", true);
        sendData();
      }

      @Override
      public void onError(Exception e) {
        data.put("error", e.toString());
        sendData();
      }

      @Override
      public void onCancel() {
        data.put("cancel", true);
        sendData();
      }
    });
    update.start();
  }

  @Override
  public void onCancel(Object o) {
    Log.i(TAG, "取消下載-整合的第三方下載沒有提供取消方法");
  }
}

複製程式碼
2.1.4 在 MainActivity 中註冊外掛
// 註冊更新元件 在onCreate方法中
UpdateVersionPlugin.registerWith(registrarFor("iwubida.com/update_version"));
複製程式碼

我們需要獲取到下載進度,所以我們採用EventChannel來持續單向通訊。

2.3 dart端實現

static const channelName = 'plugins.iwubida.com/update_version';
  static const stream = const EventChannel(channelName);
  // 進度訂閱
  StreamSubscription downloadSubscription;
  int percent = 0;
  
   // 開始下載
  void _startDownload() {
    if (downloadSubscription == null) {
      downloadSubscription = stream
          .receiveBroadcastStream(widget.data.apkUrl)
          .listen(_updateDownload);
    }
  }

  // 停止監聽進度
  void _stopDownload() {
    if (downloadSubscription != null) {
      downloadSubscription.cancel();
      downloadSubscription = null;
      percent = 0;
    }
  }

  // 進度下載
  void _updateDownload(data) {
    int progress = data["percent"];
    if (progress != null) {
      setState(() {
        percent = progress;
      });
    }
  }
  
複製程式碼

2.4 其它

另外 Android 還有許可權申請的問題。可以參考下面專案中的程式碼。

專案原始碼

位置: lib/widget/update_version.dart

相關文章