技术文档

Android 客户端

星线 Android 使用 Kotlin 与 Jetpack Compose 实现聊天、工作台、记忆和个人设置。当前工程版本标记为预览版;本文说明源码组织、构建配置、数据流和平台能力边界。

工具链声明

配置 当前源码值
applicationId / namespace cn.thestarline.workbench
最低系统 Android 8.0,API 26
compileSdk / targetSdk 35 / 35
Java / Kotlin JVM target 17 / 17
Kotlin 与 Compose 编译插件 2.0.21
Android Gradle Plugin 8.7.3
Gradle Wrapper 9.2.1
versionName / versionCode 1.0.6-preview / 7

这些是仓库配置声明。本轮没有执行构建,Gradle 与 AGP 的兼容性、开发机 JDK 和最终产物版本需在发布环境核对;不能仅凭配置表认定工具链已验证。Compose BOM 声明为 2024.12.01,通话使用 LiveKit Android 2.29.0,扫码使用打包式 ML Kit、CameraX 与 ZXing。

入口与页面状态

MainActivity 创建 AppState,接收初始 Intent 和后续深链,再通过 StarlineApp 组合页面。AppState 集中维护当前 tab、page、会话、聊天列表、新事、任务、收藏和记忆状态,使用 Compose 可观察状态与协程更新界面。

页面由 tab:page 状态映射到聊天、账号、任务、浏览器、记忆编辑、转出和扫码等 Composable。主布局处理状态栏、导航栏与输入法 inset,内容宽度上限为 720dp;底部导航按当前页面显示。页面切换和新事卡片过渡会读取系统动画开关。Activity 销毁时调用状态清理,停止所属任务和资源。

修改现有功能时应沿用 AppState 的操作入口和页面状态,避免在独立 Composable 中再建一套会话或持久化状态。新数据模型应明确字段兼容规则;当前大量服务对象使用 JSONObject,新增字段应防止缺失值导致崩溃。

网络与认证

ServiceApi 在 IO 协程中使用 HttpURLConnection,负责 JSON 请求、媒体上传、受大小限制的下载以及服务端错误转换。普通请求、事件轮询和媒体操作使用不同超时。AppState 的事件循环调用 /events 并刷新当前会话与页面数据。

starlineChatBaseUrl Gradle 属性生成 BuildConfig.CHAT_BASE_URL,默认指向 https://chat.thestarline.cn。Release 清单禁止明文流量,Debug 清单单独允许本地 HTTP 联调。即使构建属性接受 HTTP,正式包仍受清单限制;测试服务和账号服务应使用同一环境。

登录使用本机 PKCE 事务,打开 Account 返回的验证页面,经 starlineworkbench://chat-auth 回到 App。待处理事务和会话使用本机加密文件保存。配置与安全约束见认证。

本机数据与系统能力

LocalData 将任务、收藏、最近访问和偏好保存在私有 SharedPreferences;会话、记忆索引和附件经过 SecureFile 加密写入私有文件。密钥由 Android Keystore 生成,算法为 256 位 AES-GCM,写入先落临时文件并同步后重命名。清单设置 allowBackup=false。任务和普通偏好并未因此变成 AES-GCM 加密数据,数据分类见安全与隐私。

扫码相机由 CameraX 绑定生命周期,ML Kit 在本机解析二维码;也可选择图片或手动输入。实时位置通过 LiveLocationService 前台服务和持续通知维持,城市贴纸识别采用另一条短时定位路径。文件预览使用私有 FileProvider 与临时 URI 授权。权限细节见权限与可访问性。

与 iOS 的具体差异

范围 Android 当前行为
个人任务 待办/已完成/全部,无独立任务搜索与逾期筛选;日期选到当天末尾
首页今日待办 包含正数到期且不晚于今天末尾的未完成项,实际也包含历史逾期
网站去重 比较完整 URL 字符串,不复用 iOS 去 fragment、默认端口的规范化
记忆主题 固定模板和关键词;不调用 iOS FoundationModels
原生 pending 保存 verifier/state/到期时间,不持久化 API 基址或换票 ticket
授权来源 当前仅信任正式 Account HTTPS,覆盖聊天地址不会自动放行本地 Account
普通发送重试 未确认 clientId 保存在进程内映射,按账号、聊天范围和具体提交内容绑定
记忆转出 授权后先选目标 URI,再本机生成文件;无通用导入入口

这些差异需要在调用方和测试预期中体现,不能用 iOS 的页面、持久化策略或测试结果代替 Android 验收。任务和浏览器实现见工作台,存储字段与兼容见本机数据格式。

MainActivity 销毁会 dispose 当前 AppState、停止所属协程并释放通话资源;持续位置共享另由前台服务管理。切到后台与 Activity 销毁不同,关闭聊天页也不自动结束位置或通话。普通事件轮询不是后台通知服务,短时重连、进程恢复和锁屏来电需分别验证,见客户端生命周期。

开发与验收

在 android-app 目录可执行:

./gradlew :app:testDebugUnitTest :app:assembleDebug

设备测试放在 app/src/androidTest,本地单元测试放在 app/src/test。本轮只审阅源码,没有执行以上命令或安装 APK。已有测试文件不表示当前提交已经通过。

Android 预览客户端与 iOS 并非所有能力对等:iOS 系统模型主题生成没有移植,Android 使用本机关键词推荐;Rust OpenMLS 加密聊天尚未接入。后台来电推送、真机跨网络音视频、真实相机与完整多因素转出应分别验收,不能由模拟器页面或 active 信令状态推断完成。参见本地记忆、消息与媒体、测试和发布。

Markdown 原文完整文档文本