Flutter app應(yīng)用內(nèi)更新 版本檢查(教你避坑)

一、為什么需要?

在我們?nèi)粘J褂肁pp中經(jīng)常會看到有版本需要更新。這有有兩個用處:
1.通知用戶有新版本,并且有什么更新內(nèi)容;
2.在一些bug性要求強制更新的情況可以強制必須更新。

二、更新樣式是什么?

版本檢測

下載更新

三、需要的插件

插件有下面四個。我使用的是當(dāng)前版本,讀者根據(jù)最新版本使用

  #dio
  dio: ^3.0.8
 #更新插件
  ota_update: ^2.2.1
  #獲取app信息
  package_info: ^0.4.0+14
  #跳轉(zhuǎn)第三方
  url_launcher: ^5.4.2

把上面代碼寫在pubspec.yaml文件的以下位置


dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  #這里寫插件

執(zhí)行package get

四、主要代碼是什么?

-首先定義一個版本模型,下面的BaseModel只是定義了一個抽象類,這里你們可以去掉

class VersionModel extends BaseModel{
  String version;
  bool mandatory;
  List<String> updateContent;
  String iosAddress;
  String androidAddress;
  VersionModel.fromJson(Map<String, dynamic> json) : super.fromJson(json){
    version=json['version'];
    mandatory=json['mandatory'];
    updateContent=List.from(json['updateContent']);
    iosAddress=json['iosAddress'];
    androidAddress=json['androidAddress'];
  }

  @override
  Map<String, dynamic> toJson() {
    return {
      'version':version,
      'mandatory':mandatory,
      'updateContent':updateContent,
      'iosAddress':iosAddress,
      'androidAddress':androidAddress,
    };
  }
}

先是檢查版本的方法

  ///檢測當(dāng)前app版本
 _getCurrentVersion()async{
    PackageInfo packageInfo=await PackageInfo.fromPlatform();
    var currentVersion=packageInfo.version;
    return currentVersion;
  }

  ///版本校驗
  _checkVersion()async {
  /// 獲得服務(wù)器版本
  //這寫上獲取json的url,json格式按照定義的versionModel
    String url='http://xxxxxxxxxxxxxxxxxxx/version.json'
    var json = await Dio().get(url);
    if(json==null){
      //獲取版本失敗 網(wǎng)絡(luò)或者其他原因 退出App
      //ToastUtil.showToast('獲取版本失敗');
      await SystemChannels.platform.invokeMethod('SystemNavigator.pop');
    }
    serviceVersion=VersionModel.fromJson(json);
    var currentVersion = await _getCurrentVersion();
    print(currentVersion);
    if(currentVersion==serviceVersion.version){
      //驗證通過
      _goNextPage();
    }else{
      //版本不符彈出對話框
      _showUpdateDialog();
    }
  }
_showUpdateDialog(){
    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (_){
        List<Widget> contentList=[];
        var style=TextStyle(fontSize: 15,);
        contentList.addAll(serviceVersion.updateContent.map((item){
          return Text(item,style: style,);
        }).toList());
        contentList.insert(0, Container(height: 0.4,color: Colors.black,margin: EdgeInsets.only(top: 5,bottom: 5),));
        return CupertinoAlertDialog(
          title:Text('版本更新',style:TextStyle(fontSize: 18,fontWeight: FontWeight.w600)),
          content: Container(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: contentList
            ),
          ),
          actions: <Widget>[
            FlatButton(
              child: Text('取消'),
              textColor: Colors.grey,
              onPressed: serviceVersion.mandatory?null:(){
                _goNextPage();
              },
            ),
            FlatButton(
              child: Text('更新'),
              textColor: Colors.blue,
              onPressed: ()async{
                if(Platform.isAndroid){
                  //安卓應(yīng)用內(nèi)下載
                  Navigator.pop(context);
                  tryOtaUpdate();
                }else{
                  //ios 跳轉(zhuǎn)商店
                  if(await canLaunch(serviceVersion.iosAddress)){
                    await launch(serviceVersion.iosAddress);
                  }else{
                    throw 'Could not launch ';
                  }
                }
              },
            )
          ],
        );
      }
    );
  }

下面是安卓后臺下載更新方法

Future<void> tryOtaUpdate() async {
    try {
       OtaUpdate()
        .execute(serviceVersion.androidAddress, destinationFilename: 'task_app.apk')
        .listen(
          (OtaEvent event) {
          setState(() => currentEvent = event);
        },
      );
    } catch (e) {
      print('Failed to make OTA update. Details: $e');
    }
  }

頁面可以如下展示。也可根據(jù)自己實際情況更換

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: currentEvent != null && serviceVersion != null ? AppBar(
        title: const Text('更新應(yīng)用'),
      ) : null,
      body: Center(
        child: Container(
          padding: EdgeInsets.only(left: 20, right: 20),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.end,
            children: <Widget>[
              Image.asset(
                'assets/images/check_logo.png', height: 100, width: 100,),
              Container(
                height: 100,
                //如果currentEvent不為空則展示加載條
                child: currentEvent != null ? Column(
                  children: <Widget>[
                    double.tryParse(currentEvent.value) is double
                      ? LinearProgressIndicator(
                      semanticsLabel: currentEvent.value,
                      value: double.tryParse(currentEvent.value) / 100,
                      semanticsValue: currentEvent.value,
                    )
                      : Container(),
                    Container(
                      child: Text(
                        '${currentEvent.status == OtaStatus.DOWNLOADING
                          ? '下載中'
                          : (currentEvent.status == OtaStatus.INSTALLING
                          ? '安裝中...'
                          : '')} ${(currentEvent.status == OtaStatus.DOWNLOADING
                          ? ':'
                          : '')} ${currentEvent.value}${currentEvent.status ==
                          OtaStatus.DOWNLOADING ? '%' : ''} \n'),
                      margin: EdgeInsets.only(bottom: 50),
                    )
                  ],
                ) : Container()
              )
            ],
          ),
        ),
      )
    );
  }

下面是我給的示例驗證version.json

{
    "version": "1.0.3",
    "mandatory": false,
    "updateContent": ["1、修復(fù)了一些顯示問題", "2、新增搜索頁面", "3、項目管理可切換成員搜索", "4、項目過期顯示橙色"],
    "iosAddress": "https://apps.apple.com/cn/app/tasktodo/id1498326734",
    "androidAddress": "http://lc-sys.oss-cn-shanghai.aliyuncs.com/apk/task_s103.apk"
}

五、安卓和ios設(shè)置

ios因為是跳轉(zhuǎn)到appstore去更新沒什么需要設(shè)置的
安卓使用Ota_update插件還需要一些其他設(shè)置
-首先在項目android/app/src/main/AndroidManifest.xml文件中添加如下代碼

  ...以上省略,這段代碼主要是用于ota_update插件的
       <provider
            android:name="sk.fourq.otaupdate.OtaUpdateFileProvider"
            android:authorities="${applicationId}.ota_update_provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths" />
        </provider>

    </application>

-然后在android/app/src/main/res文件夾內(nèi)新建文件夾xml再往里面添加一個filepaths.xml文件,內(nèi)容是

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_download" path="Download"/>
</paths>

到此有很多小伙伴就成功了。。但是這里面還有幾個大坑

六、還有哪些坑?

1、如果你安卓下載地址是http的那么恭喜你成功入坑。
安卓從sdk 27開始http訪問很多情況下會被禁止。如何做呢?
在上面的xml文件夾內(nèi)再新建一個文件network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

然后在AndroidManifest.xml的

    <application
        android:name="io.flutter.app.FlutterApplication"
        android:label="task todo"
        android:networkSecurityConfig="@xml/network_security_config"
        ...以下省略。添加上面一句用來執(zhí)行剛才添加的network_security_config.xml

然后大功告成。
2、有很多朋友這里會發(fā)現(xiàn)下載成功了。安裝卻失敗了,那么你又進(jìn)坑了。
我測試很多次發(fā)現(xiàn)這是模擬器的問題。模擬器無法直接安裝apk。你不用管。直接安裝到手機上去就行了。手機上可以安裝成功。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容