CI / backend (push) Canceled after 0s
纸白底改冷调与主色同轴;语义色 sage/wheat/rust 不变,sky 提亮与主色区分。Logo 三段线改浅蓝白、圆点改亮蓝;favicon/PWA 图标/安卓自适应图标/状态栏一并重绘,新增 tools/make-icons.py 作为唯一出处。
130 lines
6.5 KiB
Markdown
130 lines
6.5 KiB
Markdown
# 安卓端
|
||
|
||
Kotlin + Jetpack Compose。功能与 Web 端同构:登录 → 工作区 → 任务 / 工单 / 知识。
|
||
|
||
## 它已经能编译出 APK 了(本机实测)
|
||
|
||
```
|
||
BUILD SUCCESSFUL in 38s
|
||
app/build/outputs/apk/debug/app-debug.apk 9.94 MB
|
||
```
|
||
|
||
而且**真的在模拟器上跑通了**:登录 → 建工作区 → 任务列表(中文标题、状态、截止日、勾选完成)→ 工单列表 → 知识列表,全部打到真实后端。
|
||
|
||
| 登录 | 任务列表 |
|
||
|---|---|
|
||
|  |  |
|
||
|
||
一键起模拟器 + 装包(环境变量都替你设好了):
|
||
|
||
```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 补齐)
|
||
```
|
||
|
||
## 连不上后端?先看这三件事
|
||
|
||
1. **后端要监听所有网卡**:`uvicorn app.main:app --host 0.0.0.0 --port 8100`。
|
||
默认的 `127.0.0.1` 只有本机可见,手机连不上。
|
||
2. **地址要填对**:包里的默认值是模拟器地址 `http://10.0.2.2:8100`。
|
||
真机在登录页点「改地址」填电脑的局域网 IP(如 `http://192.168.8.151:8100`),
|
||
点「测试连接」看到「连得通」再登录。改一次会记住,不用重新打包。
|
||
3. **防火墙**:Windows 没弹过「允许访问」的话,手机包会被丢。管理员 PowerShell 执行
|
||
`New-NetFirewallRule -DisplayName "DadaoTask backend 8100" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8100 -Profile Private`。
|
||
|
||
还有一个容易查半天的点:主清单配了 `network_security_config`(白名单只有
|
||
`10.0.2.2/127.0.0.1/localhost`),这种情况下 `android:usesCleartextTraffic="true"` **不生效**,
|
||
真机连 `http://192.168.8.x` 会被系统拦成 "CLEARTEXT communication not permitted",
|
||
表现就是"点了登录没反应/登录不上去",而模拟器一切正常。
|
||
所以 `android/app/src/debug/res/xml/network_security_config.xml` 单独给 debug 放开了明文,
|
||
release 依旧只走 HTTPS 白名单。
|
||
|
||
## 连哪个后端
|
||
|
||
`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、无连接设备),端到端只验证到"能编译、能装"。
|