# 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。*