我正在开发一个 Flutter 项目,其中使用后台服务(带有 flutter_background_service 包)来处理 WebSocket 连接。即使应用程序位于后台,WebSocket 也会收到更新。我的目标是将后台服务中接收到的 WebSocket 数据流式传输到主应用程序,以便 UI 可以实时更新。
final service = FlutterBackgroundService();
Future<void> initializeService() async {
await service.configure(
iosConfiguration: IosConfiguration(
autoStart: true, onForeground: onStart, onBackground: onBackground),
androidConfiguration: AndroidConfiguration(
autoStartOnBoot: false,
onStart: onStart,
isForegroundMode: true,
autoStart: false),
);
}
IO.Socket? socket;
void connectWebSocket(String uniqueId) {
const String serverUrl = 'http://test.buggyhub.com:4000/';
socket = IO.io(
serverUrl,
IO.OptionBuilder()
.setTransports(['websocket'])
.disableAutoConnect()
.build(),
);
socket?.connect();
socket?.onConnect((_) {
log('Connected to server with unique ID: $uniqueId');
socket?.emit('sarthiId', uniqueId);
});
socket?.on('connectionResponse', (data) {
log('Message from server: $data');
});
socket?.on('bookingUpdate', (data) async {
log('Received bookingUpdate from server: $data');
// I want to stream this data to the main app
});
socket?.onDisconnect((_) {
log('Disconnected from server');
});
}
@pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
WidgetsFlutterBinding.ensureInitialized();
DartPluginRegistrant.ensureInitialized();
if (service is AndroidServiceInstance) {
service.on('setAsForeground').listen((event) {
service.setAsForegroundService();
});
service.on('setAsBackground').listen((event) {
service.setAsBackgroundService();
});
service.on('stopService').listen((event) {
service.stopSelf();
});
}
Timer.periodic(const Duration(seconds: 20), (timer) async {
if (service is AndroidServiceInstance && await service.isForegroundService()) {
log('Running background service');
socket?.disconnect();
connectWebSocket('uniqueId');
}
});
await Firebase.initializeApp();
}
@pragma('vm:entry-point')
Future<bool> onBackground(ServiceInstance serviceInstance) async {
WidgetsFlutterBinding.ensureInitialized();
DartPluginRegistrant.ensureInitialized();
await Firebase.initializeApp();
return true;
}
我的问题:
如何将WebSocket数据(在后台服务中接收)以流的形式发送到主应用程序,以便它可以用于实时更新UI?
我尝试过的:
我知道 Flutter 中的 StreamController 和 Stream,但不确定如何使用后台服务中运行的 WebSocket 的数据来实现这一点。
即使应用程序位于后台,我也想保持此流连接,并在应用程序位于前台时更新 UI。
任何有关如何实现这一目标的帮助或建议将不胜感激!
基本示例
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await initializeService(); runApp(const MyApp()); }
Future<void> initializeService() async { final service = FlutterBackgroundService();
await service.configure(
androidConfiguration: AndroidConfiguration(
// this will be executed when app is in foreground or background in separated isolate
onStart: onStart,
// auto start service
autoStart: false,
isForegroundMode: false,
),
iosConfiguration: IosConfiguration(
// auto start service
autoStart: false,
// this will be executed when app is in foreground in separated isolate
onForeground: onStart,
), ); }
void onStart(ServiceInstance service) async { service.on('toServer').listen((data) {
///////////////////////////////////////////////////
//here you code use websocket to send data to server });
//////////////////////////////////////////////////////// //here you code use websocket to receive data from server await Future.delayed(const Duration(seconds: 1)); service.invoke('fromServer', {"data": "Text expample 1 secons"}); await Future.delayed(const Duration(seconds: 5)); service.invoke('fromServer', {"data": "Text expample 5 secons"}); }
class MyApp extends StatefulWidget { const MyApp({super.key});
@override State<MyApp> createState() => _MyAppState(); }
class _MyAppState extends State<MyApp> { final bgService = FlutterBackgroundService();
@override Widget build(BuildContext context) {
final Stream<Map<String, dynamic>?> fromServer = bgService.on('fromServer');
//Send data to server
bgService.invoke('toServer', {"data": "Text expample"});
return MaterialApp(
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: const Text('Material App Bar'),
),
body: Center(
child: StreamBuilder<Map<String, dynamic>?>(
stream: fromServer,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const CircularProgressIndicator();
}
return Text(
snapshot.data!['data'].toString(),
style: const TextStyle(fontSize: 24),
);
},
),
),
),
); } }