flutter 实现app升级
准备工作集成flutter_bugly集成permission_handler获取权限集成path_provider 获取外部存储路径集成open_file打开文件遇到问题flutter_bugly这个方法FlutterBugly.checkUpgrade(isManual:true,isSilence:true),UpgradeInfo 一直返回null。下面是打印出来的logD/CrashRe
·
准备工作
- 集成flutter_bugly
- 集成permission_handler获取权限
- 集成path_provider 获取外部存储路径
- 集成open_file打开文件
- flutter使用toast
- 生成uuid
- 使用dio实现文件下载并且监听进度 地址
遇到问题
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;
}
});
}
}
更多推荐
所有评论(0)