限制访问外部存储,安卓< 10



我想在android中读写用户存储中的文件<10应用Scoped storage,由于某种原因,我不能使用隐私友好的存储访问,因此我需要使用All files access权限。为了获得权限,我使用Permission Handler包并像下面这样调用Permission.manageExternalStorage.request():

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

唉,一旦我调用了这个方法,这就是我得到的: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中,也就是说,权限处理程序给出的输出几乎没有意义。我试图用flutter clean清理项目,甚至创建一个新项目只是为了测试它,但它仍然未能检索所需的权限。

我试图检查我得到的manageExternalStorage的当前权限状态:PermissionStatus.restricted

从文档PermissionStatus。限制的意思是:

操作系统拒绝访问请求的特性。用户不能更改此应用程序的状态,可能是由于积极的限制,如因为家长控制已经到位。仅支持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().requestedPermissionsAPI返回的数组的一部分返回。因此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;
}

最新更新