在Adapter中使用Activity获取的Uri发送邮件时权限报错如何解决
问题解决方法
错误根因
该报错由两个常见问题共同导致:
- 你通过
ACTION_OPEN_DOCUMENT获取到的Content URI默认只有临时访问权限,App重启、进程被销毁后权限会自动失效,就算提前将URI存在数据库中也无法继续访问。 - 你之前写的
grantUriPermission代码是给你自己的App包名授予权限,你本身在拿到URI的临时有效期内就有权限,这段代码完全没有实际作用,你需要将URI访问权限授予接收这个Intent的邮件应用才可以。
具体修复步骤
步骤1:拿到URI时提前申请持久化权限
你最初在Activity中通过ACTION_OPEN_DOCUMENT获取到用户选中的文件URI后,不要直接存入数据库,先调用以下代码申请持久化访问权限,这样后续App重启后从数据库读出来的URI依然可以正常访问:
// 拿到用户选中的URI后先执行这段代码,再持久化到数据库 val takeFlags: Int = intent.flags and (Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION) contentResolver.takePersistableUriPermission(uri, takeFlags)
注意:如果你之前存到数据库的URI没有申请过持久化权限,旧URI直接作废即可,需要引导用户重新选择一次文件,走上面的流程存新的URI。
步骤2:正确给邮件应用传递URI权限
两种方案选一种即可,推荐选方案1更简单:
方案1:给Intent加权限标志位,系统自动处理授权
直接在构造发送邮件的Intent时添加读取权限标志,系统会自动给所有匹配到的邮件应用授予该URI的临时访问权限:
try { val emailIntent = Intent(Intent.ACTION_SEND) emailIntent.type = "plain/text" // 新增这行即可 emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) emailIntent.putExtra(Intent.EXTRA_EMAIL, arrayOf(kindleEmailAddress)) emailIntent.putExtra(Intent.EXTRA_SUBJECT, title) emailIntent.putExtra(Intent.EXTRA_STREAM, att) emailIntent.putExtra(Intent.EXTRA_TEXT, message) context.startActivity(Intent.createChooser(emailIntent, "正在发送邮件...")) } catch (t: Throwable) { Toast.makeText(context, "请求失败,请重试:$t", Toast.LENGTH_LONG).show() }
方案2:手动查询所有可处理邮件的应用,挨个授权
如果你需要更精准控制授权范围,可以用下面的代码手动授权:
try { val emailIntent = Intent(Intent.ACTION_SEND) emailIntent.type = "plain/text" emailIntent.putExtra(Intent.EXTRA_EMAIL, arrayOf(kindleEmailAddress)) emailIntent.putExtra(Intent.EXTRA_SUBJECT, title) emailIntent.putExtra(Intent.EXTRA_STREAM, att) emailIntent.putExtra(Intent.EXTRA_TEXT, message) // 查询所有可处理发送邮件Intent的应用,挨个授予URI读取权限 val resInfoList = context.packageManager.queryIntentActivities(emailIntent, PackageManager.MATCH_DEFAULT_ONLY) for (resolveInfo in resInfoList) { val packageName = resolveInfo.activityInfo.packageName context.grantUriPermission(packageName, att, Intent.FLAG_GRANT_READ_URI_PERMISSION) } context.startActivity(Intent.createChooser(emailIntent, "正在发送邮件...")) } catch (t: Throwable) { Toast.makeText(context, "请求失败,请重试:$t", Toast.LENGTH_LONG).show() }
内容的提问来源于stack exchange,提问作者Kurik9797
相关产品推荐
相关产品推荐

