安卓Q:file.mkdirs()返回false

33

我们有一个应用程序,使用外部存储器来存储一些临时文件:图像、二进制数据。这段代码已经运行了几年时间,没有大的更改,直到最近。在Android Q上它不能工作:

File f = new File(Environment.getExternalStorageDirectory().toString() + File.separator + MainActivity.APP_DIR)
f.mkdirs();
// do sth with f

mkdirs现在仅返回false

所需权限已在清单文件中提供:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

这段代码在之前的 Android 版本上可以正常工作。是否有某些系统级别的更改影响了此类型的访问? 如果是这样,有什么解决方法吗?


请参考以下答案:https://dev59.com/BVUL5IYBdhLWcg3wSmco#50571167 - Malek Tubaisaht
3个回答

63

在Android Q中引入了Scoped Storage,这是一项重大的隐私变更。

从Q beta 4开始,可以通过以下方式opt-out该功能:

  • 针对API 28(或更低版本)进行目标设置
  • 在目标API 29的情况下使用requestLegacyExternalStorage清单属性:

<manifest ... >
  <!-- This attribute is "false" by default on apps targeting Android Q. -->
  <application android:requestLegacyExternalStorage="true" ... >
    ...
  </application>
</manifest>

编辑:如其他答案所述,如果应用程序针对API 30,则此方法不起作用- Android 11设备将忽略旧存储标志。

编辑2:提醒任何计划在Play商店上发布应用程序的人- 不久将限制使用此标志(新的和更新的应用程序将不被接受),除非其对核心功能(例如文件管理器)是必需的。


他不是在要求安卓派吗?但我认为你正在解决安卓Q相关的问题。 - exploitr
@Toaster 你说得对,我回复的时候已经很晚了。由于某种奇怪的原因,我认为9已经是Q了。 - Pawel
哈哈,没关系。你有空的时候更新答案就好啦。 - exploitr
@khusrav,这就是我想到的,我没有看到为什么那段代码在P上不起作用,但知道在Q上会有问题。 - Pawel
@khusrav 好吧,那真是场灾难。:-D - exploitr
显示剩余3条评论

11

更新:自 Android 11 开始,强制使用了作用域存储。针对 Android 10(API 级别 29)的应用程序仍可以请求 requestLegacyExternalStorage 属性。此标志允许应用程序临时退出与作用域存储相关的更改,例如授予访问不同目录和不同类型媒体文件的权限。更新您的应用程序以针对 Android 11 后,系统将忽略 requestLegacyExternalStorage 标志。


在 API 级别 29 中,直接访问共享 / 外部存储设备已被弃用。当应用程序以 Build.VERSION_CODES.Q 为目标时,getExternalStorageDirectory() 方法返回的路径不再直接对应用程序可用。 应用程序可以通过迁移到替代方案,如 Context#getExternalFilesDir(String)MediaStoreIntent#ACTION_OPEN_DOCUMENT 等继续访问存储在共享 / 外部存储上的内容。

使用有作用域的存储是最佳实践,除非您的应用程序需要访问不位于特定应用程序目录中的文件。

在 Android-Q 中处理文件管理问题的人可以阅读这篇文章以了解更多信息。


@RonTLV 更新了答案,包括Android11开发者预览版3的隐私更改。 - Anoop M Maddasseri

3
在新的Android更新中,API 30中,你只能写入你的应用程序特定文件
 File directory = new File(context.getFilesDir(), "YOUR_DIR");
 directory.mkdirs();

或者在您的应用的外部存储中 Android/data

File directory = new File(myContext.getExternalFilesDir("FolderName"),"YOUR_DIR");

更新

这个答案提供了另一种解决方案https://dev59.com/ZL_pa4cB1Zd3GeqP_g8c#65744517

更新

还有一种方式是在清单文件(manifest)中授予权限

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

像这个答案https://dev59.com/hlIG5IYBdhLWcg3wjhYh#66968986一样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接