230 lines
10 KiB
Markdown
230 lines
10 KiB
Markdown
# 橘视厅酒店版 App 开发与测试记录
|
||
|
||
> 日期:2026-07-14
|
||
> 项目:MediaApp(橘视厅酒店版)
|
||
> 版本:v1.0
|
||
|
||
---
|
||
|
||
## 一、概述
|
||
|
||
本次开发围绕天卡(日卡)激活 → 设备鉴权 → 微信支付 → 发卡 → 播放的完整链路进行联调与修复,并完成了权益持久化/静默鉴权、播放器画面比例、UI 美化等优化。
|
||
|
||
---
|
||
|
||
## 二、问题修复记录
|
||
|
||
### 2.1 激活请求无法到达后端
|
||
|
||
- **现象**:点击激活后请求未到达后端,错误仅以弹窗形式出现,无法定位原因。
|
||
- **修复**:
|
||
- 新增 `FileLogger` 工具类,持久化日志到 `Android/data/com.pukka.mediaapp/files/logs/daycard.log`。
|
||
- 新增 `FileLoggingInterceptor`,拦截 OkHttp 请求/响应写入日志文件。
|
||
- 在 `SignManager`(激活/init/refresh/heartbeat)、`PaymentViewModel`(鉴权/下单/轮询)关键路径加入 `FileLogger` 调用。
|
||
- **结果**:通过 `adb pull` 拉取日志后成功定位问题,激活流程恢复正常。
|
||
|
||
### 2.2 Gson `code` 字段冲突
|
||
|
||
- **现象**:后端返回的 JSON 中 `code` 字段被 Gson 解析为重复键,导致业务码判断异常。
|
||
- **原因**:`BaseResponse` 子类(`CheckBenefitsResponse`、`CreateOrderResponse` 等)各自声明了 `override val code/msg`,与父类产生重复 JSON 字段。
|
||
- **修复**:移除所有子类中的 `code`/`msg` 声明,统一继承 `BaseResponse()`。
|
||
- **文件**:`DayCardModels.kt`
|
||
|
||
### 2.3 支付弹窗渲染异常
|
||
|
||
- **现象**:支付弹窗仅显示"微信扫码支付"6 个字,其余区域空白,所有按钮不可点击。
|
||
- **原因**:240dp×240dp 的二维码 `FrameLayout` 在加载/错误状态下未隐藏,将按钮挤出可视区域。
|
||
- **修复**:
|
||
- 给 `FrameLayout` 添加 `android:id="@+id/flQrcode"`。
|
||
- 在 `showPaymentDialog`/加载/错误分支设置 `flQrcode.visibility = GONE`,在 `showQrCode` 中设为 `VISIBLE`。
|
||
- **文件**:`dialog_payment.xml`、`DetailActivity.kt`
|
||
|
||
### 2.4 天卡库存不足提示
|
||
|
||
- **现象**:天卡卡池为空时,后端返回 HTTP 200 + `{"code":500,"msg":"天卡库存不足,请补充库存后再试"}`,前端需正确识别。
|
||
- **修复**:前端按 JSON `code` 字段判断(而非 HTTP 状态码),`code === 500` 且 `msg` 包含"库存不足"时弹出错误提示。
|
||
- **备注**:抢卡失败时会产生孤儿订单(status=PENDING),由后端超时定时任务 `DayCardOrderTimeoutTask` 清理为 CANCELLED。
|
||
|
||
### 2.5 发卡成功但返回播放地址异常
|
||
|
||
- **现象**:支付成功、发卡成功后,获取播放地址异常。
|
||
- **原因**:绑定与鉴权链路问题(橘视厅平台订购关系)。
|
||
- **修复**:平台侧订购关系修正后恢复正常。
|
||
|
||
---
|
||
|
||
## 三、权益持久化与静默鉴权
|
||
|
||
### 3.1 背景
|
||
|
||
成功获取播放地址后,切换其它电影点击播放仍弹出支付提示窗。虽然流程很快走完,但体验不佳。需实现有效期内权益持久化 + 静默鉴权。
|
||
|
||
### 3.2 实现方案
|
||
|
||
#### SignManager 权益缓存(`DayCardSignUtil.kt`)
|
||
|
||
| 方法 | 说明 |
|
||
|------|------|
|
||
| `cacheBenefits(thirdCardNo, expireAt)` | 缓存卡号 + 过期时间到 SharedPreferences `jst_sign` |
|
||
| `getCachedThirdCardNo()` | 读取缓存卡号,过期返回空串 |
|
||
| `clearBenefits()` | 清除权益缓存 |
|
||
| `parseExpireAtToMillis()` | 解析多种时间格式为毫秒时间戳 |
|
||
|
||
- 过期时间兜底:解析失败时使用 `SIGN_TTL` 作为默认有效期。
|
||
|
||
#### PaymentViewModel(`PaymentViewModel.kt`)
|
||
|
||
- **缓存命中**:`startPaymentFlow()` 开头同步检查 `getCachedThirdCardNo()`,非空则直接发射 `HasPermission`,不发起网络请求、不弹窗。
|
||
- **缓存写入**:三处调用 `cacheBenefits()`:
|
||
1. `checkBenefits` 返回 ACTIVE 时
|
||
2. 轮询支付成功后首次 `checkBenefits` 返回 ACTIVE 时
|
||
3. 轮询支付成功后重试 `checkBenefits` 返回 ACTIVE 时
|
||
- **缓存清除**:SDK 初始化失败时调用 `clearBenefits()`(卡号可能已失效,下次播放重新鉴权)。
|
||
- **修复**:移除了之前重复的 `flowJob = viewModelScope.launch` 嵌套问题。
|
||
|
||
#### DetailActivity 静默播放(`DetailActivity.kt`)
|
||
|
||
| 状态 | 原行为 | 新行为 |
|
||
|------|--------|--------|
|
||
| `CheckingPermission` | 弹支付窗"正在检查播放权限" | 静默,不弹窗不提示 |
|
||
| `HasPermission` | 弹窗"已有播放权限" | 直接播放,无弹窗无 Toast |
|
||
| `CreatingOrder` | 弹窗加载 | 弹窗加载(仅无权益路径触发) |
|
||
| `WaitingForPayment` | 展示二维码 | 展示二维码(不变) |
|
||
| `PaymentSuccess` | 弹窗"支付成功" | 关闭弹窗直接播放,无 Toast |
|
||
| `Error` | 弹窗显示错误 | 弹窗显示错误,重置播放标志 |
|
||
|
||
- `playWithThirdCardNo` / `fetchVideoUrlFromSdk`:移除所有加载 Toast,仅保留错误 Toast(LENGTH_LONG)。
|
||
- `startPaymentFlow()`:移除"正在检查播放权限..." Toast。
|
||
- **最终效果**:天卡有效期内切换电影点播放,完全静默,直接进入播放器。
|
||
|
||
### 3.3 链路时序
|
||
|
||
```
|
||
首次播放(无缓存):
|
||
点击播放 → checkBenefits(网络) → ACTIVE → cacheBenefits → 播放
|
||
点击播放 → checkBenefits(网络) → UNBOUND → createOrder → 二维码 → 支付 → 轮询PAID → checkBenefits → cacheBenefits → 播放
|
||
|
||
后续播放(缓存有效):
|
||
点击播放 → getCachedThirdCardNo(本地) → HasPermission → 播放 [全程无网络、无弹窗]
|
||
|
||
缓存过期/SDK失败:
|
||
点击播放 → getCachedThirdCardNo 返回空 → checkBenefits(网络) → 重新走鉴权流程
|
||
```
|
||
|
||
---
|
||
|
||
## 四、App 名称与播放器
|
||
|
||
### 4.1 App 名称
|
||
|
||
- `strings.xml` 中 `app_name` 从"媒资展示"改为"橘视厅酒店版"。
|
||
|
||
### 4.2 播放器画面比例
|
||
|
||
- `activity_player.xml` 中 `StyledPlayerView` 的 `resize_mode` 从 `fill`(拉伸填充)改为 `fit`(保持原始比例,不拉伸)。
|
||
- 非 16:9 内容会自动上下/左右留黑边。
|
||
|
||
---
|
||
|
||
## 五、UI 布局优化
|
||
|
||
### 5.1 新增 Drawable(8 个)
|
||
|
||
| 文件 | 用途 |
|
||
|------|------|
|
||
| `bg_poster_rounded.xml` | 海报四角圆角裁切背景 |
|
||
| `bg_poster_rounded_top.xml` | 海报顶部圆角(卡片用) |
|
||
| `bg_play_button.xml` | 播放按钮橙色渐变 + 24dp 大圆角 |
|
||
| `bg_nav_selected.xml` | 导航选中胶囊背景 |
|
||
| `bg_section_bar.xml` | 楼层标题橙色竖条指示器 |
|
||
| `bg_button_secondary.xml` | 次要按钮半透明圆角 |
|
||
| `bg_dialog.xml` | 支付弹窗渐变背景 + 16dp 圆角 |
|
||
| `bg_qrcode_white.xml` | 二维码白底圆角 |
|
||
|
||
### 5.2 更新 Drawable(4 个)
|
||
|
||
| 文件 | 变更 |
|
||
|------|------|
|
||
| `bg_card.xml` | 纯色 → 渐变层次感,圆角 8→10dp |
|
||
| `bg_card_focus.xml` | 焦点边框白色 → 橙色 |
|
||
| `bg_button_accent.xml` | 纯色 → 渐变,圆角 8→20dp |
|
||
| `bg_search_input.xml` | 圆角优化 |
|
||
|
||
### 5.3 布局优化
|
||
|
||
| 布局文件 | 优化内容 |
|
||
|----------|----------|
|
||
| `item_content.xml` | 海报圆角裁切,标题/评分字号增大,间距优化 |
|
||
| `activity_detail.xml` | 海报 120→150dp 加圆角,播放按钮渐变大圆角(140×52dp),信息区间加分割线,整体字号增大 |
|
||
| `item_nav.xml` | 选中态从下划线改为橙色胶囊背景 |
|
||
| `item_section.xml` | 楼层标题前加橙色竖条指示器 |
|
||
| `activity_home.xml` | 顶栏底部加分割线 |
|
||
| `item_search_result.xml` | 海报圆角,字号增大,间距优化 |
|
||
| `activity_list.xml` | 侧边栏间距优化 |
|
||
| `dialog_payment.xml` | 渐变背景,二维码白底圆角,主按钮渐变,关闭按钮改次要样式 |
|
||
|
||
### 5.4 代码优化
|
||
|
||
| 文件 | 变更 |
|
||
|------|------|
|
||
| `AdapterUtils.kt` | 焦点边框白色 → 橙色,圆角 8→10dp,聚焦时 `bringToFront` |
|
||
| `NavAdapter.kt` | 选中态从 `BottomLineDrawable` 下划线改为 `bg_nav_selected` 胶囊背景 |
|
||
|
||
---
|
||
|
||
## 六、测试情况
|
||
|
||
| 测试项 | 结果 | 备注 |
|
||
|--------|------|------|
|
||
| 设备激活 | ✅ 通过 | 卸载重装后可正常激活 |
|
||
| 鉴权 → 播放(有权益) | ✅ 通过 | 缓存命中后静默播放 |
|
||
| 鉴权 → 支付 → 播放(无权益) | ✅ 通过 | 二维码展示 → 支付 → 发卡 → 播放 |
|
||
| 天卡库存不足 | ✅ 通过 | 正确提示"天卡库存不足" |
|
||
| 切换电影重复播放 | ✅ 通过 | 有效期内不弹窗,直接播放 |
|
||
| SDK 初始化失败 | ✅ 通过 | 清除缓存,Toast 提示错误 |
|
||
| 播放器 16:9 | ✅ 通过 | 不拉伸,保持原始比例 |
|
||
| App 名称显示 | ✅ 通过 | 显示"橘视厅酒店版" |
|
||
| UI 布局美观度 | ✅ 通过 | 圆角海报、渐变卡片、橙色焦点态 |
|
||
|
||
---
|
||
|
||
## 七、关键文件清单
|
||
|
||
```
|
||
MediaApp/app/src/main/java/com/pukka/mediaapp/
|
||
├── network/
|
||
│ ├── DayCardSignUtil.kt # SignManager + 权益缓存 + Retrofit 客户端
|
||
│ └── DayCardApiService.kt # API 接口定义
|
||
├── viewmodel/
|
||
│ └── PaymentViewModel.kt # 支付/鉴权流程状态机
|
||
├── ui/
|
||
│ ├── DetailActivity.kt # 详情页 + 静默播放逻辑
|
||
│ ├── VideoPlayerActivity.kt # ExoPlayer 播放器
|
||
│ └── adapter/
|
||
│ ├── AdapterUtils.kt # 焦点高亮 + 主题色
|
||
│ ├── ContentAdapter.kt # 内容卡片适配器
|
||
│ └── NavAdapter.kt # 导航适配器
|
||
├── model/daycard/
|
||
│ └── DayCardModels.kt # 响应模型(BaseResponse 继承)
|
||
└── utils/
|
||
└── FileLogger.kt # 文件日志工具
|
||
|
||
MediaApp/app/src/main/res/
|
||
├── layout/ # 全部布局文件(已优化)
|
||
├── drawable/ # 14 个 drawable(8 新增 + 4 更新 + 2 原有)
|
||
├── values/
|
||
│ ├── colors.xml # 颜色定义
|
||
│ ├── dimens.xml # 尺寸定义
|
||
│ ├── strings.xml # 字符串(app_name 已改)
|
||
│ └── themes.xml # 主题
|
||
```
|
||
|
||
---
|
||
|
||
## 八、待办与后续
|
||
|
||
- [ ] 天卡过期后自动重新走鉴权流程的体验验证(长期测试)
|
||
- [ ] 支付弹窗在弱网环境下的超时处理优化
|
||
- [ ] UI 在不同分辨率 TV 盒子上的适配验证
|
||
- [ ] 考虑权益缓存过期前提前静默刷新(避免过期瞬间首次播放有延迟)
|