Files
tongxunruanjian/mobile/README.md
T
1d393f4f1e fix(mobile): 让华为 AGConnect 在 AGP 9 下能识别真实配置
放入 agconnect-services.json 后原插件坐标无法解析,且 1.9.1 不兼容 AGP 9。
映射到 agcp 1.9.5.301,Gradle 可按包名校验;该文件继续忽略不入库。

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: multica-agent <github@multica.ai>
2026-08-31 00:56:12 +08:00

101 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.
# 畅联 · 手机端(Flutter
公司内部通讯 App 的手机端源码。骨架配色走企业微信式办公风(主色蓝 `#3B87F5`),聊天手感照微信。仓库已带 `android/``ios/` 平台脚手架与全部权限声明,**不需要再跑 `flutter create`**。
## 打包 / 运行
打包是开发机上的事,**服务器上不需要装 Flutter**(服务器只跑 docker 后端)。在装好 Flutter 与 Android SDK 的开发机上:
```bash
cd mobile
flutter pub get
flutter build apk --release # 出安卓安装包 build/app/outputs/flutter-apk/app-release.apk
```
iOS 需要一台 Mac 搭配 Xcode 与开发者证书,另按苹果流程打包。
已声明的平台权限(勿删):
- `android/app/src/main/AndroidManifest.xml``INTERNET``RECORD_AUDIO`(语音消息/通话)、`MODIFY_AUDIO_SETTINGS`、存储/相册读取(发文件、发图片)、`POST_NOTIFICATIONS`(极光离线通知)。公网默认 HTTPS;内网联调 `--dart-define=USE_TLS=false` 时仍允许明文,故暂保留 `usesCleartextTraffic`
- `ios/Runner/Info.plist``NSMicrophoneUsageDescription`(语音消息与通话)、`NSPhotoLibraryUsageDescription`(发图片)、`NSAppTransportSecurity/NSAllowsArbitraryLoads`(同上,内网明文)。
- `android/build.gradle.kts` / `settings.gradle.kts` 把阿里云 Maven 镜像放在最前(本网络访问 maven.google.com 不稳定),并增加华为 Maven(厂商通道)。
## 修改服务器地址
所有服务器地址集中在 `lib/config.dart`。默认公网:`jxd.jinniu.ink` + HTTPS/WSS。
内网联调不要改文件,打包时覆盖:
```bash
flutter build apk --release \
--dart-define=SERVER_HOST=192.168.200.11 \
--dart-define=USE_TLS=false
```
仅覆盖登录服务:`--dart-define=AUTH_HOST=127.0.0.1`
| 常量 | 用途 | 公网默认 |
| --- | --- | --- |
| `apiAddr` | OpenIM API | `https://jxd.jinniu.ink` |
| `wsAddr` | OpenIM WebSocket | `wss://jxd.jinniu.ink/msg_gateway` |
| `livekitUrl` | LiveKit 语音通话 | `wss://jxd.jinniu.ink/livekit` |
| `authApiBase` | 公司账号登录后端 | `https://jxd.jinniu.ink/account` |
华为厂商通道需要本地放置 `android/app/agconnect-services.json`(与包名 `cn.solsum.jinxunda` 对应),取得方式见 `android/app/README-agconnect.md`。不要把该文件提交进 Git。
## 登录接口契约(后端:任务 B-60 account-service,已上线)
### 1. 账号登录
```
POST {authApiBase}/api/login
Content-Type: application/json
{"staffNo": "工号", "password": "...", "platformID": 1}
```
- `platformID`1 = iOS2 = Android。
- 响应统一包络 `{"code": 0, "msg": "", "data": {...}}`(业务失败也是 HTTP 200 + `code != 0`HTTP 401/400 时同样带 `msg`)。
- 成功 `data``{"userID": "...", "nickname": "...", "imToken": "...", "expireTimeSeconds": ...}`
- `userID` / `imToken` 直接传给 OpenIM SDK 的 `login`OpenIM 的登录 token 由后端用 OpenIM 管理端接口换取)。
- 失败:`msg` 会原样展示给用户。
App 登录流程:`AuthApi.login` → 拿到 userID/imToken → `IMService.login`SDK `initSDK` 在 App 启动时已执行一次)→ 进主页。userID/imToken 存 `shared_preferences`,下次启动自动登录;SDK 回调 `onUserTokenExpired` / `onKickedOffline` 时清凭证回登录页。
### 2. 语音通话 token
官方样板工程的 LiveKit token 取自 open-im-chat 业务服务端(`/user/rtc/get_token`,端口 10008),本项目服务端裁剪时移除了 open-im-chat,由 account-service 提供等价接口:
```
POST {authApiBase}/api/rtc_token
Authorization: Bearer {登录返回的 imToken}
Content-Type: application/json
{"room": "房间号", "identity": "当前用户 userID"}
```
- 成功 `data``{"token": "LiveKit 访问 token"}`App 使用 `config.dart` 中的 `livekitUrl` 作为连接地址;后端用与 livekit 容器同一对 `LIVEKIT_API_KEY` / `LIVEKIT_API_SECRET` 签发 HS256 JWT)。
- 后端会先拿 `Authorization` 里的 IM token 调 OpenIM `parse_token` 校验身份,且要求 `identity` 与 token 对应的 userID 一致。
- 通话信令(呼叫/接听/拒绝/取消/挂断)走 OpenIM 自定义消息(customType 200-204 的仅在线消息),与官方样板工程协议一致,不需要后端参与。
## 代码结构
```
lib/
main.dart 入口:主题、路由、启动页(自动登录)、被踢下线/来电处理
config.dart 服务器地址集中配置
theme.dart 颜色、字号阶梯(4 级)、间距常量(4 的倍数)
models/signaling.dart 通话信令数据模型(与官方样板一致)
utils/format.dart 时间格式化、文件大小、会话预览文案
services/
im_service.dart OpenIM SDK 封装:init/login/监听/会话列表(ChangeNotifier
auth_api.dart 公司账号登录 + LiveKit token 的 HTTP 客户端(dio
call_service.dart 一对一语音通话:信令 + LiveKit 房间
screens/ 登录、主页三 Tab(消息/通讯录/我的)、聊天、通话等页面
widgets/ 头像、消息气泡、输入栏、四态视图
```
## 测试账号
员工账号由管理员在 account-service 管理页批量导入(工号 + 姓名 + 初始密码),App 端不开放自助注册。联调时请管理员先导入测试名单。