我需要打开一个文件,这是我的应用程序中的附件,这些文件可以是任何类型的真的,图像,视频,PDF,EXCEL文件… Android 13拥有读_媒体_图像、读_媒体_视频和读_媒体_音频的权限,可以通过permission_handler:

[Permission.photos, Permission.videos, Permission.audio].request()

之后,当我可以用open_file包打开从通知下载的文件时:

OpenFile.open(path)

但当我试图打开一个pdf文件时,它就是不起作用.它给了我一个错误: Permission denied: android.permission.MANAGE_EXTERNAL_STORAGE flutter

这种权限在设置中被永久拒绝,而且每当我需要从通知中打开文件时,用户都不会直观地将他发送到应用程序.另外,我读到了here,我不能把它放在货单上,因为它会被Play Store拒绝.

如果您能帮我解决这个问题,下面是代码:

import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:open_file/open_file.dart';
import 'package:pagedesk/data/model/ticket/attachemnt_item.dart';
import 'package:pagedesk/data/network/firebase_api.dart';
import 'package:pagedesk/utils/Utils.dart';
import 'package:pagedesk/view_model/ticket_attachemnts_view_model.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';

class Notifications {
  int maxProgress = 5;
  bool isCompleted = false;

  Future getDownloadNotification(
      AttachemntItem item,
      String downloadingText,
      String downloadCompletedText,
      String downoadFaildMessage,
      String cantOpenFailMessage,
      TicketAttachemntsViewModel viewModel) async {
    final AndroidNotificationDetails androidNotificationDetails =
        AndroidNotificationDetails(
      'name',
      'name',
      channelDescription: 'progress channel description',
      channelShowBadge: false,
      importance: Importance.max,
      priority: Priority.high,
      onlyAlertOnce: true,
      showProgress: false,
    );
    final NotificationDetails notificationDetails =
        NotificationDetails(android: androidNotificationDetails);

    String newPath = "";

    Directory directory;
    try {
      if (Platform.isAndroid) {
        if (await requestStoragePermissions()) {
          directory = (await getExternalStorageDirectory())!;
          print(directory);
          List<String> paths = directory.path.split("/");
          for (int x = 1; x < paths.length; x++) {
            String folder = paths[x];
            if (folder != "Android") {
              newPath += "/$folder";
            } else {
              break;
            }
          }
          newPath = "$newPath/Download";
          directory = Directory(newPath);
        } else {
          return;
        }
      } else {
        if (await _requestPermission(Permission.storage)) {
          directory = await getApplicationDocumentsDirectory();
        } else {
          return;
        }
      }

      if (!await directory.exists()) {
        await directory.create(recursive: true);
      }

      String filename = item.name;
      String path = directory.path;
      print('FILENAME: $filename');
      print('OATH: $path');

      File file = File('$path/$filename');
      if (await file.exists()) {
        int suffix = 1;
        String newFileName;
        while (await file.exists()) {
          newFileName =
              '${filename.replaceAll(RegExp(r'\..+'), '')}($suffix)${filename.substring(filename.lastIndexOf('.'))}';

          file = File('$path/$newFileName');
          suffix++;
        }
      } else {
        print("File doesn't exist");
      }

      FirebaseApi.localNotifications.show(
          item.id,
          item.name,
          isCompleted ? downloadCompletedText : downloadingText,
          notificationDetails,
          payload: newPath);
      viewModel.getAttachment(item).then((value) => {
            if (value != null)
              {
                file.writeAsBytes(value),
                isCompleted = true,
                FirebaseApi.localNotifications.cancel(item.id),
                FirebaseApi.localNotifications.show(item.id, item.name,
                    downloadCompletedText, notificationDetails,
                    payload: file.path)
              }
            else
              {
                isCompleted = false,
                FirebaseApi.localNotifications.cancel(item.id),
                FirebaseApi.localNotifications.show(item.id, item.name,
                    downoadFaildMessage, notificationDetails,
                    payload: null)
              }
          });
    } catch (e) {
      print('ERROR');
    }
  }
}

void openFile(String path, String cantOpenFileMessage) async {
  try {
    final result = await OpenFile.open(path);
    if (result.type == ResultType.done) {
      print('File opened successfully');
    } else if (result.type == ResultType.noAppToOpen) {
      Utils.toastMessage(cantOpenFileMessage);
    } else {
      Utils.toastMessage("Can't open file throgh this app.");
    }
  } catch (e) {
    print('Error opening file: $e');
  }
}

Future<bool> _requestPermission(Permission permission) async {
  if (await permission.isGranted) {
    return true;
  } else if (await permission.isPermanentlyDenied) {
    openAppSettings();
    return false;
  } else {
    var result = await permission.request();
    if (result == PermissionStatus.granted) {
      return true;
    }
  }

  return false;
}

Future<bool> requestStoragePermissions() async {
  List<Permission> permissions = [];
  final deviceInfo = await DeviceInfoPlugin().androidInfo;

  if (deviceInfo.version.sdkInt > 32) {
    permissions = [Permission.photos, Permission.videos, Permission.audio];
  } else {
    permissions = [Permission.storage];
  }
  Map<Permission, PermissionStatus> statuses = await permissions.request();
  return !statuses.containsKey(false);
}

list 权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission. READ_MEDIA_AUDIO" />

推荐答案

我非常肯定(不是100%),因为这是一个默认被拒绝的新权限,您需要让用户通过其设置手动更改它,即使它对用户来说并不像您所说的那样直观.

我不知道你是否已经看到,你可以通过编程打开设置页面,这样对用户来说更容易.

不幸的是,我认为没有比这更好的解决方案了.

Flutter相关问答推荐

如何在应用程序启动时解析和加载JSON文件?

在Flutter TextField中计算子字符串位置

UI中的Flutter 下拉列表值未更改

我怎样才能在Ffltter中显示html布局链接?

使用Ffltter CREATE创建项目时,androidManifest.xml中缺少包属性

Flutter守护进程无法启动

集装箱堆放和定位时的高度问题

在 Flutter 中使用条件语句设置 ImageProvider Object 类型的背景图像

Flutter 包错误:此应用程序使用的是已弃用的 Android 嵌入版本

使用Flutter项目设置Firebase遇到困难?这些解决方案或许能帮到你!

在 Flutter 中更改喜欢按钮的 colored颜色

在 Flutter 中读取 Firebase 数据库数据时遇到问题

如何在 flutter 中使用 tabbar 作为底部导航栏?

Android: 从 URI 获取音频元数据

Flutter 中出现错误空判断运算符用于空值

Flutter:制作自定义小部件的最佳做法是什么?

gridview 的所有按钮都应该在Flutter 中适合其父容器

Flutter_riverpod 安装时出现问题

未处理的异常:FileSystemException:无法打开文件,路径 = 'assets/res.zip'(操作系统错误:没有这样的文件或目录,errno = 2)

如何从 Flutter 中的列表中提取 JSON?