简体   繁体   中英

How to grant permission to access External Storage in Flutter

When I use the following line in my flutter code:

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

I get the following error:

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

I tried adding these to AndroidManifest.xml under manifest tab:

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

But it didnt work. I also tried re-running it after flutter clean but still I got the same result.

Can someone please help me to fix this issue.

My main goal is to be able to access(read/write) all the accessible directories present in the storage of an android/ios device. Just like our regular phones File Manager.

Thanks a lot for answering.

My recommendation is to avoid doing that.

Since Android 10, access to shared storage was very restricted trough the implementation of scoped storage . It's not allowed anymore to access files trough the file system path unless it's part of your limited scoped storage.

Unless accessing shared storage trough absolute paths is strictly necessary, you should be using Storage Access Framework or MediaStore API.

Android 11 will do nothing but enforce even more these restrictions.

All files access

The majority of apps that require shared storage access can follow scoped storage best practices such as the Storage Access Framework or MediaStore API. However, some apps have a core use case that requires broad access of files on a device, but cannot do so efficiently using the privacy-friendly storage best practices.

For example, an anti-virus app's primary use case might require regular scanning of many files across different directories. If this scanning requires repeated user interactions to select directories using the system file picker, it may provide a poor user experience. Other use cases—such as file manager apps, backup and restore apps, and document management apps—may require similar considerations.

An app can request a special app access called All files access from the user by doing the following:

Declare the MANAGE_EXTERNAL_STORAGE permission in the manifest. Use the ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION intent action to direct users to a system settings page where they can enable the following option for your app: Allow access to manage all files.

Take into account the requirements for an app to be able to use MANAGE_EXTERNAL_STORAGE as It's not allowed for everyone

Google Play restricts the use of high risk or sensitive permissions, including a special app access called All files access.

If your app does not require access to the all files access permission, you must remove it from your app's manifest in order to successfully publish your app. Details on policy-compliant alternative implementations are also detailed below.

If your app meets the policy requirements for acceptable use or is eligible for an exception, you will be required to declare this and any other high risk permissions using the Declaration Form in the Play Console.

Apps that fail to meet policy requirements or do not submit a Declaration Form may be removed from Google Play. https://support.google.com/googleplay/android-developer/answer/9956427?hl=en

add path_provider as a dependency in your pubspec.yaml file:

path_provider 1.6.11

Use it as follows, eg

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

You need to create a native channel for that purpose and invoke the native code from flutter and receive a response. Just google, you will find many guides to implement

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),
      ),
    );
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM