即使授予存储权限后,在三星手机上创建目录也被拒绝

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

folderPathpermission_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都被授予,用户也被拒绝访问[关闭]

即使在 Ar.js 中的浏览器中授予权限后,地理定位访问被拒绝弹出窗口也会显示

Postgres:即使授予了授权,也拒绝架构的权限