1. 說明
-
iOS 和Android 更新是完全不一樣的。
-
iOS 只能跳轉到 AppStore,比較好實現
-
Android則需要下載apk包,由於Android機型較多,這裡我們用 dart 連線第三方的原生 Android 下載庫。
-
更新介面和下載更新分開處理的。
-
iOS 沒得下載進度這一說,Android 則有。
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