Skip to content

Commit 3594e22

Browse files
committed
feat:Add APK installation permission handling and improved error messages
1 parent 7b867ea commit 3594e22

File tree

2 files changed

+107
-15
lines changed

2 files changed

+107
-15
lines changed

android/app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<uses-permission
2626
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
2727
tools:ignore="ScopedStorage" />
28+
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
2829

2930
<application
3031
android:name="com.github.openlistteam.openlistflutter.App"
@@ -85,4 +86,4 @@
8586
</receiver>
8687

8788
</application>
88-
</manifest>
89+
</manifest>

lib/utils/download_manager.dart

Lines changed: 105 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -356,11 +356,76 @@ class DownloadManager {
356356
return newPath;
357357
}
358358

359+
/// 检查是否为 APK 文件
360+
static bool _isApkFile(String filePath) {
361+
return filePath.toLowerCase().endsWith('.apk');
362+
}
363+
364+
/// 检查和请求安装权限
365+
static Future<bool> _checkInstallPermission() async {
366+
if (!Platform.isAndroid) return true;
367+
368+
try {
369+
// 检查是否有安装权限
370+
bool hasPermission = await Permission.requestInstallPackages.isGranted;
371+
372+
if (!hasPermission) {
373+
// 请求安装权限
374+
PermissionStatus status = await Permission.requestInstallPackages.request();
375+
376+
if (status.isGranted) {
377+
return true;
378+
} else if (status.isPermanentlyDenied) {
379+
// 权限被永久拒绝,引导用户到设置页面
380+
getx.Get.dialog(
381+
AlertDialog(
382+
title: const Text('需要安装权限'),
383+
content: const Text('为了安装 APK 文件,需要授予安装权限。请在设置中手动开���。'),
384+
actions: [
385+
TextButton(
386+
onPressed: () => getx.Get.back(),
387+
child: const Text('取消'),
388+
),
389+
TextButton(
390+
onPressed: () {
391+
getx.Get.back();
392+
openAppSettings();
393+
},
394+
child: const Text('去设置'),
395+
),
396+
],
397+
),
398+
);
399+
return false;
400+
} else {
401+
getx.Get.showSnackbar(const getx.GetSnackBar(
402+
message: '需要安装权限才能安装 APK 文件',
403+
duration: Duration(seconds: 3),
404+
));
405+
return false;
406+
}
407+
}
408+
409+
return true;
410+
} catch (e) {
411+
log('检查安装权限失败: $e');
412+
return true; // 如果检查失败,继续尝试打开
413+
}
414+
}
415+
359416
/// 尝试打开文件
360417
static Future<void> _openFile(String filePath) async {
361418
try {
362419
log('尝试打开文件: $filePath');
363420

421+
// 如果是 APK 文件,先检查安装权限
422+
if (_isApkFile(filePath)) {
423+
bool hasPermission = await _checkInstallPermission();
424+
if (!hasPermission) {
425+
return; // 没有权限,不继续打开
426+
}
427+
}
428+
364429
// 使用 open_filex 插件打开文件
365430
final result = await OpenFilex.open(filePath);
366431

@@ -372,16 +437,29 @@ class DownloadManager {
372437
// 文件成功打开,不需要额外提示
373438
break;
374439
case ResultType.noAppToOpen:
375-
getx.Get.showSnackbar(getx.GetSnackBar(
376-
message: '没有找到可以打开此文件的应用',
377-
duration: const Duration(seconds: 3),
378-
mainButton: TextButton(
379-
onPressed: () {
380-
_showFileLocation(filePath);
381-
},
382-
child: const Text('查看位置'),
383-
),
384-
));
440+
if (_isApkFile(filePath)) {
441+
getx.Get.showSnackbar(getx.GetSnackBar(
442+
message: '无法安装 APK 文件,可能需要在设置中开启"允许安装未知来源应用"',
443+
duration: const Duration(seconds: 5),
444+
mainButton: TextButton(
445+
onPressed: () {
446+
openAppSettings();
447+
},
448+
child: const Text('去设置'),
449+
),
450+
));
451+
} else {
452+
getx.Get.showSnackbar(getx.GetSnackBar(
453+
message: '没有找到可以打开此文件的应用',
454+
duration: const Duration(seconds: 3),
455+
mainButton: TextButton(
456+
onPressed: () {
457+
_showFileLocation(filePath);
458+
},
459+
child: const Text('查看位置'),
460+
),
461+
));
462+
}
385463
break;
386464
case ResultType.fileNotFound:
387465
getx.Get.showSnackbar(const getx.GetSnackBar(
@@ -390,10 +468,23 @@ class DownloadManager {
390468
));
391469
break;
392470
case ResultType.permissionDenied:
393-
getx.Get.showSnackbar(const getx.GetSnackBar(
394-
message: '没有权限打开此文件',
395-
duration: Duration(seconds: 3),
396-
));
471+
if (_isApkFile(filePath)) {
472+
getx.Get.showSnackbar(getx.GetSnackBar(
473+
message: '没有权限安装 APK 文件,请在设置中开启安装权限',
474+
duration: const Duration(seconds: 5),
475+
mainButton: TextButton(
476+
onPressed: () {
477+
openAppSettings();
478+
},
479+
child: const Text('去设置'),
480+
),
481+
));
482+
} else {
483+
getx.Get.showSnackbar(const getx.GetSnackBar(
484+
message: '没有权限打开此文件',
485+
duration: Duration(seconds: 3),
486+
));
487+
}
397488
break;
398489
case ResultType.error:
399490
default:

0 commit comments

Comments
 (0)