您好,登录后才能下订单哦!
随着Android系统的不断更新,Google对文件系统的访问权限管理也变得越来越严格。特别是在Android 11(API级别30)及以上版本中,引入了Scoped Storage(分区存储)机制,极大地改变了应用程序访问外部存储的方式。本文将详细介绍在Android 11及以上版本中,如何申请文件读写权限,并提供相应的代码示例和最佳实践。
在Android 11之前,应用程序可以通过READ_EXTERNAL_STORAGE
和WRITE_EXTERNAL_STORAGE
权限访问整个外部存储空间。然而,这种粗粒度的权限管理方式存在安全隐患,容易导致用户隐私数据泄露。
为了增强用户隐私保护,Android 11引入了Scoped Storage机制,将外部存储空间划分为应用专属存储和共享存储两部分。应用专属存储是每个应用程序私有的存储空间,其他应用程序无法访问;共享存储则是所有应用程序都可以访问的公共存储空间,但访问权限受到严格限制。
Scoped Storage是Android 10引入的一项新特性,旨在限制应用程序对外部存储空间的访问权限。在Android 11中,Scoped Storage得到了进一步强化,成为默认的存储访问方式。
Scoped Storage的核心思想是将外部存储空间划分为以下几个部分:
在Android 11及以上版本中,应用程序需要根据不同的存储类型申请相应的文件读写权限。以下是详细的申请流程。
在Android 11中,应用程序仍然需要请求READ_EXTERNAL_STORAGE
和WRITE_EXTERNAL_STORAGE
权限来访问共享存储空间。然而,这些权限的作用范围已经大大缩小,仅限于访问媒体文件和下载文件。
首先,在AndroidManifest.xml
文件中声明所需的存储权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
在Android 6.0(API级别23)及以上版本中,应用程序需要在运行时请求危险权限。以下是如何在运行时请求存储权限的示例代码:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
REQUEST_CODE_STORAGE_PERMISSION);
}
应用专属文件是每个应用程序私有的存储空间,其他应用程序无法访问。在Android 11中,应用程序无需请求任何权限即可访问自己的应用专属文件。
内部存储中的应用专属文件位于/data/data/<package_name>/files
目录下。以下是如何访问内部存储中的应用专属文件的示例代码:
File internalFile = new File(getFilesDir(), "example.txt");
try (FileOutputStream fos = new FileOutputStream(internalFile)) {
fos.write("Hello, World!".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
外部存储中的应用专属文件位于/storage/emulated/0/Android/data/<package_name>/files
目录下。以下是如何访问外部存储中的应用专属文件的示例代码:
File externalFile = new File(getExternalFilesDir(null), "example.txt");
try (FileOutputStream fos = new FileOutputStream(externalFile)) {
fos.write("Hello, World!".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
共享存储空间是所有应用程序都可以访问的公共存储空间,但访问权限受到严格限制。在Android 11中,应用程序需要请求READ_EXTERNAL_STORAGE
和WRITE_EXTERNAL_STORAGE
权限来访问共享存储空间。
媒体文件包括图片、视频和音频文件,存储在共享存储空间的Pictures
、Movies
和Music
目录下。以下是如何访问媒体文件的示例代码:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
ContentResolver resolver = getContentResolver();
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = resolver.query(uri, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String displayName = cursor.getString(
cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
Log.d("MediaFile", displayName);
}
cursor.close();
}
}
下载文件存储在共享存储空间的Download
目录下。以下是如何访问下载文件的示例代码:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
ContentResolver resolver = getContentResolver();
Uri uri = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
Cursor cursor = resolver.query(uri, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String displayName = cursor.getString(
cursor.getColumnIndex(MediaStore.Downloads.DISPLAY_NAME));
Log.d("DownloadFile", displayName);
}
cursor.close();
}
}
在Android 11中,应用程序可以通过MediaStore
API访问媒体文件。以下是如何使用MediaStore
API访问媒体文件的示例代码:
ContentResolver resolver = getContentResolver();
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = resolver.query(uri, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String displayName = cursor.getString(
cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
Log.d("MediaFile", displayName);
}
cursor.close();
}
在Android 11中,应用程序可以通过MediaStore
API访问下载文件。以下是如何使用MediaStore
API访问下载文件的示例代码:
ContentResolver resolver = getContentResolver();
Uri uri = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
Cursor cursor = resolver.query(uri, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String displayName = cursor.getString(
cursor.getColumnIndex(MediaStore.Downloads.DISPLAY_NAME));
Log.d("DownloadFile", displayName);
}
cursor.close();
}
在Android 10中,Scoped Storage是可选的,开发者可以通过在AndroidManifest.xml
文件中设置requestLegacyExternalStorage
属性来禁用Scoped Storage。然而,在Android 11中,Scoped Storage成为默认的存储访问方式,requestLegacyExternalStorage
属性不再有效。
为了兼容Android 10及以下版本,开发者可以在AndroidManifest.xml
文件中添加以下代码:
<application
android:requestLegacyExternalStorage="true"
... >
...
</application>
在Android 11中,应用程序无法直接访问其他应用程序的文件。如果应用程序需要访问其他应用程序的文件,可以通过ContentProvider
或FileProvider
实现文件共享。
如果用户拒绝了存储权限请求,应用程序可以通过ActivityCompat.shouldShowRequestPermissionRationale
方法判断是否需要向用户解释权限的重要性。如果需要解释,可以向用户展示一个对话框,说明权限的作用和必要性。
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
// 向用户解释权限的重要性
new AlertDialog.Builder(this)
.setTitle("权限请求")
.setMessage("我们需要访问存储权限来读取文件")
.setPositiveButton("确定", (dialog, which) -> {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
REQUEST_CODE_STORAGE_PERMISSION);
})
.setNegativeButton("取消", null)
.show();
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
REQUEST_CODE_STORAGE_PERMISSION);
}
为了增强用户隐私保护,应用程序应尽量减少权限请求。只有在必要时才请求存储权限,并确保用户了解权限的作用和必要性。
在Android 11中,推荐使用ContentResolver
和MediaStore
API访问共享存储空间中的文件。这种方式更加安全,且符合Scoped Storage的设计理念。
如果用户拒绝了存储权限请求,应用程序应优雅地处理这种情况,避免崩溃或功能异常。可以通过提示用户重新授权或提供替代方案来解决问题。
由于Android 11及以上版本的存储权限管理方式发生了较大变化,开发者应确保应用程序在不同Android版本上的兼容性。可以通过在多个Android版本上进行测试,确保应用程序在各种情况下都能正常运行。
Android 11及以上版本的文件读写权限管理方式发生了重大变化,引入了Scoped Storage机制,增强了用户隐私保护。开发者需要了解这些变化,并根据新的权限管理方式调整应用程序的文件访问逻辑。通过合理申请权限、使用ContentResolver
和MediaStore
API访问文件,以及处理权限被拒绝的情况,开发者可以确保应用程序在Android 11及以上版本上正常运行,并提供良好的用户体验。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。