放入 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>
101 lines
5.3 KiB
Markdown
101 lines
5.3 KiB
Markdown
# 畅联 · 手机端(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 = iOS,2 = 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 端不开放自助注册。联调时请管理员先导入测试名单。
|