局域网内Docker化离线Android推送通知方案咨询(支持服务器切换)
实现方案
一、Docker化离线通知服务搭建
1. 选型:EMQX MQTT Broker
选择EMQX作为通知核心服务,它支持Docker容器化部署,完全无需外部依赖,可离线运行,同时支持原生MQTT协议(适配移动端)和MQTT over WebSocket(适配Web端),满足多端通知需求。
2. Docker-compose配置
在你的docker-compose.yml中添加EMQX服务,配置端口映射和本地存储挂载,确保重启后配置和消息不丢失:
version: '3.8' services: emqx: image: emqx/emqx:5.1 container_name: emqx-broker ports: - "1883:1883" # MQTT原生端口(移动端用) - "8083:8083" # MQTT over WebSocket端口(Web端用) - "18083:18083" # EMQX管理控制台端口(可选,用于调试) volumes: - ./emqx/data:/opt/emqx/data - ./emqx/log:/opt/emqx/log - ./emqx/etc:/opt/emqx/etc restart: always
主服务器和本地服务器都用这套配置启动EMQX即可。
3. 通知发送与接收逻辑
- 服务端发通知:业务服务(同样Docker化)通过MQTT客户端连接EMQX,将通知消息发布到指定主题(如
/notifications/user/{userId})。 - Flutter端收通知:集成
mqtt_client库,根据当前服务器地址连接对应的EMQX实例:- 移动端:连接
tcp://{server_ip}:1883 - Web端:连接
ws://{server_ip}:8083/mqtt
订阅对应主题后实时接收通知;同时用本地存储(如Hive、SharedPreferences)缓存通知记录,离线时也能查看历史通知。
- 移动端:连接
二、Flutter应用多服务器切换实现
1. 服务器配置管理
在应用中添加服务器设置页面,允许用户输入或选择主服务器/本地服务器地址(可预设默认值),将选中的地址保存到本地存储:
import 'package:shared_preferences/shared_preferences.dart'; class ServerConfig { static const String _currentServerKey = 'current_server'; static const String _mainServerUrl = 'https://main-server.com'; static const String _localServerUrl = 'http://local-server:8080'; static Future<String> getCurrentServer() async { final prefs = await SharedPreferences.getInstance(); return prefs.getString(_currentServerKey) ?? _mainServerUrl; } static Future<void> switchToMainServer() async { final prefs = await SharedPreferences.getInstance(); await prefs.setString(_currentServerKey, _mainServerUrl); } static Future<void> switchToLocalServer() async { final prefs = await SharedPreferences.getInstance(); await prefs.setString(_currentServerKey, _localServerUrl); } }
2. 全局连接切换逻辑
封装网络请求和MQTT连接工具类,依赖ServerConfig获取当前服务器地址,切换时自动断开旧连接并重新连接:
import 'package:mqtt_client/mqtt_client.dart'; import 'package:mqtt_client/mqtt_server_client.dart'; class MqttService { late MqttServerClient _client; String? _currentServer; Future<void> connect() async { final serverUrl = await ServerConfig.getCurrentServer(); if (_currentServer == serverUrl && _client.connectionStatus?.state == MqttConnectionState.connected) { return; } // 断开旧连接 if (_currentServer != null) { _client.disconnect(); } // 初始化新连接 final host = serverUrl.split('://')[1]; _client = MqttServerClient.withPort(host, 'flutter-client', 1883); _client.setProtocolV311(); _client.keepAlivePeriod = 30; try { await _client.connect(); _currentServer = serverUrl; // 订阅用户专属通知主题 _client.subscribe('/notifications/user/123', MqttQos.atLeastOnce); _client.updates?.listen((List<MqttReceivedMessage<MqttMessage>> messages) { final message = messages.first.payload as MqttPublishMessage; final payload = MqttPublishPayload.bytesToStringAsString(message.payload.message); // 处理通知逻辑(如弹出本地通知、更新UI) print('收到通知: $payload'); }); } catch (e) { print('MQTT连接失败: $e'); _client.disconnect(); } } }
3. 状态同步与UI更新
使用状态管理工具(如Provider)维护当前服务器状态,所有依赖地址的UI和业务逻辑监听状态变化自动更新:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; class ServerState with ChangeNotifier { String _currentServer = 'https://main-server.com'; String get currentServer => _currentServer; Future<void> init() async { final prefs = await SharedPreferences.getInstance(); _currentServer = prefs.getString('current_server') ?? _currentServer; notifyListeners(); } Future<void> switchServer(String serverUrl) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString('current_server', serverUrl); _currentServer = serverUrl; notifyListeners(); // 触发MQTT重连和API客户端更新 await MqttService().connect(); } }
4. 离线场景适配
本地服务器场景下,确保所有业务服务(API、EMQX)通过docker-compose一起部署,形成完整离线环境;Flutter端切换到本地服务器后,自动更新所有API请求的baseUrl,避免依赖外部网络。
内容的提问来源于stack exchange,提问作者unownone
相关产品推荐
相关产品推荐

