### 4. 权限申请流程图设计:规范、路径与输出物
#### 适用场景
当开发团队需要将权限申请逻辑实现为代码时,必须先依据业务需求绘制标准化流程图。该流程图服务于以下场景:
- **新功能开发**:首次申请某项 Runtime 权限。
- **权限策略变更**:系统版本升级或隐私政策调整,需要重新设计申请链路。
- **技术评审**:架构师或安全审查人员评估申请逻辑是否合理、是否包含降级兜底。
---
#### 前置条件
1. 已确认所需权限列表(精确到 `Manifest.permission` 常量)。
2. 已明确每个权限的申请触发时机(用户点击、功能入口、后台任务)。
3. 团队成员掌握至少一种流程图绘制工具(如 draw.io、Visio、PlantUML 或 Mermaid)。
---
#### 操作步骤
##### 4.1 流程图符号规范
所有申请流程必须遵循以下符号体系,确保多项目间可读性一致:
| 符号 | 形状 / 颜色 | 名称 | 描述 |
|------|-------------|------|------|
|
| 圆角矩形 / 蓝底白字 | 开始 / 结束 | 流程起点和终点 |
|
| 矩形 / 绿底白字 | 处理步骤 | 可执行的代码操作(如 `ContextCompat.checkSelfPermission`) |
|
| 菱形 / 橙底白字 | 决策节点 | 条件判断(如“权限是否已授予”) |
|
| 矩形 + 左侧竖线 / 紫底白字 | 预定义流程 | 跳转到子流程图(如“系统授权对话框”子流程) |
|
| 平行四边形 / 青底白字 | 文档 / 输出物 | 生成或读取的数据文件(如 `PermissionGrantResult`) |
|
| 带箭头实线 / 深灰 | 流线 | 流程控制方向 |
> **强制要求**:同一项目中只使用以上 6 种符号,禁止自行发明新形状或颜色。
##### 4.2 主流程分支
标准的权限申请流程图应包含以下 **3 条分支路径**:
- **分支 A(已授予)**
`开始 → 检查权限(自检) → 决策:已授予/未授予 → 已授予 → 直接执行功能 → 结束`
- **分支 B(可以继续请求)**
`已授予? 未授予 → 决策:shouldShowRationale → 否 → 调用requestPermissions → 系统授权对话框 → 监听ActivityResult → 决策:用户授权/拒绝`
- **分支 C(需要解释后请求)**
`决策:shouldShowRationale → 是 → 显示自定义解释弹窗 → 用户确认 → 调用requestPermissions → 同上`
##### 4.3 决策节点
每个流程图中的决策节点必须标注明确的 **Y / N** 标签,且所有分支必须终结于统一的“结束”节点:
| 决策节点位置 | 判断条件 | Y(是)分支 | N(否)分支 |
|-------------|---------|------------|------------|
| D1 | `checkSelfPermission == PERMISSION_GRANTED` | 直接执行 | 进入 D2 |
| D2 | `shouldShowRequestPermissionRationale` | 显示解释弹窗 | 直接请求 |
| D3 | `resultCode == Activity.RESULT_OK && granted.length > 0` | 执行功能 | 降级 UI 或提示 |
> 对于“永不再次询问”场景,必须在 D2 的子流程中增加一个额外决策节点,检测用户是否勾选了“不再询问”。若为 `true`,则直接跳转到“引导用户前往设置”的处理步骤。
##### 4.4 输出物标注
每个处理步骤必须标注其输出物(数据或状态)。标注格式为 **【输出:<产出名称>】**,置于步骤框下方或右侧说明框内:
| 处理步骤 | 输出物说明 |
|----------|-----------|
| `checkSelfPermission()` | 【输出:权限状态码】`int`(0=授予,-1=拒绝) |
| `shouldShowRequestPermissionRationale()` | 【输出:布尔值】`true` 或 `false` |
| `requestPermissions(array, requestCode)` | 【输出:PENDING_INTENT】系统授权请求实例 |
| `ActivityResultCallback.onActivityResult()` | 【输出:授权结果表】`PermissionGrantResult` 对象集合 |
---
#### 输入输出物
| 类型 | 名称 | 来源 / 去向 | 格式 / 载体 |
|------|------|-------------|-------------|
| **输入** | `AndroidManifest.xml` 权限声明 | 项目源码 | XML 文件 |
| **输入** | 用户交互事件(按钮点击、页面加载) | View 层事件 | Android `Intent` / `Handler` |
| **输出** | 流程审批图(PDF / PNG) | 技术评审会议 | draw.io / PlantUML 导出 |
| **输出** | `PermissionGraph.json` 机器可读版本 | CI 代码检查 | JSON 文件(含节点 ID、分支条件、输出物标签) |
---
#### 责任边界
- **开发工程师**:绘制第一版流程图,确保符号规范、分支完整。
- **技术组长**:审查决策节点是否遗漏“永不询问”分支;确认输出物标注与实际 API 返回值一致。
- **测试工程师**:依据流程图设计测试用例,确保每一条分支路径都有对应的冒烟/回归用例。
---
#### 记录材料
| 材料编号 | 材料名称 | 保存形式 | 保留周期 |
|----------|---------|----------|----------|
| SOC-RP-04-01 | 权限申请流程图(SVG 源文件) | Git 仓库 /docs/flowchart | 整个项目生命周期 |
| SOC-RP-04-02 | 流程图符号规范表 | Wiki / 团队协作文档 | 永久 |
| SOC-RP-04-03 | 流程图评审意见记录表 | Jira / 工单系统评论 | 项目交付后 6 个月 |
---
#### 异常处理
| 异常场景 | 流程图处理方案 | 输出物标注调整 |
|----------|---------------|----------------|
| 用户连续两次拒绝且勾选“不再询问” | 新增决策节点检测 `neverAskAgain`,直接跳转至“引导前往设置”步骤 | 【输出:引导意图】`Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)` |
| 系统授权对话框异常弹出(如 Activity 被销毁) | 在 D3 前增加“Activity 是否存活”决策节点,若否,则结束流程并记录日志 | 【输出:异常日志】`W/PERMISSION: Activity destroyed` |
| 权限声明在运行时被系统撤回 | 在“直接执行功能”前增加二次检查决策节点(兜底) | 【输出:撤回通知】`BroadcastReceiver.onReceive()` |
---
#### 验收标准
1. 流程图包含 **≥ 3 条** 独立分支路径(已授予、可以请求、需要解释)。
2. 所有决策节点均标注 **Y / N** 且无未完结箭头。
3. 每个处理步骤下方或说明框内标有**【输出:<产出名称>】**。
4. 符号使用严格对齐规范表,颜色与形状不允许偏差。
5. 在代码评审中,流程图与实际代码路径 **100%** 匹配。
---
#### 本章核心 SVG:权限申请主流程图
> **使用说明**:该 SVG 可直接嵌入开发文档或 draw.io。所有节点与分支均遵循本章符号规范,输出物标注以黄色说明框呈现。