Skip to content

Commit d191f09

Browse files
committed
FEAT: 更新词典订阅体验并修复稳定性问题
- 增强词典/翻译流式渐显、TTS 预热与网络访问层稳定性\n- 修复更新弹窗、加载状态、API 错误日志与深色模式视觉问题\n- 统一订阅入口与优惠徽标样式,更新 paywall logo 资源\n- 清理无效 StoreKit 引用并同步相关文档
1 parent 9e50be4 commit d191f09

119 files changed

Lines changed: 10465 additions & 4784 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,9 @@ jobs:
173173
exit 1
174174
fi
175175
DART_DEFINES+=("--dart-define=REVENUECAT_API_KEY_GOOGLE=${REVENUECAT_API_KEY_GOOGLE}")
176-
# 侧载 APK(GitHub / 官网直装):声明 apk 渠道 → 走网页支付而非 Play Billing。
176+
# 侧载 APK(GitHub / 官网直装):声明 direct 渠道 → 走网页支付而非 Play Billing。
177177
# 缺 WEB_PURCHASE_LINK_TEMPLATE 时优雅退回原行为(不启用网页支付)。
178-
DART_DEFINES+=("--dart-define=DISTRIBUTION_CHANNEL=apk")
178+
DART_DEFINES+=("--dart-define=DISTRIBUTION_CHANNEL=direct")
179179
if [[ -n "$WEB_PURCHASE_LINK_TEMPLATE" ]]; then
180180
DART_DEFINES+=("--dart-define=WEB_PURCHASE_LINK_TEMPLATE=${WEB_PURCHASE_LINK_TEMPLATE}")
181181
else
@@ -383,6 +383,7 @@ jobs:
383383
exit 1
384384
fi
385385
DART_DEFINES+=("--dart-define=REVENUECAT_API_KEY_APPLE=${REVENUECAT_API_KEY_APPLE}")
386+
DART_DEFINES+=("--dart-define=DISTRIBUTION_CHANNEL=app_store")
386387
# 先用 flutter 编译 dart 代码,--no-codesign 跳过签名
387388
flutter build ios --release --no-codesign --flavor=prod \
388389
--build-name="$BUILD_NAME" \

CLAUDE.md

Lines changed: 56 additions & 281 deletions
Large diffs are not rendered by default.

PLAN.md

Lines changed: 62 additions & 717 deletions
Large diffs are not rendered by default.

TASKS.md

Lines changed: 69 additions & 1879 deletions
Large diffs are not rendered by default.
95.3 KB
Loading

docs/plan-archive/plan-2026-07-12-full.md

Lines changed: 751 additions & 0 deletions
Large diffs are not rendered by default.

docs/reference/claude-2026-07-12-full.md

Lines changed: 530 additions & 0 deletions
Large diffs are not rendered by default.

docs/reference/claude-summary.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# CLAUDE 摘要
2+
3+
> 说明:仓库规则禁止直接改 `CLAUDE.md`,因此这里提供压缩入口。
4+
> 真实规则仍以根目录 `CLAUDE.md``AGENTS.md` 为准。
5+
6+
## 核心约束
7+
8+
- 文件驱动:决策落到 `PLAN.md` / `TASKS.md`
9+
- 单任务推进:一次只做一个任务。
10+
- 最小改动:只改当前任务直接相关文件。
11+
- 测试优先:功能与修复都要补验证。
12+
- 类型安全:避免 `dynamic``as` 强转、`!` 非空断言。
13+
- 文档同步:任务完成后更新 `TASKS.md`,必要时更新 `PLAN.md`
14+
15+
## 开发流程
16+
17+
开始前:
18+
19+
1.`PLAN.md`
20+
2.`TASKS.md`
21+
3. 明确本次单一任务
22+
4. 等待用户确认后修改
23+
24+
完成后:
25+
26+
1. 检查测试覆盖
27+
2. 清理死代码
28+
3. 检查中文注释
29+
4. 运行与改动直接相关的 analyze / test
30+
5. 更新 `TASKS.md`
31+
6. 必要时更新 `PLAN.md`
32+
7. 输出摘要
33+
34+
## 当前最重要的踩坑主题
35+
36+
- iOS 语音识别 session 隔离
37+
- `flutter_tts` stop / speak 时序
38+
- Android `versionCode` 必须全局单调递增
39+
- Android 离线 ASR native 崩溃排查
40+
- 锁屏媒体会话与前台播放隔离
41+
- TTS 合成与缓存链路
42+
- 词典非 modal 面板与流式 AI 词典协议
43+
44+
详细踩坑记录见根目录 [CLAUDE.md](../../CLAUDE.md) 第 7 节。

docs/subscription-setup.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,13 @@ flutter run --dart-define-from-file=auth.env
7474

7575
### 平台启停语义(编译期开关)
7676

77-
**「某平台是否启用订阅」= 是否给该平台注入 RC key**(单一真相源,无独立 flag)
77+
**订阅实现由 `platform + DISTRIBUTION_CHANNEL` 本地决定**
7878

