简体   繁体   English

限制访问外部存储,android < 10

[英]Restricted access to external storage, android < 10

I want to read and write files in user storage in android < 10 that applied Scoped storage and for some reason, I cannot use the privacy-friendly storage access for that therefore I need to use All files access permission.我想在应用Scoped storage的 android < 10 中的用户存储中读取和写入文件,出于某种原因,我无法为此使用隐私友好的存储访问权限,因此我需要使用All files access权限。 For getting the permission I'm using the Permission Handler package and calling the Permission.manageExternalStorage.request() like the following:为了获得许可,我使用Permission Handler程序 package 并调用Permission.manageExternalStorage.request() ,如下所示:

Future<void> _requestManageExternalStorage() async {
  if(!await Permission.manageExternalStorage.isGranted) {
    await Permission.manageExternalStorage.request();
  }
}

Alas, once I called that method this is what I got: No permissions found in manifest for: []22 las,一旦我调用该方法,这就是我得到的: No permissions found in manifest for: []22

As for the permissions list within Android Manifest.xml :至于Android Manifest.xml中的权限列表:

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

note that I put it in the correct location, which is in /android/app/src/main/AndroidManifest.xml with that being said, the output given by the Permission Handler is pretty much non-sense.请注意,我把它放在了正确的位置,在/android/app/src/main/AndroidManifest.xml中,据说,权限处理程序给出的 output 几乎是无意义的。 I tried to clean the projects with flutter clean and even create a new project only to test it but it still failed to retrieve the wanted permission.我尝试使用flutter clean项目,甚至创建一个新项目只是为了测试它,但它仍然无法检索到所需的权限。

I tried to check what actually is the current permission status for manageExternalStorage which I got: PermissionStatus.restricted我试图检查我得到的 manageExternalStorage 的当前权限状态实际上是什么: PermissionStatus.restricted

From the documentation PermissionStatus.restricted means:从文档 PermissionStatus.restricted 意味着:

The OS denied access to the requested feature.操作系统拒绝访问请求的功能。 The user cannot change this app's status, possibly due to active restrictions such as parental controls being in place.用户无法更改此应用程序的状态,这可能是由于存在家长控制等活动限制。 Only supported on iOS.仅支持 iOS。

From that, I can only assume that the OS is forcefully denied the All Files Access?由此,我只能假设操作系统被强制拒绝所有文件访问?

I'm using permission_handler: ^8.2.5 which at the time writing this is the latest version.我正在使用permission_handler: ^8.2.5 ,在撰写本文时这是最新版本。

The full code I use to test:我用来测试的完整代码:

import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool isGranted = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'Manage External Storage Test:',
            ),
            Text(
              'Is granted: $isGranted',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _requestManageExternalStorage,
      ),
    );
  }

  Future<void> _requestManageExternalStorage() async {
    if(!await Permission.manageExternalStorage.isGranted) {
      final res = await Permission.manageExternalStorage.request();
      setState((){
        isGranted = res.isGranted;  
      });
    }
  }
}

Full AndroidManifest.xml:完整的 AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.file_access_test">

    <!-- Permissions options for the `storage` group -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <!-- Permissions options for the `manage external storage` group -->
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

    <application
        android:name="io.flutter.app.FlutterApplication"
        android:icon="@mipmap/ic_launcher"
        android:label="MAKE IT DAMN WORK"
        tools:ignore="AllowBackup,GoogleAppIndexingWarning">

        <activity android:name="io.flutter.embedding.android.FlutterActivity"
            android:launchMode="singleTop"
            android:theme="@android:style/Theme.Black.NoTitleBar"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
</manifest>

Any insight or help is very appreciated!非常感谢任何见解或帮助! tested in android 10在 android 10 中测试

The android.permission.MANAGE_EXTERNAL_STORAGE permission is introduced with Android 11 (API 30) and therefore not supported on Android 10 or lower (see official documentation ). android.permission.MANAGE_EXTERNAL_STORAGE权限是在 Android 11 (API 30) 中引入的,因此在 Android 10 或更低版本上不受支持(请参阅官方文档)。

The permission_handler plugin returns PermissionStatus.restricted because it doesn't know how to handle the permission on Android 10 and below. permission_handler 插件返回PermissionStatus.restricted因为它不知道如何处理 Android 10 及以下版本的权限。 In case of Android 10 and lower simply restrict to requesting the android.permission.READ_EXTERNAL_STORAGE and android.permission.WRITE_EXTERNAL_STORAGE permissions.对于 Android 10 及更低版本,只需限制请求android.permission.READ_EXTERNAL_STORAGEandroid.permission.WRITE_EXTERNAL_STORAGE权限。

The log message is printed because the android.permission.MANAGE_EXTERNAL_STORAGE permission is not returned as part of the array returned by the Context.getPackageInfo().requestedPermissions API.打印日志消息是因为android.permission.MANAGE_EXTERNAL_STORAGE权限没有作为Context.getPackageInfo().requestedPermissions API 返回的数组的一部分返回。 Therefore the permission_handler plugin thinks the permission is not listed in the AndroidManifest.xml file.因此permission_handler 插件认为该权限未在AndroidManifest.xml 文件中列出。 In this case this is of course not entirely true, however my assumption is that Android filters out permissions that don't apply on the current Android version.在这种情况下,这当然不完全正确,但我的假设是 Android 会过滤掉不适用于当前 Android 版本的权限。

As maintainer of the permission_handler plugin I will make sure the log message gets updated so it takes this option also into account.作为permission_handler 插件的维护者,我将确保日志消息得到更新,因此它也考虑了这个选项。

This is how I implemented it.这就是我实现它的方式。 I am basically checking which version of SDK is the android device using.我基本上是在检查 SDK 的哪个版本是 android 设备使用的。 If the device is below Android 11, we'll ask for basic permission.如果设备低于 Android 11,我们将请求基本权限。 If the device is android 11 or above, then we'll ask for manage external storage, also.如果设备是 android 11 或以上,那么我们也会要求管理外部存储。 I am using a bool to know if the device got the right permissions.我正在使用 bool 来了解设备是否获得了正确的权限。 In my test, it works.在我的测试中,它有效。

Future<bool> getPermissions() async {
    bool gotPermissions = false;

    var androidInfo = await DeviceInfoPlugin().androidInfo;
    var release = androidInfo.version.release; // Version number, example: Android 12
    var sdkInt = androidInfo.version.sdkInt; // SDK, example: 31
    var manufacturer = androidInfo.manufacturer;
    var model = androidInfo.model;

    print('Android $release (SDK $sdkInt), $manufacturer $model');

    if (Platform.isAndroid) {
        var storage = await Permission.storage.status;

        if (storage != PermissionStatus.granted) {
            await Permission.storage.request();
        }

        if (sdkInt >= 30) {
            var storage_external = await Permission.manageExternalStorage.status;

            if (storage_external != PermissionStatus.granted) {
                await Permission.manageExternalStorage.request();
            }

            storage_external = await Permission.manageExternalStorage.status;

            if (storage_external == PermissionStatus.granted 
                && storage == PermissionStatus.granted) {
                gotPermissions = true;
            }
        } else {
            // (SDK < 30)
            storage = await Permission.storage.status;

            if (storage == PermissionStatus.granted) {
                gotPermissions = true;
            }
        }
    }

    return gotPermissions;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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