Android11适配

适配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")        
    }    
} 

参考:https://juejin.im/post/6890811621724618765

你可能感兴趣的:(Android11适配)