Files
tongxunruanjian/mobile
KIMI 3b5c76cac4 fix: 修复手机连不上服务器时启动页无限转圈(B-58)
- 启动页先读本地凭证:无凭证(首次打开)直接进登录页,不再先等 SDK 初始化
- SDK init/login 加 20s 超时;init 用共享 Future 防止超时后重复触发 initSDK
- 登录页对 IM 登录超时给出明确提示(确认手机连着公司内网 WiFi)
- 修复 flutter create 模板遗留的 widget_test(引用不存在的 MyApp),改为登录页渲染冒烟测试
- 版本号 1.0.1+2
2026-08-15 14:54:52 +08:00
..

畅联 · 手机端(Flutter

公司内部通讯 App 的手机端源码。骨架配色走企业微信式办公风(主色蓝 #3B87F5),聊天手感照微信。仓库已带 android/ios/ 平台脚手架与全部权限声明,不需要再跑 flutter create

打包 / 运行

打包是开发机上的事,服务器上不需要装 Flutter(服务器只跑 docker 后端)。在装好 Flutter 与 Android SDK 的开发机上:

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.xmlINTERNETRECORD_AUDIO(语音消息/通话)、MODIFY_AUDIO_SETTINGS、存储/相册读取(发文件、发图片);并开启了 usesCleartextTraffic(内网服务器暂用 http/ws 明文,开通外网改 HTTPS 后应移除)。
  • ios/Runner/Info.plistNSMicrophoneUsageDescription(语音消息与通话)、NSPhotoLibraryUsageDescription(发图片)、NSAppTransportSecurity/NSAllowsArbitraryLoads(同上,内网明文)。
  • android/build.gradle.kts / settings.gradle.kts 把阿里云 Maven 镜像放在最前(本网络访问 maven.google.com 不稳定)。

修改服务器地址

所有服务器地址集中在 lib/config.dart,改 serverHost(内网 IP/域名)和对应端口常量即可:

常量 用途 默认值
apiAddr OpenIM API http://192.168.200.11:10002
wsAddr OpenIM WebSocket ws://192.168.200.11:10001
livekitUrl LiveKit 语音通话 ws://192.168.200.11:17880(注意已重映射,非默认 7880
authApiBase 公司账号登录后端 http://192.168.200.11:10010

登录接口契约(后端:任务 B-60 account-service,已上线)

1. 账号登录

POST {authApiBase}/api/login
Content-Type: application/json

{"staffNo": "工号", "password": "...", "platformID": 1}
  • platformID1 = iOS2 = Android。
  • 响应统一包络 {"code": 0, "msg": "", "data": {...}}(业务失败也是 HTTP 200 + code != 0HTTP 401/400 时同样带 msg)。
  • 成功 data{"userID": "...", "nickname": "...", "imToken": "...", "expireTimeSeconds": ...}
    • userID / imToken 直接传给 OpenIM SDK 的 loginOpenIM 的登录 token 由后端用 OpenIM 管理端接口换取)。
  • 失败:msg 会原样展示给用户。

App 登录流程:AuthApi.login → 拿到 userID/imToken → IMService.loginSDK 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 端不开放自助注册。联调时请管理员先导入测试名单。