Files
lumaplayer/CODE_REVIEW_2026-09-06.md
beyondandClaude Opus 5 6e5c9fce95 全面安全加固 + UI一致性 + 功能修复 + 性能优化
安全修复:
- usesCleartextTraffic=false + network_security_config.xml (LAN例外)
- 备份规则排除数据库/SP/缓存 (backup_rules.xml, data_extraction_rules.xml)
- ProGuard Release移除 Log.d/Log.v
- EmbyRepository 日志脱敏 + API Key安全注释
- EmbyServer URL长度/主机名/端口验证

UI一致性:
- LumaDesignSystem 新增16个颜色令牌 + LumaBorders + 2个排版令牌
- 6个屏幕文件硬编码颜色统一到LumaColors
- 排版统一 17sp→18sp, 30sp→32sp, 34sp→32sp

功能修复:
- 首页MyMediaGrid点击导航到库列表
- 搜索齿轮图标导航到设置
- FavoritesAllScreen/HomeLibraryAllScreen 添加下拉刷新
- RecordsScreen 13+硬编码中文→stringResource() + 修复count bug
- 新增16个日历字符串(中英文)

性能优化:
- TMDB数据类添加@Immutable注解
- HomeContentCache添加LRU驱逐策略(最多3个快照)
- VideoPlayerScreen内部轮询从250ms降至500ms

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 16:43:25 +08:00

15 KiB
Raw Permalink Blame History

LumaPlayer 全面代码审查报告

项目: LumaPlayer (com.example.myapplication) — Emby 媒体库客户端 审查日期: 2026-09-06 审查范围: UI 一致性 / 安全漏洞 / 性能问题 / 功能缺失 / 代码质量 审查方法: 5 个专项代理并行审查,阅读全部 50+ 源文件


📊 总览

审查分类 🔴 Critical 🟠 Major 🟡 Minor 合计
🎨 UI 样式一致性 4 11 15 30
🔒 安全漏洞 3 7 5 15
⚡ 性能问题 0 7 8 15
📋 功能缺失 3 6 14 23
🏗️ 代码质量 1 7 4 12
合计 11 38 46 95

🚨 Top 10 最关键问题

# 严重度 分类 问题 文件
1 🔴 安全 明文密码存储在 Room 数据库(无加密),设备 Root 后密码可读 ServerEntity.java:19
2 🔴 安全 usesCleartextTraffic="true" 全局允许 HTTP 明文传输 AndroidManifest.xml:11
3 🔴 安全 认证接口无证书固定,MITM 可截获用户密码 EmbyRepository.kt:181
4 🔴 代码质量 全项目零 ViewModel,所有业务逻辑在 Composable 内,配置变更丢失状态 全局架构
5 🔴 UI 多处硬编码 Color(0xFF152036) 等暗色值,浅色主题下不可见 MediaDetailScreen.kt:1842
6 🔴 功能 播放设置点击无反应(onClick = {}),连播偏好每次重置 SettingsScreen.kt:158
7 🔴 功能 首页"我的媒体"网格点击无反应,空注释 // Handle selection HomeScreen.kt:1063
8 🔴 功能 搜索栏齿轮图标点击无反应 AppNavHost.kt:214
9 🟠 安全 备份规则为空,数据库含密码被自动备份到云端 AndroidManifest.xml:11-12
10 🟠 安全 50+ 处 catch (_: Exception) 静默吞掉异常,用户看不到真实错误 EmbyRepository.kt 多处

🎨 一、UI 样式一致性(30 个发现)

🔴 Critical(4 个)

C1. 硬编码暗色背景色破坏浅色模式

  • 文件: MediaDetailScreen.kt:1842, 1929
  • 问题: Color(0xFF152036) 作为剧集卡片背景,浅色主题下几乎不可见
  • 建议: 替换为 LocalDetailSurface.current 或从沉浸式调色板派生

C2. EpisodeListDialog 复制了 GlassDialog 的逻辑

  • 文件: MediaDetailScreen.kt:1730-1750
  • 问题: 手动实现 background(pageBottom.copy(alpha = 0.98f)) + dialogBorder,与 GlassDialog 不一致
  • 建议: 统一使用 GlassDialog 或 LumaColors.glassBorder

C3. 在线/离线状态颜色绕过设计令牌

  • 文件: LibraryScreen.kt:119-123,HomeScreen.kt:1260,VideoPlayerScreen.kt:1676
  • 问题: 多处直接用 Color(0xFF34C759) / Color(0xFFFF3B30) / Color(0xFFFF453A),三种不同的红色表示"离线"。LumaColors.success / LumaColors.danger 已定义但被绕过
  • 建议: 统一到 LumaColors.success / LumaColors.danger

