簡體   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