79-
- 注入 `REVENUECAT_API_KEY_APPLE` → iOS 启用;注入 `REVENUECAT_API_KEY_GOOGLE` → Android 启用。
79+
- `ios|macos + app_store` → Apple IAP / StoreKit;`android + play` → Google Play / RevenueCat Google。
80+
- `android|macos|windows + direct` → RevenueCat Web Purchase Link / Paddle。
8081
- 未注入 key 的平台:RC 不初始化、**订阅入口整体隐藏**(设置页 tile 不渲染、`openPaywall` 拦截并提示、Paywall 路由显示占位页),app 照常匿名运行。
81-
- **macOS 当前被代码显式排除**`revenuecat_config.dart``revenueCatApiKey` 只在 iOS 返回 Apple key):macOS IAP 未验证(Milestone 5 Phase 4),验证通过后恢复 `|| Platform.isMacOS` 分支即可启用
82-
- 停用/启用某平台需要发版——这与商店要求一致(Play 激活订阅本就要求上传含 IAP 的构建),不损失灵活性**限额侧的启停是后端 env,即时生效、无需发版**(见第 7 节 `AI_QUOTA_ENFORCED_PLATFORMS`)。
82+
- 未注入或非法 distribution 保守隐藏支付入口;旧值 `apk` / `desktop` 仅在客户端解析层兼容为 `direct`,不再作为正式 header 值
83+
- 停用/启用支付需要发版**限额侧按平台+渠道组合由后端 env 控制**(见第 7 节 `AI_QUOTA_ENFORCED_CLIENTS`)。
8384

8485
相关代码:`lib/config/revenuecat_config.dart`(读 key + `isSubscriptionSupported`)、`lib/features/subscription/providers/subscription_availability.dart`(UI 门控 provider)、`lib/main.dart``Purchases.configure`)。
8586

@@ -92,7 +93,7 @@ RevenueCat 托管 Web Paywall(底层 Paddle 计费),权益仍经 RevenueCa
9293
构建时注入:
9394

9495
```
95-
DISTRIBUTION_CHANNEL=apk # 或 desktop
96+
DISTRIBUTION_CHANNEL=direct
9697
WEB_PURCHASE_LINK_TEMPLATE=https://pay.rev.cat/<token>/{app_user_id}/paywall
9798
```
9899

@@ -168,22 +169,21 @@ AI_QUOTA_ENFORCEMENT_ENABLED=true # 启用限额(订阅豁免 + 免费 5
168169
```
169170
> 只认字面量 `'true'``'false'`、空、未设置都视为关闭。改这个变量后需重新部署(Vercel 环境变量在下次部署生效)。开关关闭时,webhook 仍可照常落库订阅状态(不影响),只是暂不据此限额。
170171
171-
### 平台灰度:`AI_QUOTA_ENFORCED_PLATFORMS`(默认空 = 全放行)
172+
### 平台+渠道灰度:`AI_QUOTA_ENFORCED_CLIENTS`(默认空 = 全放行)
172173

173-
限额**按平台灰度启用**:订阅已上线的平台限额,未上线的平台(买不了会员,限了只会堵死用户)继续无限用
174+
限额按合法的 `platform:distribution` 组合灰度启用,支付尚未上线的组合继续无限用
174175

175176
```
176177
# 后端部署环境(Vercel 等)
177-
AI_QUOTA_ENFORCED_PLATFORMS=ios # 只对 iOS 限额(当前阶段)
178-
# AI_QUOTA_ENFORCED_PLATFORMS=ios,android # Android 订阅上线后加进来即可,无需发版
179-
# 不设 / 空 → 不对任何平台限额
178+
AI_QUOTA_ENFORCED_CLIENTS=ios:app_store,android:play
179+
# 可选追加 macos:app_store / macos:direct / android:direct / windows:direct
180+
# 不设 / 空 → 不对任何组合限额
180181
```
181182

182-
- 合法值:`ios` / `macos` / `android` / `windows`(逗号分隔,大小写与空白不敏感,非法项忽略)。
183-
- 平台来源:客户端 AI 请求携带的 `x-app-platform` header(`lib/services/client_info.dart`,两个 AI API client 恒定携带)。
184-
- **缺 header 一律放行(fail-open)**:老版本客户端不带 header 且没有 402 → 订阅引导的处理逻辑,对其限额只会让 AI 功能直接报错。因此**限额只对新版客户端生效**,等 iOS 新版铺开后再把总开关置 true。
185-
- header 可伪造,但这是按平台灰度的商业开关而非安全边界;全平台上线(列表列全)后此绕过通道自然消失。
186-
- 判定顺序(`isFreeQuotaExceeded`):总开关 → 平台列表 → 订阅豁免 → 免费额度比较。
183+
- 合法组合:`android:play``android:direct``ios:app_store``macos:app_store``macos:direct``windows:direct`
184+
- 客户端请求同时携带 `x-app-platform``x-app-distribution`;正式 distribution 只允许 `play` / `app_store` / `direct`
185+
- **缺失、非法值或非法组合一律 fail-open**:旧客户端缺 distribution 时不启用限额。
186+
- 判定顺序(`isFreeQuotaExceeded`):总开关 → 组合名单 → 订阅豁免 → 免费额度比较。
187187

188188
### 已实现(后端代码,`fluency-frontend`
189189
- `user_entitlements` 表(迁移 `0037_fluffy_william_stryker.sql`):**每 (用户, entitlement) 一行**(复合唯一键,对齐 RC 官方 Supabase 集成做法,支持多权益),`is_active` + `expires_at_ms`(bigint) + `raw`(jsonb 事件原文,逃生舱) 等。

0 commit comments

Comments
 (0)