C4. LibraryScreen 对话框 overlay 破坏浅色主题

  • 文件: LibraryScreen.kt:934, 1097, 1287
  • 问题: surfaceOverlay = Color.White.copy(alpha = 0.94f) 在暗色主题下产生近不透明白色面板
  • 建议: 使用 LumaColors.background.copy(alpha = 0.94f) 或移除 overlay

🟠 Major(11 个)

# 文件 问题 建议
M1 HomeScreen.kt:407 / MediaDetailScreen.kt:938 星级评分 Color(0xFFFFC107) 无令牌 添加 LumaColors.ratingStar
M2 HomeScreen.kt:837-843 RainbowNumber 渐变色未纳入设计系统 添加到 LumaColors.rainbowGradient
M3 SettingsScreen.kt:406-416 弹窗颜色绕过 LumaColors.regularTint 统一使用令牌
M4 MediaDetailScreen.kt:1278-1280 "最佳资源"徽章金色无令牌 复用 LumaColors.accent
M5 LibraryScreen.kt:844,946,1106 图标库渐变色重复 3 次 提取为命名常量
M6 VideoPlayerScreen.kt:1387-1855 播放器面板 7 种硬编码颜色 创建 PlayerColors 对象
M7 SearchScreen.kt:730 / RecordsScreen.kt:357 海报卡片手动实现而非用 LumaMediaCard 重构使用统一组件
M8 SearchScreen.kt:554 / RecordsScreen.kt:259 等 多处直接用 AsyncImage 而非 LumaAsyncImage 统一替换
M9 多文件 章节标题字体大小不一致(17sp/18sp) 统一到 LumaTypography.title (18sp)
M10 HomeScreen.kt:650 使用 ExtraBold(800) 而设计系统定义 Bold(700) 统一为 Bold
M11 AppBottomBar.kt:35 底栏激活色 #0091FF 与 LumaColors.accent #3B82F6 不同 使用 LumaColors.accent

🟡 Minor(15 个)

# 问题
m1 间距值 8.dp/10.dp/12.dp 直接写而非用 LumaSpacing.*
m2 LumaSettingRow 使用 14.dp 非标准间距
m3 LumaSettingRow 标题用 15.sp 字面值而非 LumaTypography.body
m4 12.sp 字号未纳入排版系统
m5 LumaPageTopBar 用 20.sp 非标准字号
m6 Hero 标题用 30.sp + FontWeight.Black 非标准
m7 MediaDetailScreen 剧集标题 34.sp 非标准
m8-12 5 处缺少 contentDescription(轮播指示器、网格卡片、日历箭头、播放器剧集项)
m13 HomeScreen 离线红色 #FF453A 与其他处 #FF3B30 不同
m14 MediaDetailScreen 返回按钮绕过 LumaIconButton
m15 边框宽度不一致(0.5dp ~ 1.5dp),无 LumaBorders 令牌

🔒 二、安全漏洞(15 个发现)

🔴 Critical(3 个)

S1. 明文密码存储 (CWE-312)

  • ServerEntity.java:19 — 密码和 accessToken 以明文存储在 Room 数据库
  • 建议: 使用 SQLCipher 加密数据库,或至少用 EncryptedSharedPreferences

S2. 全局允许明文流量 (CWE-319)

  • AndroidManifest.xml:11 — usesCleartextTraffic="true" 允许所有 HTTP 明文传输
  • 建议: 设置为 false,添加 network_security_config.xml

S3. 认证无证书固定 (CWE-295/300)

  • EmbyRepository.kt:181 — 密码通过 JSON POST 发送,OkHttp 无 CertificatePinner
  • 建议: 实现证书固定,认证仅走 HTTPS

🟠 Major(7 个)

# CWE 问题 文件
S4 CWE-312 遗留迁移从明文 SP 写入明文 Room ServerRepository.kt:200
S5 CWE-798 TMDB Token 编译进 BuildConfig,APK 反编译可提取 build.gradle.kts:28
S6 CWE-598 api_key 作为 URL 查询参数传输 EmbyRepository.kt:869
S7 CWE-921 allowBackup="true" + 空备份规则,数据库被云端备份 AndroidManifest.xml:11-12
S8 CWE-319 buildServerUrl 支持 HTTP 明文协议 EmbyServer.kt:142
S9 CWE-311 Room 数据库未加密 (emby_player.db) AppDatabase.java:152
S10 异常处理 50+ 处 catch (_: Exception) 静默吞掉错误 EmbyRepository.kt 等

