项目场景:
在Flutter项目中使用flutter_downloader: ^1.9.1
下载apk文件,小米手机提示下载成功但是通知栏进度条卡住并且未跳出安装apk的窗口。
当前Android项目包名:com.app.update.demo
问题描述
下载更新app提示“下载成功!”,但是执行语句
OpenResult openResult= await OpenFile.open(file.path,type: 'application/vnd.android.package-archive');
时报错:ResultType.fileNotFound
。下载保存地址为:/storage/emulated/0/Android/data/com.app.update.demo/files/my_app/my_app_1668582134848.apk
,可是在文件管理器中找到my_app_1668582134848.apk文件实际保存地址为:/storage/emulated/0/Download/my_app_1668582134848.apk
,与目标位置不一致所以报错找不到文件
upDateApp() async {
if (Platform.isIOS) {
if (await canLaunchUrl(Uri.parse(XConfig.appStoreUrl))) {
await launchUrl(Uri.parse(XConfig.appStoreUrl));
} else {
throw ('无效的url');
}
} else if (Platform.isAndroid) {
bool isStorage = await PreferenceUtils.requestStoragePermission();
if (!isStorage) {
Fluttertoast.showToast(
msg: "未开启手机储权限",
gravity: ToastGravity.CENTER,
);
return;
}
var times = DateTime.now().millisecondsSinceEpoch;
var fileName = 'my_app_$times.apk';
_bindBackgroundIsolate(fileName);
FlutterDownloader.registerCallback(downloadCallback);
var savedDir = await _prepareSaveDir();
File file = File(Uri.encodeFull(savedDir + '/' + fileName));
if (await file.exists()) await file.delete();
FlutterDownloader.enqueue(
url: XConfig.androidApkUrl + '?time=$times',
headers: {"auth": "test_for_sql_encoding"},
savedDir: savedDir,
fileName: fileName,
showNotification: true,
saveInPublicStorage: true,
openFileFromNotification: true);
}
}
void _bindBackgroundIsolate(String name) {
final ReceivePort _port = ReceivePort();
bool isSuccess = IsolateNameServer.registerPortWithName(
_port.sendPort, 'downloader_send_port_app');
if (!isSuccess) {
_unbindBackgroundIsolate();
_bindBackgroundIsolate(name);
return;
}
_port.listen((dynamic data) async {
String? id = data[0];
DownloadTaskStatus? status = data[1];
double progress = data[2] / 100;
if (status == DownloadTaskStatus.running) {
EasyLoading.showProgress(progress, status: '正在下载最新版本');
}
if (status == DownloadTaskStatus.failed) {
EasyLoading.showError('下载失败,请稍后再试!');
EasyLoading.dismiss();
}
if (status == DownloadTaskStatus.complete && id != null) {
EasyLoading.showSuccess('下载成功!');
EasyLoading.dismiss();
var savedDir = await _prepareSaveDir();
var filePath = '$savedDir/$name';
File file =File(Uri.encodeFull(filePath));
OpenResult openResult= await OpenFile.open(file.path,
type: 'application/vnd.android.package-archive');
print(openResult.message);
}
});
}
_prepareSaveDir() async {
String _localPath = (await _findLocalPath())! + '/my_app';
final savedDir = Directory(Uri.encodeFull(_localPath));
bool hasExisted = await savedDir.exists();
if (!hasExisted) {
savedDir.createSync();
}
return _localPath;
}
void _unbindBackgroundIsolate() {
IsolateNameServer.removePortNameMapping('downloader_send_port_app');
}
Future<String?> _findLocalPath() async {
var externalStorageDirPath;
if (Platform.isAndroid) {
final directory = await getExternalStorageDirectory();
externalStorageDirPath = directory?.path??await getTemporaryDirectory();
} else if (Platform.isIOS) {
externalStorageDirPath =
(await getApplicationDocumentsDirectory()).absolute.path;
}
return externalStorageDirPath;
}
原因分析:
小米手机MIUI针对下载保存的apk文件进行了另存,并且删除了原路径的文件
解决方案:
在下载成功以后根据下载目标路径判断当前文件是否存在,如果不存在则使用小米系统下载保存路径+文件名重试:/storage/emulated/0/Download/文件名.apk
if (status == DownloadTaskStatus.complete && id != null) {
EasyLoading.showSuccess('下载成功!');
EasyLoading.dismiss();
var savedDir = await _prepareSaveDir();
var filePath = '$savedDir/$name';
File file =File(Uri.encodeFull(filePath));
if(file.existsSync()){
print(file.path);
}else{
// 小米手机下载完成后会将文件移动到/storage/emulated/0/Download/路径下
var xiaomiPath= filePath.replaceAll("Android/data/com.app.update.demo/files/my_app/", "Download/");
file =File(Uri.encodeFull(xiaomiPath));
}
OpenResult openResult= await OpenFile.open(file.path,
type: 'application/vnd.android.package-archive');
print(openResult.message);
}
创作不易,请作者喝杯咖啡: