Files
DadaoTask/android/README.md
T
dadao f683436689
CI / backend (push) Canceled after 0s
feat(android): 安卓端第一次真跑起来,修两个联调才暴露的解析 bug
上一轮只是"能编译"。这一轮在模拟器上真装了、真登录、真点了,才发现两个问题:

1. workspaces() / members() 直接按 List 解析,但服务端列表接口返回的是
   {"items": [...]}。表现就是登录成功后首页红字「响应格式异常(HTTP 200)」,
   而且工作区永远显示为空。新增 WorkspacePage / MemberPage 容器类型。
2. 之前 Api.kt 的请求体全是没加 @Serializable 的普通 data class(上一提交已修),
   这次把成员/工作区的解析也按同样思路收口。

环境侧(写进 android/README + 新增 android/scripts/emulator.ps1):
- sdkmanager 拉不到远端索引,系统镜像是直连 dl.google.com 手动装的;
  压缩包里多一层 x86_64/,要把内容提上一层,否则 AGP 找不到 system.img
- AVD 放工程内(~/.android 受限不可写),建 AVD 与启动都靠 ANDROID_USER_HOME / ANDROID_AVD_HOME
- 无头启动要 -no-window -gpu swiftshader_indirect
- 点按坐标要拿 uiautomator dump 的 bounds,别拿降采样截图猜
- adb shell input text 打不了中文(NPE),中文数据走接口或直接写库

验证(模拟器 API 35,连 fnsvr-01 的真库):
登录 → 建工作区 ShipFast → 任务列表显示 4 条中文任务(状态、截止日都对)
→ 勾选完成,条目从「进行中」消失(乐观锁生效)→ 工单页、知识页均正常渲染。
截图放进 2.Design/screens/android-{login,tasks}.png。
2026-10-28 17:04:35 +08:00

113 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 安卓端
Kotlin + Jetpack Compose。功能与 Web 端同构:登录 → 工作区 → 任务 / 工单 / 知识。
## 它已经能编译出 APK 了(本机实测)
```
BUILD SUCCESSFUL in 38s
app/build/outputs/apk/debug/app-debug.apk 9.94 MB
```
而且**真的在模拟器上跑通了**:登录 → 建工作区 → 任务列表(中文标题、状态、截止日、勾选完成)→ 工单列表 → 知识列表,全部打到真实后端。
| 登录 | 任务列表 |
|---|---|
| ![登录](../2.Design/screens/android-login.png) | ![任务](../2.Design/screens/android-tasks.png) |
一键起模拟器 + 装包(环境变量都替你设好了):
```bash
pwsh -File android/scripts/emulator.ps1 -Install
```
本机从零把编译链搭起来踩过的坑都固化在仓库里了,别再走一遍:
| 现象 | 原因 | 仓库里的解法 |
|---|---|---|
| `Failed to load native library 'native-platform.dll'` | 旧 `~/.gradle` 缓存坏了 | 用独立 `GRADLE_USER_HOME`(我用的 `.local/gradle-home`) |
| `validateSigningDebug: AccessDeniedException debug.keystore.lock` | 沙箱/受限用户对 `~/.android` 无写权限 | 工程内 keystore:`android/keystore/debug.keystore`,`app/build.gradle.kts` 显式指向 |
| `compileDebugKotlin: AccessDeniedException %TEMP%\kotlin-compiler-*.alive` | `%TEMP%` 不可写 | 构建前把 `TEMP`/`TMP` 指到工程内可写目录 |
| `Could not connect to Kotlin compile daemon` | 受限环境里 Kotlin 编译守护进程连不回来 | `gradle.properties` 里 `kotlin.compiler.execution.strategy=in-process` |
| 依赖下载极慢(5 分钟 2MB) | Google Maven 直连慢 | `settings.gradle.kts` 先走阿里云镜像,再回落 google/mavenCentral |
需要:**JDK 17**(`JAVA_HOME`)、Android SDK **platform 35** + build-tools。
```bash
cd android
gradle :app:assembleDebug # 或 ./gradlew(wrapper 需 Android Studio 补齐)
```
## 连哪个后端
`android/local.properties`(不入库):
```properties
dadao.apiBase=http://10.0.2.2:8100 # 模拟器访问宿主机
# dadao.apiBase=http://192.168.8.160:8100 # 真机走局域网
```
真机调试时后端必须监听 `0.0.0.0` 而不是 `127.0.0.1`:
```bash
uvicorn app.main:app --host 0.0.0.0 --port 8100
```
`app/src/debug/AndroidManifest.xml` 对 debug 变体放开了明文 HTTP——
release 仍然只允许 `network_security_config.xml` 里列出的域,别把这条挪到 main。
## 安装到手机
```bash
adb install -r app/build/outputs/apk/debug/app-debug.apk
```
首次打开 → 手机号登录(开发环境验证码在接口响应里回显,形如 `开发环境验证码:123456`)。
## 结构
```
app/src/main/java/com/dadao/task/
├── MainActivity.kt 入口 + Splash/Login/Home/Tasks/Knowledge 路由
├── data/
│ ├── Api.kt OkHttp + kotlinx.serialization;信封解包、业务码抛 ApiException
│ └── TokenStore.kt 令牌本地存储(TODO:换 EncryptedSharedPreferences)
└── ui/
├── Theme.kt 与 Web 一致的墨青 + 陶土色板
├── LoginScreen.kt 手机号 + 验证码
├── HomeScreen.kt 工作区列表 / 新建 / 生成邀请码
├── TaskListScreen.kt 任务视图切换、快速新建、勾选完成、详情与评论
└── KnowledgeScreen.kt 知识四态 tab、手记、按状态给动作(发布需 owner/admin)
```
## 模拟器(本机搭建记录,别重复踩)
`sdkmanager` 在这台机器上拉不到远端仓库索引(`Failed to download any source lists!`,但直连
`dl.google.com` 的 zip 是通的),所以系统镜像是**手动装的**:
1. 下 `https://dl.google.com/android/repository/sys-img/google_apis/x86_64-35_r09.zip`(1.66 GB),
解压到 `%LOCALAPPDATA%\Android\Sdk\system-images\android-35\google_apis\x86_64`
—— 注意压缩包里还有一层 `x86_64/`,要**把内容提上一层**,否则 AGP 找不到 `system.img`。
2. 建 AVD 时把用户目录指到工程内(`~/.android` 在受限用户下不可写):
```powershell
$env:ANDROID_USER_HOME="$repo\.local\android-user"
$env:ANDROID_AVD_HOME="$repo\.local\android-avd"
avdmanager create avd -n dadao -k "system-images;android-35;google_apis;x86_64" -d pixel_6 --force
```
3. 启动必须带 `-no-window -gpu swiftshader_indirect`(无头环境下 GL 走软件渲染);
`emulator -accel-check` 应显示 `WHPX ... installed and usable`。
驱动模拟器点按不要凭截图猜坐标——`adb shell input tap` 用的是**物理像素**,而截图常被降采样。
用 `adb shell uiautomator dump` 拿 `bounds` 最稳。另外 `adb shell input text` 打不了中文(会 NPE),
中文数据走接口造。
## 已知待办
- 工单页还没做(Web 已有):需要"我指派的 / 我发起的"两栏 + 接收/开工/提交/验收按钮;
接口在 `Api.kt` 里已经齐了(`tickets` / `ticketAction` / `verifyTicket` / `promote`)。
- 明文令牌存储(`TokenStore` 里已标 TODO)。
- 无离线缓存,弱网直接报错——与产品 D7「在线优先」一致。
- 邀请链接 `https://dadaotask.com/join/<wsId>/<code>` 已在 Manifest 注册,落地处理尚未实现。
- 未在本机跑过模拟器(无 system-image、无连接设备),端到端只验证到"能编译、能装"。