🟡 Minor(5 个)

# 问题
S11 Log.d("EmbyAuth", ...) 在 Release 中仍可见
S12 服务器 URL 输入无长度/格式验证
S13 IconLibrary.kt:167 用 java.net.URL 而非共享 OkHttp 客户端
S14 Log.e 输出异常堆栈可能泄露服务器细节
S15 ProGuard 未配置 -assumenosideeffects 移除 Log.d/v

⚡ 三、性能问题(15 个发现)

🟠 Major(7 个)

# 问题 文件 影响
P1 TmdbCastMember / TmdbRecommendation 等缺少 @Immutable TmdbRepository.kt:21-59 不必要的重组
P2 FavoriteEntity 是 Java 可变类传入 Compose,永远不稳定 FavoriteEntity.java:13 LazyGrid 每项重组
P3 MediaDetailScreen 用 Column + verticalScroll 而非 LazyColumn MediaDetailScreen.kt:489 所有子组件同时组合,内存高
P4 播放器 250ms 轮询 + 内部重复轮询,4次/秒重组整个控件 VideoPlayerScreen.kt:389-434 UI 持续重组
P5 FavoritePosterCard 在主线程解析 JSON RecordsScreen.kt:363 滚动时卡顿
P6 HomeContentCache 无限增长无驱逐 HomeScreen.kt:136 内存泄漏风险
P7 VideoPlayerScreen 单函数 ~1600 行,~40 个状态变量 VideoPlayerScreen.kt:260 任何状态变更重组整个播放器

🟡 Minor(8 个)

# 问题
P8 MyMediaGrid LazyRow 缺少 key
P9 SearchResultsCache 每次服务器完成都 .toList() 拷贝
P10 castMembers 每次重组做 O(n×m) 名称匹配
P11 FavoriteSectionHeader 显示 "$count/$count" 无意义
P12 播放器剧集 LazyColumn 缺少 key
P13 CalendarEpisodeCard 每次重组调 LocalDate.now()
P14 搜索并行化可改进(季/集可缓存)
P15 Hero shuffled() 在主线程执行

📋 四、功能缺失(23 个发现)

🔴 Critical(3 个)

F1. 播放设置为空壳

  • SettingsScreen.kt:158 — 点击无反应,无播放速度/连播/字幕偏好等设置
  • 连播偏好 (confirmBeforeContinuousPlayback) 每次打开播放器重置

F2. 首页"我的媒体"网格点击无反应

  • HomeScreen.kt:1063 — // Handle selection 空注释,点击无导航

F3. 搜索栏齿轮图标无功能

  • AppNavHost.kt:214 — onGearClick = {} 空实现

🟠 Major(6 个)

# 问题 文件
F4 HomeLibraryAllScreen 无下拉刷新 HomeLibraryAllScreen.kt:149
F5 RecordsScreen 收藏/日历 Tab 无下拉刷新 RecordsScreen.kt:137
F6 FavoritesAllScreen 无下拉刷新 FavoritesAllScreen.kt:59
F7 SearchAllScreen 无分页/无限滚动 SearchAllScreen.kt:59
F8 FavoriteSectionHeader 显示 "$count/$count" 数字重复 RecordsScreen.kt:321
F9 日历 Tab 13+ 个中文字符串硬编码,英文模式不翻译 RecordsScreen.kt:580-899

🟡 Minor(14 个)

# 问题
F10 HomeLibraryAllScreen 滚动加载无底部 loading 指示器
F11 搜索历史清除无确认对话框
F12 播放速度偏好不持久化
F13 无 Deep Link 支持
F14 收藏 Tab 无 loading 状态
F15 详情页加载失败无重试按钮
F16 所有导航转场相同,详情→播放器无特殊过渡
F17 播放器错误无重试机制
F18 空库分区显示标题但无内容提示
F19 缓存管理仅清除图标缓存,不含 Coil/搜索历史
F20 日历依赖 TMDB 无回退,失败静默空白
F21 排序弹窗固定高度 304.dp
F22-23 多处交互元素缺少 contentDescription

🏗️ 五、代码质量(12 个发现)

🔴 Critical(1 个)

Q1. 零 ViewModel 架构 — 全项目无 ViewModel

  • 所有业务逻辑在 @Composable 函数中
  • MainApp.kt:146-206 中 addServer/updateServer 含认证逻辑
  • AppNavHost.kt:397-519 中 PlayerDestination 有 8 个 remember 状态变量
  • 影响: 配置变更(旋转/深色切换)丢失状态,无法单元测试
  • 建议: 至少引入 HomeViewModel, MediaDetailViewModel, PlayerViewModel

