flutter 实现app升级

准备工作

遇到问题

flutter_bugly
这个方法FlutterBugly.checkUpgrade(isManual:true,isSilence:true),UpgradeInfo 一直返回null。
下面是打印出来的log
D/CrashReport(31776): [Upload] Bugly version from headers is: bugly/1.0
D/CrashReport(31776): [Upload] Status from server is 0 (pid=31776 | tid=31843).
D/CrashReport(31776): [Upload] Received 127 bytes
D/CrashReport(31776): [Util] Unzip 111 bytes data with type Gzip
D/CrashReport(31776): [Upload] Response cmd is: 0, length of sBuffer is: 0
D/CrashReport(31776): [Database] insert t_pf success.
I/CrashReport(31776): [Upload] Success: 804
D/CrashReport(31776): [UploadManager] Local network consume: 30 KB
D/CrashReport(31776): [Database] deleted t_lr data 1
D/CrashReport(31776): [Database] insert t_lr success.
D/CrashReport(31776): [UploadManager] Network total consume: 31 KB
I/CrashReport(31776): upload succ:[804] [sended 775] [recevied 127]
I/CrashReport(31776): 你已放弃让SDK来处理策略
I/CrashReport(31776): betaStrategy is null
I/CrashReport(31776): 用户自定义activity,创建task失败 [strategy:null]
  • 解决方案:
    在本地打包设置版本名称和版本号 pubspec.yaml,打包上传到腾讯bugly 应用升级里面
    在这里插入图片描述
    在这里插入图片描述
    上传的构建版本必须比本地的大,把本地版本更改回去1.0.0+1 继续测试升级功能,就能获取到。
flutter_bugly 和 open_file AndroidManifest.xml 合并冲突报错
  • 仔细查看open_file readme 在 /android/app/src/main/AndroidManifest.xml 添加
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools" // 添加+++
          package="xxx.xxx.xxxxx">
    <application>
        ...
        // 添加+++
        <provider
                android:name="androidx.core.content.FileProvider"
                android:authorities="${applicationId}.fileProvider"
                android:exported="false"
                android:grantUriPermissions="true"
                tools:replace="android:authorities">
            <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/filepaths"
                    tools:replace="android:resource" />
        </provider>
        // 结束+++
    </application>
</manifest>

app-update.dart

import 'package:ZyFlutter/utils/update_dialog.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bugly/flutter_bugly.dart';
import 'package:open_file/open_file.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:path_provider/path_provider.dart';
import 'package:uuid/uuid.dart';
import 'package:dio/dio.dart';

//toast
import 'package:fluttertoast/fluttertoast.dart';

/// app升级
class AppUpdate {
  // app升级
  String _platformVersion = 'Unknown';
  GlobalKey<UpdateDialogState> _dialogKey = new GlobalKey();

  // 初始化app
  initUpgradeApp(BuildContext context) {
    // 初始化app升级
    FlutterBugly.init(
      androidAppId: '',
      iOSAppId: '',
    ).then((_result) {
      _platformVersion = _result.message;
      FlutterBugly.setUserId('');
      FlutterBugly.putUserData(key: 'name', value: 'zhoukai');
      int tag = 9527;
      FlutterBugly.setUserTag(tag);
      checkUpgrade(context);
    });
  }

  // 显示弹出信息
  void showUpdateDialog(
      String version,
      String url,
      bool isForceUpgrade,
      String title,
      int fileSize,
      int pubTime,
      String content,
      BuildContext contex) {
    showDialog(
        context: contex,
        barrierDismissible: false,
        builder: (_) => _buildDialog(version, url, isForceUpgrade, title,
            fileSize, pubTime, content, contex));
  }

  Widget _buildDialog(
      String version,
      String url,
      bool isForceUpgrade,
      String title,
      int fileSize,
      int pubTime,
      String content,
      BuildContext context) {
    return WillPopScope(
      onWillPop: () async => isForceUpgrade,
      child: UpdateDialog(
        key: _dialogKey,
        version: version,
        title: title,
        content: content,
        pubTime: pubTime,
        fileSize: fileSize,
        onClickWhenDownload: (_msg) {
          // 提示不要重复下载
          Fluttertoast.showToast(msg: _msg);
        },
        onClickWhenNotDownload: () {
          // 下载apk, 完成打开apk文件,建议使用dio+open_file插件
          requestPermiss(context).then((value) {
            if (value) {
              // 获取存储路径
              getPhoneLocalPath(context).then((result) {
                var uuid = Uuid();
                String name = uuid.v4().replaceAll('-', '');
                // 生成唯一的文件名
                String appName = '${result}/${name}.apk';
                downApk(url, appName);
              });
            }
          });
        },
      ),
    );
  }

