当前位置: 首页 > 工具软件 > Android_Data > 使用案例 >

android10以上,访问Android/data文件

越星晖
2023-12-01

自从android10使用分区存储后,文件的操作显得更为复杂,幸运的是,谷歌为我们提供许多操作简单的api,这篇文章主要讲的是android除沙盒目录和共享目录外其他目录的操作

android10以上,如果想要获取其他文件,最简单的方法是申请MANAGE_EXTERNAL_STORAGE权限,获取该权限之后,任何文件都可以正常操作,然后你就不用往下看了……

由于registerForActivityResult()正式版已发布很久,并且官方为registerForActivityResult提供了许多简便易用的api,这里获取文件的方法使用registerForActivityResult

如果找不到registerForActivityResult,你需要将activity版本提升到1.2.0,fragment版本提升到1.3.0以上

打开文件选择器


        //打开文件选择器,选择txt文件      
        val select = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->

        }
        //txt的mimeType,其他文件的则使用相对应的type,比如pdf,则传application/pdf,图片文件传image/*
        select.launch("text/plain")


        //多选文件:
        val select =
            registerForActivityResult(ActivityResultContracts.GetMultipleContents()) { list ->
            }

        select.launch("text/plain")

        
        //多类型多文件
        registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()){
            
        }.launch(arrayOf("mimeType1","mimeType2"))
        
        //多类型单文件
        registerForActivityResult(ActivityResultContracts.OpenDocument()){
            
        }.launch(arrayOf("mimeType1","mimeType2"))

文件夹操作

//打开文件夹选择器
    private val select = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) {
        
    }

select.launch(null)

//获取到文件夹uri后,如果需要遍例文件夹下所有文件:

        val tree = DocumentFile.fromTreeUri(this,文件夹uri)
        if(tree != null){
            val uris = tree.listFiles()
            uris.forEach {
                //该文件夹下文件uri
                it.uri
            }
        }

DocumentFile操作访问文件效率远远不及file操作,如果只是一个文件倒没什么,但如果是个文件夹,里面上百个文件,那么访问速度慢的问题就体现出来了,这时可以将获取到的文件夹uri转成file再操作,这种方法目前还可以用,但我不知道什么时候谷歌会把这方便禁掉

注:需要requestLegacyExternalStorage="true" 和READ_EXTERNAL_STORAGE权限

fun getTreeFile(context: Context, uri: Uri): File? {
    val docId = DocumentsContract.getTreeDocumentId(uri)
    val split = docId.split(":")
    val type = split[0]
    if(type.equals("primary",true)){
        return runCatching { File("${Environment.getExternalStorageDirectory()}/${split[1]}") }.getOrNull()
    }else{
        val manager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
        val storageVolumeClazz = Class.forName("android.os.storage.StorageVolume")
        val getVolumeList: Method = manager.javaClass.getMethod("getVolumeList")
        val getUuid = storageVolumeClazz.getMethod("getUuid")
        val getState = storageVolumeClazz.getMethod("getState")
        val getPath = storageVolumeClazz.getMethod("getPath")
        val result = getVolumeList.invoke(manager)
        val length = Array.getLength(result)
        for (i in 0 until length){
            val ele = Array.get(result,i)
            if(Environment.MEDIA_MOUNTED == getState.invoke(ele) || Environment.MEDIA_MOUNTED_READ_ONLY == getState.invoke(ele)){
                val uuid = getUuid.invoke(ele) as? String
                if(uuid == type){
                    return runCatching { File("${getPath.invoke(ele)}/${split[1]}") }.getOrNull()
                }
            }
        }
    }
    return null
}

外部文件夹访问权限

访问文件夹,也是需要访问权限的,一般来说,通过文件管理器获取的uri,会在获取的时候得到授权,这个权限会直到你的应用重启时才失效,如果你需要永久保留这个文件夹的使用权限,可以通过这段代码申请:

 applicationContext.contentResolver.takePersistableUriPermission(
            需要保留访问权限的uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or
                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION
        )

 类似资料: