用途
该技能面向 Expo React Native 应用,解决操作系统权限请求的设计与实现问题。它覆盖相机、麦克风、照片、位置、通讯录、日历、运动、通知、蓝牙等权限,目标是在用户按下需要权限的控件时才发起询问,避免启动时一次性弹窗,并妥善处理拒绝、阻止、部分授权等边界情况。App Tracking Transparency 不在此技能范围内,由 admob-ads-and-consent 通过 ConsentPort 处理。
主要能力
- 按动作询问:权限请求在控件按下时触发(gate.requestAccess(onAllowed)),不在启动、根布局、effect 或模块作用域发起。
- 权限清单契约:每个权限在 contracts/permissions.json 中登记,记录服务功能、询问来源、平台、用途字符串键、是否先解释及文案键。
- 七种状态映射:服务适配器将系统答案映射为 granted、limited、provisional、undetermined、denied、blocked、unavailable,用 canAskAgain 区分拒绝与阻止,用 accessPrivileges 和定位精度表示部分授权,异常调用映射为 unavailable。
- 统一门控:通过 usePermissionGate 读取最新状态,一次只发起一个询问,返回应展示的弹层;禁止直接使用模块权限 Hook。
- 先解释规则:仅当控件本身无法说明用途时展示解释弹层,只有一个“继续”按钮;Android 的 rationale 有“继续”和“不用了”。
- 尊重拒绝:用户拒绝后不再展示弹层、不跳设置、不重试;控件说明功能关闭,功能保留无权限路径。
- 阻止引导:权限被永久阻止时,后续按下展示设置弹层并打开 Linking.openSettings(),不再重复发起无法出现的对话框。
- 前台重读:通过基于 AppState 的 useSyncExternalStore 状态镜像,在每次回到前台时重新读取权限状态。
- 用途字符串:每个被询问的权限在生产构建中都有具体、已翻译的用途描述;未询问的插件权限设为 false。
- Android 规则:不在 blockedPermissions 中阻止应用会询问的权限;后台位置在前台位置之后单独请求;通知渠道先于通知询问。
- 最少权限:优先使用无需权限的系统照片选择器;仅添加照片访问、粗略位置优先于精确位置、使用期间优先于始终。
- 测试覆盖:通过 createFakePermissionAccess 覆盖 granted、allowed、limited、declined、Android rationale、blocked、unavailable 及设置变更等结果;E2E 流程显式设置权限。
使用方式
- 阅读 references/asking-flow.md,决定权限清单:每个权限由哪个按下动作询问、控件是否解释需求、无权限时什么仍可用、文案内容。优先考虑无需权限的 API。
- 复制模板:templates/src/core/permissions/、templates/src/services/permissions/、templates/src/hooks/use-permission-gate.ts 及其测试,以及 templates/contracts/permissions.json 和 permissions.schema.json。这些模板依赖 src/core/async/latest-request.ts 和错误日志端口,需先配置。
- 为每种权限编写适配器,参考 examples/src/services/permissions/camera-permission-adapter.ts,使用 createExpoPermissionAccess 包装模块的 get/request 方法。
- 配置插件选项:sourceText 指向用途键,未询问的权限设为 false,被询问的权限不放入 blockedPermissions,并在 NATIVE_TEXT_KEYS 中列出键;重新生成原生快照。
- 在每种语言的文案目录中添加 purposeKey、explain.* 和 settings.*,并填写契约条目。
- 在功能模型 Hook 中调用 usePermissionGate,在按下处理函数中调用 gate.requestAccess(onAllowed),用应用的对话框组件渲染弹层。
- 用假实现测试每种结果,参考 use-task-photo-model.test.tsx 的结构。
- 在指定设备上验证:模拟器和仿真器全新安装,Maestro 流程显式设置权限。
- 运行 node ${CLAUDE_SKILL_DIR}/scripts/check-permissions.mjs .,修复直到输出 RESULT: PASS。
适用场景
适用于需要添加相机、照片、位置、通知等权限的 Expo React Native 功能开发,尤其是需要符合 Apple App Review 与 Android 权限指南、需要多语言用途描述、需要测试拒绝和阻止路径的项目。也适合作为权限相关代码审查和商店隐私声明的对照清单。
限制
该技能针对 Expo 应用,依赖其提供的模板、脚本和契约结构。App Tracking Transparency 不在范围内。技能资料未提供具体的收费、价格或独立平台支持信息。使用前需确保已有 async-safety 相关模块、错误日志端口和 i18n 目录等前置结构。