Android Q 適配頭疼?分區(qū)存儲(chǔ)權(quán)限變更!看這篇就夠了!

Google越來(lái)越重視Android用戶的隱私保護(hù),所以在Android Q版本引進(jìn)了作用域存儲(chǔ)的概念,這一操作直接限制了開(kāi)發(fā)者慣用外部存儲(chǔ)做一些配置信息的永久儲(chǔ)存的方式(實(shí)際上開(kāi)發(fā)者因?yàn)椴蛔袷亻_(kāi)發(fā)規(guī)范,導(dǎo)致用戶的手機(jī)目錄變得雜亂不堪)。
話不多說(shuō),直接上總結(jié):

應(yīng)用內(nèi)目錄:

  • getCacheDir() = /data/user/0/packname/cache 某個(gè)應(yīng)用在內(nèi)部存儲(chǔ)中的cache路徑

  • getFilesDir() = /data/user/0/packname/cache /data/user/0/packname/files某個(gè)應(yīng)用在內(nèi)部存儲(chǔ)中的files路徑

  • getExternalCacheDir() = /storage/emulated/0/Android/data/packname/cache 某個(gè)應(yīng)用在外部存儲(chǔ)中的cache路徑

  • getExternalFilesDir(“”) = /storage/emulated/0/Android/data/packname/files某個(gè)應(yīng)用在外部存儲(chǔ)中的files路徑

  • getDir(“xxxxx”, MODE_PRIVATE).getAbsolutePath() = /data/user/0/packname/app_xxxxx 某個(gè)應(yīng)用在內(nèi)部存儲(chǔ)中的自定義路徑

以上方法路徑都含有包名,代表屬于某個(gè)應(yīng)用,可直接通過(guò)File()訪問(wèn),并且不需要申請(qǐng)讀寫權(quán)限

外部目錄(Android Q廢棄)

  • Environment.getDataDirectory() = /data 內(nèi)部存儲(chǔ)的根路徑
  • Environment.getDownloadCacheDirectory() = /data/cache
  • Environment.getRootDirectory() = /system
  • Environment.getExternalStorageDirectory().getAbsolutePath() = /storage/emulated/0 外部存儲(chǔ)的根路徑
  • Environment.getExternalStoragePublicDirectory(“”).getAbsolutePath() = /storage/emulated/0 外部存儲(chǔ)的根路徑

Android Q版本以下,在有讀寫權(quán)限的情況下,可直接使用File()訪問(wèn),Android Q版本以上,會(huì)報(bào)權(quán)限不足的異常。

公有共享目錄

  • 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系統(tǒng)針對(duì)文件類型進(jìn)行了分類,圖片、音頻、視頻這三類文件將可以通過(guò)MediaStore API來(lái)進(jìn)行訪問(wèn),而其他類型的文件則需要使用系統(tǒng)的文件選擇器來(lái)進(jìn)行訪問(wèn)。

應(yīng)用程序向媒體庫(kù)貢獻(xiàn)的圖片、音頻或視頻,將會(huì)自動(dòng)擁有其讀寫權(quán)限,不需要額外申請(qǐng)READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE權(quán)限。而如果你要讀取其他應(yīng)用程序向媒體庫(kù)貢獻(xiàn)的圖片、音頻或視頻,則必須要申請(qǐng)READ_EXTERNAL_STORAGE權(quán)限才行。WRITE_EXTERNAL_STORAGE權(quán)限將會(huì)在未來(lái)的Android版本中廢棄。

如何向公有共享目錄添加數(shù)據(jù)

  • insert:image、video、audio、downloads可使用contentResolver.insert(uri,contentValues)方法得到新增文件的uri,然后通過(guò)contentResolver.openOutputStream(uri)字節(jié)流插入數(shù)據(jù)
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("這是測(cè)試數(shù)據(jù)".toByteArray())
        os.flush()
    }
} catch (e: Exception) {
    e.printStackTrace()
}

如何獲取共有共享目錄的媒體文件

  • getUri:image、video、audio可通過(guò)contentResolver.query(uri,projection,selection,selectionArgs,sortOrder)方法查找到uri,而downloads下的文件只能通過(guò)Intent(Intent.Intent.ACTION_OPEN_DOCUMENT)文件選擇器,在onActivityResult()方法中通過(guò)data.data獲取文件的uri
//獲取相冊(cè)中的圖片
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)

如何更新公有共享目錄現(xiàn)有的媒體文件

  • update: 拿到文件的uri后,通過(guò)contentResolver.openOutputStream(uri)方法,通過(guò)字節(jié)流改變文件內(nèi)容
val os = this.contentResolver.openOutputStream(uri!!)
os?.use {
    os.write("這是測(cè)試數(shù)據(jù)".toByteArray())
    os.flush()
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容