我的Android应用程序的目标是Android 13(API 33(
WRITE_EXTERNAL_STORAGE权限在API 33(即Android 12及以下版本(以下似乎运行正常,但在Android 13上运行应用程序时,WRITE_EEXTERNAL_STORAGE的运行时权限弹出窗口不会出现。
我的Android应用程序在应用程序的私人存储中创建了一个密钥库文件。
Android 13的行为变化提到了这一点:
如果你的应用程序以Android 13为目标,你必须请求一个或多个新的权限而不是READ_EXTERNAL_STORAGE。
新权限为:
- 图像和照片:READ_MEDIA_Images
- 视频:READ_MEDIA_VIDEO音频
- 音频文件:READ_MEDIA_Audio
我在官方文档中没有找到任何关于这方面的信息。该文档只关注媒体文件,没有任何关于其他文件类型的信息。
https://developer.android.com/about/versions/13/behavior-changes-13#granular-媒体权限
TLDR:您没有。
来自谷歌官方文档:
"如果您的应用程序以Android 11为目标,WRITE_EEXTERNAL_STORAGE权限和WRITE_MEDIA_STORAGE特权权限将不再提供任何额外的访问权限">
因此,实际上,如果你在Android 11或更高版本上请求WRITE_EEXTERNAL_STORAGE,你将不会请求任何内容。这就是安卓向作用域存储迁移的全部意义,它有效地防止应用程序读取或写入其他应用程序的存储目录,除非它们访问特定的文件类型(例如,媒体,使用您提到的权限(或谷歌自己授予特殊的文件管理器权限。有关作用域存储的更多信息,请参阅这篇写得很好的文章,但TLDR安全性和应用程序卸载的剩余文件是谷歌这样做的主要原因。
因此,如果你真的想写文件,要么确保你只写应用程序指定的存储目录,在这种情况下,你根本不需要任何权限,要么如果你确实需要写应用程序不拥有的目录,从谷歌获得文件管理器权限(如何获得该权限(
您可以在Android官方文档或"如何在Android 13中的共享存储位置中保存文件";。从Android 10开始,如果你想写一个其他应用程序(如文件管理器(或用户可以直接访问的文件,那么你必须将其写入共享存储位置。这必须分三个步骤完成:
步骤1:启动系统选择器以由用户选择目标。
private ActivityResultLauncher<Intent> launcher; // Initialise this object in Activity.onCreate()
private Uri baseDocumentTreeUri;
public void launchBaseDirectoryPicker() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
launcher.launch(intent);
}
步骤2:在onActivityResult((中接收系统选取器返回的Uri作为所选目标。在这里,您可以选择保留权限和Uri以备将来使用。
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
baseDocumentTreeUri = Objects.requireNonNull(result.getData()).getData();
final int takeFlags = (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// take persistable Uri Permission for future use
context.getContentResolver().takePersistableUriPermission(result.getData().getData(), takeFlags);
SharedPreferences preferences = context.getSharedPreferences("com.example.fileutility", Context.MODE_PRIVATE);
preferences.edit().putString("filestorageuri", result.getData().getData().toString()).apply();
} else {
Log.e("FileUtility", "Some Error Occurred : " + result);
}
}
第3步:将内容写入文件。
public void writeFile(String fileName, String content) {
try {
DocumentFile directory = DocumentFile.fromTreeUri(context, baseDocumentTreeUri);
DocumentFile file = directory.createFile("text/*", fileName);
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(file.getUri(), "w");
FileOutputStream fos = new FileOutputStream(pfd.getFileDescriptor());
fos.write(content.getBytes());
fos.close();
} catch (IOException e) {
}
}
如果使用的是sdk 33,请使用(READ_MEDIA_IMAGES(而不是(WRITE_EEXTERNAL_STORAGE(。
检查Android API 31和aove 的WRITE_EXTERNAL_STORAGE
public static boolean isGrantedPermissionWRITE_EXTERNAL_STORAGE(Activity activity) {
int version = Build.VERSION.SDK_INT;
if( version <= 32 ) {
boolean isAllowPermissionApi28 = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED ;
Log.i("general_em","isGrantedPermissionWRITE_EXTERNAL_STORAGE() - isAllowPermissionApi28: " + isAllowPermissionApi28);
return isAllowPermissionApi28;
} else {
boolean isAllowPermissionApi33 = Environment.isExternalStorageManager();
Log.i("general_em","isGrantedPermissionWRITE_EXTERNAL_STORAGE() - isAllowPermissionApi33: " + isAllowPermissionApi33);
return isAllowPermissionApi33;
}
}
对于Android 13及以上版本,请使用以下权限,
<!-- Required only if your app needs to access images or photos
that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
请参考以下参考
https://developer.android.com/training/data-storage/shared/media