# 橘视厅酒店版 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 盒子上的适配验证 - [ ] 考虑权益缓存过期前提前静默刷新(避免过期瞬间首次播放有延迟)