Android文件选择器

本文讲述了作者在合规要求下对华为应用市场因权限申请问题导致下架的应用进行整改,采用系统自带文件选择器,解决第三方库兼容性问题,并在Android14中处理文件访问权限的问题,最终通过将文件复制到App内部目录解决了问题。
摘要由CSDN通过智能技术生成

前沿

最近又在扮演合规工程师觉得。
华为应用市场把公司应用下架了,原因是权限申请时,没有明确的解释说明权限的用途。
大概就是下面这样,在顶部弄个权限说明![在这里插入图片描述]
在这里插入图片描述

好吧,看了一眼几个大厂的App,确实是做了提示。行, 那就改吧。

最佳实践

看了之前的代码,使用的是第三方的库实现,已经无法再Android API 30后的版本了,只能另外实现。
但是既然系统有自带的文件选择器,那就用系统的吧,没有必要自己实现,麻烦。用第三方库有怕更新不及时,出现一些问题修复不及时。还是用系统的靠谱,没有 UI 的要求,能用就行。

private fun onPickDoc() {
        generateActivityResultContract(
            Intent(Intent.ACTION_GET_CONTENT).apply {
                type = "*"
                addCategory(Intent.CATEGORY_OPENABLE)
            },
        ) { code, intent ->
            intent?.data?.takeIf { code == Activity.RESULT_OK }
        }.let {
            startActivityForResult(it) { uri ->
                uri ?: return@startActivityForResult

                contentResolver.query(uri, null, null, null, null)?.use { cursor ->
                    cursor.moveToFirst()
                    lastPdfName = if (cursor.count > 0) {
                        val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                        cursor.getString(nameIndex)
                    } else {
                        uri.path?.let { it1 -> File(it1).name }
                    }
                    // 这里有坑
                    uploadFile(FileUtils.copyFile(this, uri, "pdf", lastPdfName ?: "pdf"))
                }
            }
        }
    }

处理坑

在注释的地方有个问题,就是在进行上传的时候,会报错没有文件访问权限。
但是我的已经是Androi 14(API 34)了,已经没有"android.permission.WRITE_EXTERNAL_STORAGE"权限,而且已经申请了下面三个权限:

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

既然权限都申请了,居然还会报错无法访问文件!
后面怀疑是不是从拿到的Uri获取的路径不对,然后各种尝试拿到真实的文件地址。
最后呢拿到真实地址了,结果还是一样,无法读取文件数据,报错没有权限。

一天后才想到,应该是这个文件可能出现在任何位置,我们的App虽然拿到了地址,但是在上传的时候,第三方SDK在处理这个文件地址时,应该没有权限去访问。

所以,只要把文件拷贝到我们App内data下的目录下,应该就有访问权限了。访问这个我们自己的目录是不需要权限的。

object FileUtils {

    fun copyFile(context: Context, sourceUri: Uri, folderPath: String, fileName: String): String? {
        val contentResolver: ContentResolver = context.contentResolver
        return try {
            val folder = File(App.instance.externalCacheDir, folderPath)
            if (!folder.mkdirs() && (!folder.exists() || !folder.isDirectory)) {
                return null
            }
            val destinationFile = File(folder, fileName)
            contentResolver.openInputStream(sourceUri)?.use { input ->
                destinationFile.outputStream().use { output ->
                    input.copyTo(output, DEFAULT_BUFFER_SIZE)
                }
            }
            destinationFile.absolutePath
        } catch (e: IOException) {
            null
        }
    }
}

最后运行代码,确实解决了文件访问问题。

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值