  ///dio下载apk文件
  void downApk(String url, String localPath) {
    var dio = new Dio();
    try {
      dio.download(url, localPath, onReceiveProgress: (received, total) {
        double progress = received / total;
        _updateProgress(received / total);
        // 下载完毕直接打开apk
        if (progress == 1) {
          OpenFile.open(localPath);
        }
      });
    } catch (err) {
      Fluttertoast.showToast(msg: '下载失败!!!');
    }
  }

  // dio可以监听下载进度,调用此方法
  void _updateProgress(_progress) {
    _dialogKey.currentState.progress = _progress;
  }

  // 检查升级
  void checkUpgrade(BuildContext context) {
    print('获取更新中.....');
    FlutterBugly.checkUpgrade().then((UpgradeInfo info) {
      print(info);
      print('*********************检查版本');
      if (info != null && info.id != null) {
        print("----------------${info.apkUrl}");
        showUpdateDialog(
          info.versionName,
          info.apkUrl,
          info.upgradeType == 2,
          info.title,
          info.fileSize,
          info.publishTime,
          info.newFeature,
          context,
        );
      }
    });
  }

  // 获取文件存储位置

  ///PermissionGroup.storage 对应的是
  ///android 的外部存储 (External Storage)
  ///ios 的Documents` or `Downloads`
  // 申请权限存储权限
  Future requestPermiss(BuildContext context) async {
    // 查看存储权限是否存在
    var status = await Permission.storage.status;
    if (!status.isGranted) {
      // 申请权限
      Map<Permission, PermissionStatus> statuses =
          await [Permission.storage].request();
      // 用户拒绝,不提醒,直接跳转到设置,手动开启权限
      if (!statuses[Permission.storage].isGranted) {
        Fluttertoast.showToast(msg: '请打开存储权限!!!');
        openAppSettings();
        return false;
      } else {
        return true;
      }
    } else {
      return true;
    }
  }

  /// 获取手机的存储目录路径
  Future<String> getPhoneLocalPath(BuildContext context) async {
    final directory = Theme.of(context).platform == TargetPlatform.android
        ? await getExternalStorageDirectory()
        : await getApplicationDocumentsDirectory();
    return directory.path;
  }
}

update_dialog.dart

import 'package:flutter/material.dart';

class UpdateDialog extends StatefulWidget {
  // key
  final key;
  // 版本
  final version;
  // 标题
  final String title;
  // 文件大小
  final int fileSize;
  // 发布日期
  final int pubTime;
  // 更新内容
  final String content;
  final Function onClickWhenDownload;
  final Function onClickWhenNotDownload;

  UpdateDialog({
    this.key,
    this.version,
    this.title,
    this.content,
    this.fileSize,
    this.pubTime,
    this.onClickWhenDownload,
    this.onClickWhenNotDownload,
  });

  @override
  State<StatefulWidget> createState() => new UpdateDialogState();
}

class UpdateDialogState extends State<UpdateDialog> {
  var _downloadProgress = 0.0;

  @override
  Widget build(BuildContext context) {
    var _textStyle =
        new TextStyle(color: Theme.of(context).textTheme.body1.color);

    return new AlertDialog(
      title: new Text(
        widget.title,
        style: _textStyle,
      ),
      content: _downloadProgress == 0.0
          ? new Text(
              "版本${widget.version}\n${widget.content}",
              style: _textStyle,
            )
          : new LinearProgressIndicator(
              value: _downloadProgress,
            ),
      actions: <Widget>[
        new FlatButton(
          child: new Text(
            '更新',
            style: _textStyle,
          ),
          onPressed: () {
            if (_downloadProgress != 0.0) {
              widget.onClickWhenDownload("正在更新中");
              return;
            }
            widget.onClickWhenNotDownload();
//            Navigator.of(context).pop();
          },
        ),
        new FlatButton(
          child: new Text('取消'),
          onPressed: () {
            Navigator.of(context).pop();
          },
        ),
      ],
    );
  }

  set progress(_progress) {
    setState(() {
      _downloadProgress = _progress;
      if (_downloadProgress == 1) {
        Navigator.of(context).pop();
        _downloadProgress = 0.0;
      }
    });
  }
}
©️2020 CSDN 皮肤主题: 数字20 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值