如何在Flutter中授予访问外部存储的权限

时间:2020-07-18 23:37:55

标签: android flutter dart

当我在flutter代码中使用以下行时:

print(Directory("/sdcard").list(recursive: true).listen((event) {print(event);}));

我收到以下错误:

"[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: FileSystemException: Directory listing failed, path = '/sdcard/' (OS Error: Permission denied, errno = 13)"

我尝试将它们添加到清单标签下的AndroidManifest.xml中:

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

但是没有用。我还尝试在清理干净后重新运行它,但仍然得到相同的结果。

有人可以帮我解决此问题。

我的主要目标是能够访问(读取/写入)存在于android / ios设备存储中的所有可访问目录。就像我们常规的手机文件管理器一样。

非常感谢您的回答。

4 个答案:

答案 0 :(得分:2)

我的建议是避免这样做。

自Android 10起,通过实施scoped storage限制了对共享存储的访问。除非它是有限范围存储的一部分,否则将不再允许通过文件系统路径访问文件。

除非绝对必须通过绝对路径访问共享存储,否则应使用Storage Access Framework或MediaStore API。

Android 11只会执行更多这些限制。

All files access

大多数需要共享存储访问的应用程序都可以遵循一定范围的存储最佳实践,例如存储访问框架或MediaStore API。但是,某些应用程序具有核心用例,该用例需要对设备上的文件进行广泛访问,但无法使用隐私友好的存储最佳做法来有效地做到这一点。

例如,防病毒应用程序的主要用例可能需要定期扫描不同目录中的许多文件。如果此扫描需要反复的用户交互以使用系统文件选择器选择目录,则可能会带来较差的用户体验。其他用例(例如文件管理器应用程序,备份和还原应用程序以及文档管理应用程序)可能需要类似的考虑。

应用程序可以执行以下操作,要求用户授予特殊的应用程序访问权限:所有文件访问权限:

在清单中声明MANAGE_EXTERNAL_STORAGE权限。 使用ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION意向操作将用户定向到系统设置页面,在此页面中,他们可以为您的应用启用以下选项:允许访问权限来管理所有文件。

请考虑到requirements,以便某个应用能够使用MANAGE_EXTERNAL_STORAGE,因为并非所有人都可以使用

Google Play限制使用高风险或敏感权限,包括特殊的应用访问权限,称为“所有文件访问”。

如果您的应用程序不需要访问所有文件的访问权限,则必须将其从应用程序清单中删除才能成功发布应用程序。下面还将详细介绍符合政策的替代实施。

如果您的应用符合可接受使用的政策要求或有资格获得例外,则将需要您使用Play控制台中的声明表单声明此许可以及任何其他高风险许可。

不符合政策要求或未提交声明表的应用可能会从Google Play中删除。 https://support.google.com/googleplay/android-developer/answer/9956427?hl=en

答案 1 :(得分:0)

在您的pubspec.yaml文件中添加path_provider作为依赖项:

path_provider 1.6.11

按如下方式使用它,例如

Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;`

答案 2 :(得分:0)

您需要为此创建一个本机频道 并从flutter中调用本机代码并接收响应。 只是google,您会发现许多实施指南

答案 3 :(得分:0)

import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:flutter/services.dart';
import 'package:path_provider_ex/path_provider_ex.dart';
import 'dart:io';
import 'package:permission_handler/permission_handler.dart';

class MyHomePage extends StatefulWidget {MyHomePage({Key key}) : super(key: key)@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();
    getPermission();
    getMobileStorageInfo();
  }
  int _counter = 0;
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  Future download2(Dio dio, String url, String savePath) async {
    try {
      Response response = await dio.get(
        url,
        onReceiveProgress: showDownloadProgress,
        //Received data with List<int>
        options: Options(
            responseType: ResponseType.bytes,
            followRedirects: false,
            validateStatus: (status) {
              return status < 500;
            }),
      );
      print(response.headers);
      File file = File(savePath);
      var raf = file.openSync(mode: FileMode.write);
      // response.data is List<int> type
      raf.writeFromSync(response.data);
      await raf.close();
    } catch (e) {
      print(e);
    }
  }
  List<StorageInfo> storageInfo;
  Future<List<StorageInfo>> getMobileStorageInfo() async {
    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      storageInfo = await PathProviderEx.getStorageInfo();
      print(storageInfo);
    } on PlatformException {}
    return storageInfo;
  }
  getPermission() async {
    if (await Permission.contacts.request().isGranted) {
      // Either the permission was already granted before or the user just granted it.
    } else {
// You can request multiple permissions at once.
      Map<Permission, PermissionStatus> statuses = await [
        Permission.storage,
      ].request();
      print(statuses[Permission.location]);
    }
  }

  void showDownloadProgress(received, total) {
    if (total != -1) {
      print((received / total * 100).toStringAsFixed(0) + "%");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(''),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RaisedButton.icon(
                onPressed: () async {
                  String fullPath =
                      '${storageInfo[0].rootDir}' + '/Download' + '/boo2.pdf';
                  // String fullPath;

                  print('full path ${fullPath}');
                  final imgUrl =
                      "https://api.aseztak.com/storage/invoice/ORD-5F606C9A927B4.pdf";
                  var dio = Dio();

                  download2(dio, imgUrl, fullPath);
                },
                icon: Icon(
                  Icons.file_download,
                  color: Colors.white,
                ),
                color: Colors.green,
                textColor: Colors.white,
                label: Text('Dowload Invoice')),
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}