即使授予存储权限后,在三星手机上创建目录也被拒绝
Posted
技术标签:
【中文标题】即使授予存储权限后,在三星手机上创建目录也被拒绝【英文标题】:Create directory denied on Samsung phone even after Storage Permissions are granted 【发布时间】:2020-12-03 20:17:03 【问题描述】:在我的应用程序启动时,我在存储中创建了一个文件夹。为了实现这一点,我在initState()
内请求权限。只有完成后,目录检查才能继续进行。
@override
void initState()
super.initState();
easyDir = Directory(widget.folderPath);
getPermissionStatus().whenComplete(()
setState(()
//never call async operations in setState, do it in a function call.
directoryCheck();
);
);
folderPath
由permission_handler
包生成。我的手机是/storage/emulated/0/Documents/easyFolder
//check if directory exists, create if not.
Future<void> directoryCheck() async
// using awaits fixed my problem of setstate being called before
// directory was created.. and calling setState at end
exists = await easyDir.exists();
if (!exists)
await new Directory(widget.folderPath).create(recursive: true);
exists = true;
setState(()
);
Future<void> getPermissionStatus() async
_status = await Permission.storage.status;
// if permission is not granted yet, request it and update _status
if (_status != PermissionStatus.granted)
await Permission.storage.request();
_status = await Permission.storage.status;
这在模拟器上按预期工作。应用程序在启动时请求权限,等待它完成,并在允许时创建目录。
但是当安装在我的三星手机甚至朋友手机(三星)上时,由于权限被拒绝,即使在授予权限后也无法创建文件夹。
这是我在三星手机上收到的错误:
E/flutter (23275): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: FileSystemException: Creation failed, path = '/storage/emulated/0/Documents' (OS Error: Permission denied, errno = 13)
我在应用程序启动时明确给予了许可。更重要的是,当我进入我的应用程序的 appinfo 时,它显示已授予 Storage
权限。
我尝试在华为和小米手机上安装它,并且都按预期工作。
我在这里做错了什么?
这是我的AndroindManifest
中的权限行
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
如果有帮助,这里是错误堆栈:
E/flutter (23275): #0 _Directory.create.<anonymous closure> (dart:io/directory_impl.dart:124:11)
E/flutter (23275): #1 _rootRunUnary (dart:async/zone.dart:1192:38)
E/flutter (23275): #2 _CustomZone.runUnary (dart:async/zone.dart:1085:19)
E/flutter (23275): #3 _FutureListener.handleValue (dart:async/future_impl.dart:141:18)
E/flutter (23275): #4 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:682:45)
E/flutter (23275): #5 Future._propagateToListeners (dart:async/future_impl.dart:711:32)
E/flutter (23275): #6 Future._completeWithValue (dart:async/future_impl.dart:526:5)
E/flutter (23275): #7 Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:556:7)
E/flutter (23275): #8 _rootRun (dart:async/zone.dart:1184:13)
E/flutter (23275): #9 _CustomZone.run (dart:async/zone.dart:1077:19)
E/flutter (23275): #10 _CustomZone.runGuarded (dart:async/zone.dart:979:7)
E/flutter (23275): #11 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1019:23)
E/flutter (23275): #12 _microtaskLoop (dart:async/schedule_microtask.dart:43:21)
E/flutter (23275): #13 _startMicrotaskLoop (dart:async/schedule_microtask.dart:52:5)
E/flutter (23275):
【问题讨论】:
您究竟在哪里请求权限?您在模拟器和三星手机上运行的 Android 版本是什么? 您应该向我们展示getPermissionStatus()
的作用,就像@EdwynZN 指出的那样,否则您不太可能获得进一步的帮助。此外,您应该避免在不知道您是否获得许可的情况下继续进行,因为 whenComplete 实际上是一个“finally”块,这意味着它将始终被执行。 “whenComplete 方法......注册一个函数,当这个未来完成时被调用。当这个未来完成时,这个动作函数被调用,无论它是用一个值还是一个错误。” source
Android 10/Q 无法在手机上运行?
我已经用附加代码更新了我的问题。模拟器运行的是 Android 版本 11。而我的三星手机运行的是 Android 版本 10
@Uroš,谢谢,为此我将whencomplete()
放在那里。你建议我用什么来代替它?
【参考方案1】:
我觉得奇怪的是代码在 Android 11 但不是 10 中运行良好,因为新的作用域存储在Android 10 (Q)
及更高版本中写入权限应该失败
现在尝试在您的清单中选择退出 Android 10 中的范围存储(这在 Android 11 中不起作用),
<manifest ... >
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<!-- This attribute is "false" by default on apps targeting
Android 10 or higher. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
注意:将应用更新为面向 Android 11(API 级别 30)、系统忽略requestLegacyExternalStorage属性 当您的应用在 Android 11 设备上运行时,您的应用必须 准备好支持范围存储并为用户迁移应用数据 那些设备。
More info about Scoped Storage here
现在有一些问题可以帮助您解决这个问题:
文件夹路径由权限处理程序生成
我不记得权限处理程序在请求权限时返回路径,您能否详细说明如何获得widget.folderPath
?
模拟器运行的是 Android 版本 11。而我的三星手机是 在 Android 版本 10 上
华为和小米设备怎么样,它们也运行 Android 10 吗?
你在 gradle 中的 compileSdkVersion
/targetSdkVersion
或 AndroidManifest 中的 targetSdk
是什么?
【讨论】:
android:requestLegacyExternalStorage="true"
已修复。非常感谢你,你让我免于头疼:)
当心这个解决方案是临时的,当 Android 11 发布时这将不起作用,你将不得不做一些本机代码,因为现在连 path_provider 都坏了
那很不幸..我不知道编写本机代码。在这个阶段我能做些什么来避免进一步的头痛?还是我唯一的选择是等待path_provider
更新修复?
好吧,我还在等他们修复 path_provider,现在人们一直在做他们自己的包,比如 android_path_provider 或 download_path,也许你应该检查一下,这就是我们现在所能做的一切
Not working in android 11 man ...我正在使用 DIO 从 url 保存图像但不允许我出现此错误(操作系统错误:不允许操作,errno = 1)以上是关于即使授予存储权限后,在三星手机上创建目录也被拒绝的主要内容,如果未能解决你的问题,请参考以下文章
即使用户授予位置权限检查,三星 note 20 也总是会被拒绝
Android kotlin:即使在授予权限后也获得 EACCES(权限被拒绝)
JDBC连接:即使所有Previlleges都被授予,用户也被拒绝访问[关闭]