繁体   English   中英

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

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

我想在应用Scoped storage的 android < 10 中的用户存储中读取和写入文件,出于某种原因,我无法为此使用隐私友好的存储访问权限,因此我需要使用All files access权限。 为了获得许可,我使用Permission Handler程序 package 并调用Permission.manageExternalStorage.request() ,如下所示:

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

las,一旦我调用该方法,这就是我得到的: No permissions found in manifest for: []22

至于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" />

请注意,我把它放在了正确的位置,在/android/app/src/main/AndroidManifest.xml中,据说,权限处理程序给出的 output 几乎是无意义的。 我尝试使用flutter clean项目,甚至创建一个新项目只是为了测试它,但它仍然无法检索到所需的权限。

我试图检查我得到的 manageExternalStorage 的当前权限状态实际上是什么: PermissionStatus.restricted

从文档 PermissionStatus.restricted 意味着:

操作系统拒绝访问请求的功能。 用户无法更改此应用程序的状态,这可能是由于存在家长控制等活动限制。 仅支持 iOS。

由此,我只能假设操作系统被强制拒绝所有文件访问?

我正在使用permission_handler: ^8.2.5 ,在撰写本文时这是最新版本。

我用来测试的完整代码:

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

完整的 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>

非常感谢任何见解或帮助! 在 android 10 中测试

android.permission.MANAGE_EXTERNAL_STORAGE权限是在 Android 11 (API 30) 中引入的,因此在 Android 10 或更低版本上不受支持(请参阅官方文档)。

permission_handler 插件返回PermissionStatus.restricted因为它不知道如何处理 Android 10 及以下版本的权限。 对于 Android 10 及更低版本,只需限制请求android.permission.READ_EXTERNAL_STORAGEandroid.permission.WRITE_EXTERNAL_STORAGE权限。

打印日志消息是因为android.permission.MANAGE_EXTERNAL_STORAGE权限没有作为Context.getPackageInfo().requestedPermissions API 返回的数组的一部分返回。 因此permission_handler 插件认为该权限未在AndroidManifest.xml 文件中列出。 在这种情况下,这当然不完全正确,但我的假设是 Android 会过滤掉不适用于当前 Android 版本的权限。

作为permission_handler 插件的维护者,我将确保日志消息得到更新,因此它也考虑了这个选项。

这就是我实现它的方式。 我基本上是在检查 SDK 的哪个版本是 android 设备使用的。 如果设备低于 Android 11,我们将请求基本权限。 如果设备是 android 11 或以上,那么我们也会要求管理外部存储。 我正在使用 bool 来了解设备是否获得了正确的权限。 在我的测试中,它有效。

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