https://www.cnblogs.com/lunlunshiwo/p/10361298.html
在我接觸Flutter之前,做過一個比較失敗的基於DCloud的HTML5+技術的app,做過幾個RN項目。在這兩種不同機制的app升級方案中,RN采用的是微軟的CodePush技術。而那個比較失敗的項目采用的是檢查版本號,下載安裝包的方法。而在這個Flutter項目中,我在寫app更新方法時,查資料的時候查到一篇文章,文章大概意思講解了一下Flutter實行CodePush的可能性。但是,我並未找到可能實現的方法。因此,采用了簡單粗暴的進行app升級。
服務器的操作
為了檢驗版本號和下載app安裝包,我們在服務器某文件夾下放置兩個文件,第一個為version.json文件,內容為:
{
"android": "1.0.1" }
這個文件用於保存版本號,我們可以寫一個讀取方法來讀取這個版本號:
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安裝包,用來下載之后安裝。
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 開始添加了權限申請的需求,更加安全。因此,我們需要做一下額外的才做來獲取權限。
我在stackoverflow上找到了一篇文章了解了一下這個問題的解決方案。這篇文章中贊最高的方法比較負責,因為時間比較短,暫時沒有研究,不過項目組大佬說如果要完美地解決這個問題還是要會過來研究一下。
我在本次項目中采用了第二種方法,在MainActivity.java的onCreate方法中添加
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。