OCR 模型按需下载(P8 瘦身): - 移除 plugins/ppocr/assets/ 内置模型(det 9.8MB + rec 21MB + dict),APK 减包 ~31MB - 新增 modelDownloader.ts:优先从 HuggingFace/CDN 下载,兜底从 APK assets 拷贝 - OcrModule.kt 新增 setModelDir,支持从 filesystem 加载模型,回退 assets 兼容旧用户 - settingsStore 持久化 ocrModelVersion / ocrModelDir - 自动化页集成模型状态检查与一键下载 UI OCR 三层独立控制: - OcrProcessorConfig 从单一 aiVisionEnabled 拆分为 layer1/2/3 三个独立开关 - 设置页可按层启停(L1 正则规则 / L2 本地 OCR / L3 AI Vision) - OCR 处理增加耗时与字符数日志 日志系统升级: - logger.ts 新增 LogFileBackend 抽象,支持磁盘持久化(按日期 app-YYYY-MM-DD.log) - 新增 logBackend.ts(ExpoLogFileBackend)+ 日志中心页 settings/logs.tsx - 日志中心:实时缓冲 + 历史文件、4 级过滤、Tag/关键词搜索、JSON 展开、分享导出、7 天过期清理 - _layout.tsx 启动时初始化文件后端 + 日志脱敏(验证码/卡号) 原生浮层 UI 主题同步(P6): - 新增 floatingUiConfig.ts:JS 侧从 theme tokens + i18n 构建 FloatingUiConfig 推送原生 - 新增 FloatingUiConfigStore.kt:SharedPreferences 存储,三浮层组件读取 - FloatingBillView 重设计:颜色/文案走配置、新增币种 chip、金额校验改 BigDecimal - FloatingHelper / FloatingTip 同步适配 - _layout.tsx 新增 FloatingUiConfigSyncer,主题/语言切换自动推送 UI 与组件增强: - FormModal 新增 select/dropdown 控件、行内布局(row/flex)、联动回调 onValuesChange - 新增 Touchable 通用触摸组件、AccountCreateModal 快速建账弹窗 - 信用卡页展示账单周期/到期还款日/本期应还/剩余可用额度,关联账户改下拉选择 - AI 设置页重做:OpenAI/Gemini/DeepSeek 预设 + 默认 URL/模型 - 引导页新增 Android 权限检查步骤(无障碍/通知/短信/存储/悬浮窗) 去重优化: - 对手方匹配改为模糊包含(includes),双方均无对手方时判定低置信度重复 - DedupResult 新增 matchedItem 返回匹配对比项 文档重构: - README.md 重写为入口索引(品牌更新 + 模块概览 + 文档导航表) - 新增 AGENTS.md(AI 助手贡献指南)、docs/architecture.md(Mermaid 数据流/分层/OCR 级联图) - 新增 docs/development.md(环境/命令/编码规范/测试/提交规范)、plugins/README.md - UI 重设计文档(design spec + p1-p8)移入 docs/design/ 其他: - i18n 新增权限/信用卡详情/日志中心/AI 设置等翻译键 - ppocr Config Plugin 修复 import 注入去重;size-optimization 增强 - 新增测试:logger.test.ts、floating-ui-config.test.ts
8.6 KiB
P7:权限快捷引导 Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development to implement this plan task-by-task. Steps use checkbox (
- [x]) syntax. 不执行任何 git 操作(用户要求,改动留工作区)。不创建额外任务清单。
Goal: 引导页权限步骤从纯文字改可操作状态清单;automation 页补齐通知监听/短信/存储三项权限的状态检测与快速跳转按钮。不新增原生权限,只加 UI 入口和一座通知监听状态检测 bridge 方法。
背景决策
- 不新增权限。所有权限已在 AndroidManifest 中声明(通过 Config Plugin),P7 只加 UI 入口。
- 通知监听状态检测需要一个原生 bridge 方法(
isNotificationListenerEnabled),因为 RN 侧无法直接检查。用NotificationManager.getEnabledListenerPackages()。 - 短信 + 存储用 React Native 内置
PermissionsAndroidAPI。 - 引导页 UI 沿用现有 Card + Button 组件,与 P1-P5 设计系统一致。
Task 1: 新增桥接方法 isNotificationListenerEnabled
Files:
-
Modify:
plugins/accessibility/android/AccessibilityBridgeModule.kt -
Modify:
src/services/accessibilityBridge.ts -
Step 1: AccessibilityBridgeModule.kt 加方法
@ReactMethod
fun isNotificationListenerEnabled(promise: Promise) {
try {
val pm = reactContext.packageManager
val enabledListeners = android.app.NotificationManager::class.java
.getMethod("getEnabledListenerPackages")
.invoke(reactContext.getSystemService(Context.NOTIFICATION_SERVICE)) as? List<String>
val myPkg = reactContext.packageName
promise.resolve(enabledListeners?.any { it.startsWith(myPkg) } == true)
} catch (e: Exception) {
promise.resolve(false)
}
}
注意:getEnabledListenerPackages() 在 Android 11+ 需 isNotificationListenerEnabled(ComponentName);优先用反射避免 API level lint 错误,反射失败返回 false。
- Step 2: JS 侧 bridge 接口
NativeAccessibilityBridge 加 isNotificationListenerEnabled(): Promise<boolean>;
- Step 3: 编译验证
cd android && ./gradlew :app:compileDebugKotlin → BUILD SUCCESSFUL
Task 2: 引导页权限步骤(_onboarding.tsx 重写 permissions 步骤)
Files:
-
Modify:
src/app/_onboarding.tsx -
Modify:
src/i18n/zh.ts、src/i18n/en.ts(少量新键) -
Step 1: i18n 新键(zh/en 对等)
在 onboarding section 加:
permAccessibility 无障碍服务 / Accessibility Service
permNotification 通知监听 / Notification Listener
permOverlay 悬浮窗 / Overlay
permSms 短信读取 / SMS
permStorage 相册/存储 / Photos & Storage
permGranted 已授权 / Granted
permNotGranted 未授权 / Not Granted
permOpenSettings 前往设置 / Open Settings
permRequest 请求权限 / Request
- Step 2: 重写 permissions 步骤
替换 _onboarding.tsx:48 的 key: 'permissions' 步骤内容。在当前 description 下方加权限状态清单(Card 包裹,每行:图标 + 名称 + 状态点 + 操作按钮)。
权限列表:
- 无障碍服务(
BIND_ACCESSIBILITY_SERVICE)—— 最核心。检测serviceRunning(从getAccessibilityBridge().isServiceRunning()异步取)。未授权 → 跳转ACCESSIBILITY_SETTINGS - 通知监听(
BIND_NOTIFICATION_LISTENER_SERVICE)—— 检测bridge.isNotificationListenerEnabled()。未授权 → 跳转ACTION_NOTIFICATION_LISTENER_SETTINGS - 短信(
RECEIVE_SMS)——PermissionsAndroid.check()。未授权 →PermissionsAndroid.request() - 存储(
READ_MEDIA_IMAGES,Android 13+ 用READ_MEDIA_IMAGES,否则READ_EXTERNAL_STORAGE)—— 同上
实现细节:
const [permStates, setPermStates] = useState<Record<string, boolean | null>>({})—— null = 加载中useEffect(() => { checkAllPermissions(); }, [])—— 步骤切到 permissions 时触发checkAllPermissions:调PermissionsAndroid.check()检查短信和存储;调 bridge 检查无障碍和通知监听- 每行渲染:
Ionicons图标 +permLabel+ 右侧状态文字(绿「已授权」/ 灰「未授权」)+ 未授权时显示操作按钮 - 「全部已授权」时显示一个大绿色勾 + 提示文字,按钮不显示
权限 API 版本适配:
-
PermissionsAndroid.PERMISSIONS里 Android 13+ 是READ_MEDIA_IMAGES,低版本用READ_EXTERNAL_STORAGE -
统一用
Platform.Version >= 33 ? 'android.permission.READ_MEDIA_IMAGES' : 'android.permission.READ_EXTERNAL_STORAGE' -
Step 3: 验证
Run: npm run typecheck && npm test → 全绿
Run: grep -rn "onboarding.perm" src/i18n/zh.ts src/i18n/en.ts → 确认键对等
Task 3: automation 页补齐权限入口
Files:
-
Modify:
src/app/automation/index.tsx -
Modify:
src/i18n/zh.ts、src/i18n/en.ts(少量新键) -
Step 1: i18n 新键
在 automation section 加:
notificationTitle 通知监听服务 / Notification Listener
notificationEnabled 已启用 / Enabled
notificationDisabled 未启用 / Disabled
notificationOpenSettings 前往系统设置 / Open Settings
smsPermissionTitle 短信读取权限 / SMS Permission
smsPermissionGranted 已授权 / Granted
smsPermissionRequest 请求权限 / Request
storagePermissionTitle 存储权限 / Storage Permission
storagePermissionGranted 已授权 / Granted
storagePermissionRequest 请求权限 / Request
- Step 2: automation 页加权限卡片
在现有「无障碍服务状态与控制」Card 之后加一个新 Card:<Card title={t('automation.otherPermissions')}>。
内容三行:
- 通知监听:异步
bridge.isNotificationListenerEnabled()→ 状态文字 + 未启用时「前往系统设置」按钮(Linking.sendIntent('android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS')) - 短信:
PermissionsAndroid.check('android.permission.RECEIVE_SMS')+PermissionsAndroid.request() - 存储:
PermissionsAndroid.check(StoragePermission)+PermissionsAndroid.request()
实现模式:
const [notifEnabled, setNotifEnabled] = useState(false);
const [smsGranted, setSmsGranted] = useState(false);
const [storageGranted, setStorageGranted] = useState(false);
useEffect(() => {
// 异步获取各权限状态
checkNotif(); checkSms(); checkStorage();
}, []);
每行渲染:Ionicons 图标 + 权限名称 + 状态文字 + 未授权时的按钮。
- Step 3: 验证
Run: npm run typecheck && npm test → 全绿
Task 4: 编译 + 测试 + 终审
- Step 1: 编译验证
cd android && ./gradlew :app:compileDebugKotlin → BUILD SUCCESSFUL
- Step 2: 全量测试
npm test → 全绿;npm run typecheck → 0 错误
- Step 3: 审计
grep -rn "#[0-9A-Fa-f]\{6\}" src/ --include="*.ts" --include="*.tsx" | grep -v "theme/presets.ts\|theme/palette.ts" # 无输出
grep -rn "fontFamily" src/app/_onboarding.tsx src/app/automation/index.tsx # 无输出
grep -rnE "📊|💰|💸|📝|🔄|🎉|✨|⚠|📌|🌟" src/i18n/ src/app/_onboarding.tsx src/app/automation/index.tsx # 无输出(预存 i18n fallbackWarn ⚠ 除外)
- Step 4: 手工走查(需设备)
- 清数据 → 启动应用 → 引导页第 5 步(权限)→ 看到 4 个权限状态
- 点未授权的无障碍 → 跳系统无障碍设置 → 返回看到状态已变
- 点未授权的通知监听 → 跳系统通知设置
- 点短信 → 弹出系统权限对话框
- 引导页全部完成后 → 进入 automation 页 → 看到新增的权限卡片
终审修订(已实施,以实际代码为准)
终审日期:2026-07-22,审计 598 测试全绿、typecheck 干净、Kotlin BUILD SUCCESSFUL。
| # | 级别 | 问题 | 处理 |
|---|---|---|---|
| — | — | 无 Critical / Important 发现 | — |
偏差说明:
onboarding.permOverlay(悬浮窗)未加入引导页——计划 Task 2 决策列为可选项,实际未实现。不影响核心功能(sideload 自动授予 + 无障碍运行时浮窗走 ACCESSIBILITY_OVERLAY 不依赖此权限)。- T3 中
Platform.Version >= 33改为Number(Platform.Version) >= 33——React Native 的Platform.Version类型为string | number,直接比较会 TS 报错。 - T1 的
isNotificationListenerEnabled使用反射而非enabledListenerPackages属性——minSdk=24 < API 27,反射是兼容方案。