什么是 URI 权限授予(grantUriPermission)?它解决了什么问题?
解读
国内面试中,这道题常出现在“四大组件安全”环节,尤其是问到 ContentProvider 跨进程共享文件时。面试官想确认两点:
- 你是否真的在 7.0+ 设备上通过 FileProvider 做过文件分享,而不是“Demo 里直接 file:// 路径”;
- 你是否理解 Android 沙箱模型下“文件读写权限”与“组件访问权限”是两条线,grantUriPermission 正是把两者临时打通的“官方后门”。
答不出“临时性”“一次性”“可细化到具体 URI”三个关键词,基本会被判定为“只背过 FLAG_GRANT_READ_URI_PERMISSION 名字”。
知识点
- 沙箱隔离:两个 App UID 不同,默认无法直接访问对方私有目录。
- 权限粒度:AndroidManifest 里的 <provider android:grantUriPermissions="true"> 只是开关,真正决定哪条 URI 能被访问的是 Intent 里带的那一次 grant。
- 临时性:授予的权限只在接收方 Task 栈存活期间有效,finish 即失效;若需长期有效,要配合 takePersistableUriPermission 写入系统数据库。
- 安全边界:Intent 必须显式设置 FLAG_GRANT_READ_URI_PERMISSION 或 FLAG_GRANT_WRITE_URI_PERMISSION,否则即使 URI 被传过去,接收方 openFileDescriptor 也会触发 SecurityException。
- 国内适配:微信、QQ 分享文件、拍照裁切、系统安装 APK(8.0+)全部依赖 grantUriPermission,若自己封装 FileProvider 却忘记 intent.addFlags,在小米、华为机型上必现 “FileUriExposedException” 或 “Permission denied”。
- 代码模板:
Intent intent = new Intent(Intent.ACTION_SEND);
Uri uri = FileProvider.getUriForFile(context, authority, file);
intent.setDataAndType(uri, type);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(Intent.createChooser(intent, null));
答案
grantUriPermission 是 Android 提供的一种“临时、一次性、针对特定 URI”的权限授予机制。
它解决了“应用私有文件无法跨进程安全共享”的问题:
- 在 7.0 以前,开发者常用 file:// URI,接收方需申请 READ_EXTERNAL_STORAGE,既繁琐又容易把真实路径泄露出去;
- 7.0 之后强制使用 FileProvider,返回 content:// URI,但默认仍无读写权限;
- 通过 Intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION) 或 FLAG_GRANT_WRITE_URI_PERMISSION,发送方把对这条 URI 的读写权限临时授予接收方,接收方即可在无需任何系统权限的情况下打开文件;
- 权限生命周期与接收方 Task 绑定,Task 结束即自动回收,既满足最小权限原则,又避免长期暴露攻击面。
一句话总结:grantUriPermission 让“私有文件安全共享”在 Android 沙箱内成为可能,是 FileProvider 跨进程分享场景的必备配套。
拓展思考
-
如果接收方是 Service 而不是 Activity,权限还能生效吗?
答:Service 没有 Task 栈,权限随 Intent 的一次性绑定生效,Service onStartCommand 处理完后即失效;若 Service 需要长期访问,必须调用 takePersistableUriPermission 并捕获 SecurityException,否则后续访问会失败。 -
国内厂商“后台启动 Activity”限制下,如何兼容 10+ 系统?
答:先通过 PendingIntent 把授权 Intent 封装给系统组件(如 Notification 或系统裁切器),由系统侧触发,从而绕过后台启动限制;同时确保 FileProvider 路径配置里加入 android:exported="false",防止外部恶意 App 直接 query 拿到 URI。 -
与 SAF(Storage Access Framework)区别?
答:SAF 让用户主动选择文件,系统返回可持久化的 URI,权限长期有效;grantUriPermission 是开发者主动授予,默认临时,适合“我发给你、你用完即走”的闭环场景。面试中能对比两者,可体现对 Android 整体存储演进路线的理解。