Android Q 适配头疼?分区存储权限变更!看这篇就够了!

Google越来越重视Android用户的隐私保护,所以在Android Q版本引进了作用域存储的概念,这一操作直接限制了开发者惯用外部存储做一些配置信息的永久储存的方式(实际上开发者因为不遵守开发规范,导致用户的手机目录变得杂乱不堪)。
话不多说,直接上总结:

应用内目录:

  • getCacheDir() = /data/user/0/packname/cache 某个应用在内部存储中的cache路径

  • getFilesDir() = /data/user/0/packname/cache /data/user/0/packname/files某个应用在内部存储中的files路径

  • getExternalCacheDir() = /storage/emulated/0/Android/data/packname/cache 某个应用在外部存储中的cache路径

  • getExternalFilesDir(“”) = /storage/emulated/0/Android/data/packname/files某个应用在外部存储中的files路径

  • getDir(“xxxxx”, MODE_PRIVATE).getAbsolutePath() = /data/user/0/packname/app_xxxxx 某个应用在内部存储中的自定义路径

以上方法路径都含有包名,代表属于某个应用,可直接通过File()访问,并且不需要申请读写权限

外部目录(Android Q废弃)

  • Environment.getDataDirectory() = /data 内部存储的根路径
  • Environment.getDownloadCacheDirectory() = /data/cache
  • Environment.getRootDirectory() = /system
  • Environment.getExternalStorageDirectory().getAbsolutePath() = /storage/emulated/0 外部存储的根路径
  • Environment.getExternalStoragePublicDirectory(“”).getAbsolutePath() = /storage/emulated/0 外部存储的根路径

Android Q版本以下,在有读写权限的情况下,可直接使用File()访问,Android Q版本以上,会报权限不足的异常。

公有共享目录

  • Image: MediaStore.Images.Media.EXTERNAL_CONTENT_URI
  • Video: MediaStore.Video.Media.EXTERNAL_CONTENT_URI
  • Audio: MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
  • Downloads: MediaStore.Downloads.EXTERNAL_CONTENT_URI

Android系统针对文件类型进行了分类,图片、音频、视频这三类文件将可以通过MediaStore API来进行访问,而其他类型的文件则需要使用系统的文件选择器来进行访问。

应用程序向媒体库贡献的图片、音频或视频,将会自动拥有其读写权限,不需要额外申请READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限。而如果你要读取其他应用程序向媒体库贡献的图片、音频或视频,则必须要申请READ_EXTERNAL_STORAGE权限才行。WRITE_EXTERNAL_STORAGE权限将会在未来的Android版本中废弃。

如何向公有共享目录添加数据

  • insert:image、video、audio、downloads可使用contentResolver.insert(uri,contentValues)方法得到新增文件的uri,然后通过contentResolver.openOutputStream(uri)字节流插入数据
try {
    val contentValues = ContentValues()
    contentValues.put(MediaStore.Downloads.DISPLAY_NAME, filename)
    contentValues.put(MediaStore.Downloads.DATE_TAKEN, System.currentTimeMillis())
    val uri = this.contentResolver.insert(
        MediaStore.Downloads.EXTERNAL_CONTENT_URI,
        contentValues
    )
    val os = this.contentResolver.openOutputStream(uri!!)
    os?.use {
        os.write("这是测试数据".toByteArray())
        os.flush()
    }
} catch (e: Exception) {
    e.printStackTrace()
}

如何获取共有共享目录的媒体文件

  • getUri:image、video、audio可通过contentResolver.query(uri,projection,selection,selectionArgs,sortOrder)方法查找到uri,而downloads下的文件只能通过Intent(Intent.Intent.ACTION_OPEN_DOCUMENT)文件选择器,在onActivityResult()方法中通过data.data获取文件的uri
//获取相册中的图片
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()
}
//获取Downloads文件夹下的文件
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
    addCategory(Intent.CATEGORY_OPENABLE)
    type = "*/*"
    putExtra(
        DocumentsContract.EXTRA_INITIAL_URI,
        MediaStore.Downloads.EXTERNAL_CONTENT_URI
    )
}
startActivityForResult(intent, SELECT_REQ)

如何更新公有共享目录现有的媒体文件

  • update: 拿到文件的uri后,通过contentResolver.openOutputStream(uri)方法,通过字节流改变文件内容
val os = this.contentResolver.openOutputStream(uri!!)
os?.use {
    os.write("这是测试数据".toByteArray())
    os.flush()
}

你可能感兴趣的:(Android Q 适配头疼?分区存储权限变更!看这篇就够了!)