Android 问:file.mkdirs() returns 错误
Android Q: file.mkdirs() returns false
我们有一个应用程序使用外部存储来存储一些临时文件:图像、二进制数据。直到最近,它的代码已经运行了几年,没有大的变化。在 Android Q 上它不起作用:
File f = new File(Environment.getExternalStorageDirectory().toString() + File.separator + MainActivity.APP_DIR)
f.mkdirs();
// do sth with f
mkdirs
现在returns只是false
。
清单中提供了所需的权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
该代码在 Android 的早期版本上运行良好。这种访问类型是否有一些系统级别的更改?如果是这样,解决方法是什么?
通过引入 Scoped Storage,android Q 中的隐私发生了巨大变化。
自 Q beta 4 以来,可以通过以下方式 opt-out 该功能:
- 目标 API 28(或更低)
- 使用
requestLegacyExternalStorage
清单属性(目标 API 29):
<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android Q. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
edit: 如其他答案中所述,如果应用程序的目标是 API 30 - Android 11 设备,则此操作将忽略旧存储标志。
编辑 2: 任何计划在 Play 商店发布的人请注意 - 很快将限制使用此标志(不接受新的和更新的应用程序),除非它需要核心功能(例如文件管理器)
更新: 自 Android 11 scoped storage is enforced。以 Android 10(API 级别 29)为目标的应用程序仍然可以请求 requestLegacyExternalStorage
属性。此标志允许应用程序暂时选择退出与范围存储相关的更改,例如授予对不同目录和不同类型媒体文件的访问权限。将应用更新为目标 Android 11 后,系统会忽略 requestLegacyExternalStorage
标志。
在 API 级别 29 中直接访问 shared/external 存储设备已被弃用。当应用以 Build.VERSION_CODES.Q
为目标时,应用不再可以直接访问从 getExternalStorageDirectory()
方法返回的路径。
通过迁移到 Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT.
等替代方案,应用可以继续访问存储在 shared/external 存储上的内容
最佳做法是使用分区存储,除非您的应用需要访问不在应用特定目录中的文件。
那些在 Android-Q 中遇到文件管理问题的人可以阅读 this 文章以进一步了解。
在新的Android更新中API 30
你只能写在你的app-specific files
File directory = new File(context.getFilesDir(), "YOUR_DIR");
directory.mkdirs();
或在您应用的外部存储中Android/data
File directory = new File(myContext.getExternalFilesDir("FolderName"),"YOUR_DIR");
更新
这个答案提供了另一种解决方案
更新
另一种方法是在 manifest
中授予此权限
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
喜欢这个回答
我们有一个应用程序使用外部存储来存储一些临时文件:图像、二进制数据。直到最近,它的代码已经运行了几年,没有大的变化。在 Android Q 上它不起作用:
File f = new File(Environment.getExternalStorageDirectory().toString() + File.separator + MainActivity.APP_DIR)
f.mkdirs();
// do sth with f
mkdirs
现在returns只是false
。
清单中提供了所需的权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
该代码在 Android 的早期版本上运行良好。这种访问类型是否有一些系统级别的更改?如果是这样,解决方法是什么?
通过引入 Scoped Storage,android Q 中的隐私发生了巨大变化。
自 Q beta 4 以来,可以通过以下方式 opt-out 该功能:
- 目标 API 28(或更低)
- 使用
requestLegacyExternalStorage
清单属性(目标 API 29):
<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android Q. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
edit: 如其他答案中所述,如果应用程序的目标是 API 30 - Android 11 设备,则此操作将忽略旧存储标志。
编辑 2: 任何计划在 Play 商店发布的人请注意 - 很快将限制使用此标志(不接受新的和更新的应用程序),除非它需要核心功能(例如文件管理器)
更新: 自 Android 11 scoped storage is enforced。以 Android 10(API 级别 29)为目标的应用程序仍然可以请求 requestLegacyExternalStorage
属性。此标志允许应用程序暂时选择退出与范围存储相关的更改,例如授予对不同目录和不同类型媒体文件的访问权限。将应用更新为目标 Android 11 后,系统会忽略 requestLegacyExternalStorage
标志。
在 API 级别 29 中直接访问 shared/external 存储设备已被弃用。当应用以 Build.VERSION_CODES.Q
为目标时,应用不再可以直接访问从 getExternalStorageDirectory()
方法返回的路径。
通过迁移到 Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT.
最佳做法是使用分区存储,除非您的应用需要访问不在应用特定目录中的文件。
那些在 Android-Q 中遇到文件管理问题的人可以阅读 this 文章以进一步了解。
在新的Android更新中API 30
你只能写在你的app-specific files
File directory = new File(context.getFilesDir(), "YOUR_DIR");
directory.mkdirs();
或在您应用的外部存储中Android/data
File directory = new File(myContext.getExternalFilesDir("FolderName"),"YOUR_DIR");
更新
这个答案提供了另一种解决方案
更新
另一种方法是在 manifest
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
喜欢这个回答