适配targetSdkVersion 30或者以上(Android 11)
分区存储强制执行
对外部存储目录访问仅于应用专属目录,以及应用创建的特定类型媒体
分区存储在Android10已经推行。对于文件读写只能在沙盒环境,属于自己应用的目录读写。其他媒体文件可以通过MediaStore进行访问。
-
在targetSdkVersion = 29应用中,设置android:requestLegacyExternalStorage="true",就可以不启动分区存储。
-
但是targetSdkVersion = 30中不行了,强制开启分区存储。
targetSdkVersion = 30,如果是覆盖安装呢,可以增加android:preserveLegacyExternalStorage="true",暂时关闭分区存储。只要卸载重装,就会失效了;
fun saveFile() {
if (checkPermission()) {
//getExternalStoragePublicDirectory被弃用,分区存储开启后就不允许访问了
val filePath = Environment.getExternalStoragePublicDirectory("").toString() + "/test3.txt"
val fw = FileWriter(filePath)
fw.write("hello world")
fw.close()
showToast("文件写入成功")
}
}
-
targetSdkVersion = 28,运行后正常读写。
-
targetSdkVersion = 29,不删除应用,targetSdkVersion 由 28 修改到 29,覆盖安装,运行后正常读写
-
targetSdkVersion = 29,删除应用,重新运行,读写报错,程序崩溃 (open failed: EACCES (Permission denied))
-
targetSdkVersion = 29,添加android:requestLegacyExternalStorage="true"(不启用分区存储),读写正常不报错
-
targetSdkVersion = 30,不删除应用,targetSdkVersion 由 29 修改到 30,读写报错,程序崩溃 (open failed: EACCES (Permission denied))
-
targetSdkVersion = 30,不删除应用,targetSdkVersion 由 29 修改到 30,增加 android:preserveLegacyExternalStorage="true",读写正常不报错
-
targetSdkVersion = 30,删除应用,重新运行,读写报错,程序崩溃 (open failed: EACCES (Permission denied))
targetSdkVersion = 30 三种方法访问文件
- 应用专属目录
//分区存储空间
val file = File(context.filesDir, filename)
//应用专属外部存储空间
val appSpecificExternalDir = File(context.getExternalFilesDir(), filename)
- 访问公共媒体目录文件
val cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, "${MediaStore.MediaColumns.DATE_ADDED} desc")
if (cursor != null) {
while (cursor.moveToNext()) {
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))
val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
println("image uri is $uri")
}
cursor.close()
}
- SAF (存储访问框架--Storage Access Framework)
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent, 100)
@RequiresApi(Build.VERSION_CODES.KITKAT)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (data == null || resultCode != Activity.RESULT_OK)
return
if (requestCode == 100) {
val uri = data.data
println("image uri is $uri")
}
}
网友评论