🟠 Major(7 个)

# 问题 文件
Q2 所有 Repository 是 object 单例,无 DI 框架 全局
Q3 50+ 处 catch (_: Exception) 静默吞掉异常 EmbyRepository.kt 等
Q4 addServer / updateServer 80% 代码重复 MainApp.kt:152-206
Q5 5 个文件超 1000 行(最大 LibraryScreen 2031 行) 见上方
Q6 无结构化协程作用域,单例 CoroutineScope 永不取消 EmbyRepository.kt:151
Q7 仅 9 个测试文件覆盖 ~18K 行代码,Repository 层零测试 test/ 目录
Q8 playbackReportState MutableMap 无同步文档 EmbyRepository.kt:150

🟡 Minor(4 个)

# 问题
Q9 包名 com.example.myapplication 是模板默认值
Q10 EmbyAuthRequest 字段用 PascalCase 违反 Kotlin 命名
Q11 LumaMotion 持续时间命名缺描述性后缀
Q12 ExperimentalAnimationApi opt-in 可能不再需要

🛣️ 优化路线图

📅 短期(1 周)— 安全修复 + 关键 Bug

  1. 安全: usesCleartextTraffic="false" + network_security_config.xml
  2. 安全: 配置备份规则排除数据库
  3. 安全: 添加 ProGuard 规则移除 Log.d/v
  4. 安全: API Key 改用 HTTP Header 传输
  5. 功能: 修复 MyMediaGrid 点击无反应 → 导航到库列表
  6. 功能: 修复搜索齿轮图标 → 导航到设置或移除
  7. 功能: 修复 "$count/$count" 显示 bug
  8. UI: 统一在线/离线颜色到 LumaColors 令牌

📅 中期(1 个月)— 架构重构 + 安全加固

  1. 安全: 实现数据库加密(SQLCipher 或 EncryptedSharedPreferences)
  2. 安全: 添加 OkHttp 证书固定
  3. 架构: 引入至少 3 个 ViewModel(Detail/Player/Home)
  4. 架构: 引入 Hilt 依赖注入
  5. 性能: MediaDetailScreen 改用 LazyColumn
  6. 性能: VideoPlayerScreen 拆分子组件减少重组范围
  7. 功能: 实现播放设置页面(速度/连播/字幕偏好)
  8. 功能: 添加 3 个页面的下拉刷新
  9. 国际化: 日历 Tab 中文硬编码迁移到 strings.xml

📅 长期(3 个月)— 完善 + 可维护性

  1. 架构: 拆分 5 个大文件(LibraryScreen/MediaDetailScreen/VideoPlayerScreen/HomeScreen/EmbyRepository)
  2. 安全: TMDB Token 移至后端代理
  3. 测试: Repository 层单元测试覆盖
  4. 测试: Compose UI 测试覆盖关键流程
  5. UI: 统一排版系统(消除 17sp/20sp/30sp/34sp 离群值)
  6. UI: 创建 LumaBorders 设计令牌
  7. 功能: Deep Link 支持
  8. 功能: 完善缓存管理(Coil/搜索历史/视频缓存)

📈 综合健康评分

评分:6.5 / 10

维度 评分 说明
🎨 UI 一致性 6/10 设计系统完善但被大量绕过,硬编码颜色/字号泛滥
🔒 安全性 4/10 密码明文存储 + 明文传输 + 无证书固定,多项严重漏洞
⚡ 性能 6/10 已做三轮优化但核心架构问题(无 LazyColumn、大重组范围)仍在
📋 功能完整度 7/10 核心功能齐全,3 个空壳占位需实现
🏗️ 代码质量 5/10 无 ViewModel、无 DI、静默异常、大文件、测试不足

优势

  • ✅ 自有 LumaDesignSystem 设计令牌体系
  • ✅ LiquidGlass 创新 UI 效果
  • ✅ 已完成三轮系统性性能优化(@Immutable、remember、并行化)
  • ✅ 分层架构清晰(data/screens/navigation/ui)
  • ✅ 双语支持框架完善
  • ✅ Room + Migration 管理规范

核心短板

  • ❌ 安全基础薄弱(明文密码 + 明文传输)
  • ❌ 缺少 ViewModel 导致状态管理脆弱
  • ❌ 设计令牌定义完善但被大量绕过
  • ❌ 静默异常处理掩盖真实问题

报告由 5 个专项审查模块并行审查后汇总生成。审查时间:2026-09-06。