目标 我想创建一个后台服务来监听注册。如果用户成功登录,它将重定向到主页小部件
代码片段 这是我当前的代码片段,用于注册目标,但不用于导航
在 main.dart:
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
void main() async {
WidgetsFlutterBinding.ensureInitialized();
setupLocator();
BackgroundService.initializeService();
// PermissionService.requestPermissions();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
//..providers
],
child: Consumer<AuthProvider>(
builder: (context, authProvider, child) {
return ToastificationWrapper(
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'My App',
theme: ThemeData.light(),
onGenerateRoute: Routes.generateRoute,
initialRoute: Routes.login,
navigatorKey: navigatorKey,
));
},
),
);
}
}
在 background_service.dart:
class BackgroundService {
static final SIPUAHelper _helper = SipHelperManager().getHelper();
static Future<void> startBackgroundService() async {
final service = FlutterBackgroundService();
await service.startService();
}
static void stopBackgroundService() {
final service = FlutterBackgroundService();
service.invoke("stop");
}
static Future<void> initializeService() async {
final service = FlutterBackgroundService();
await service.configure(
iosConfiguration: IosConfiguration(
autoStart: true,
onForeground: onStartForeground,
onBackground: onIosBackground,
),
androidConfiguration: AndroidConfiguration(
autoStart: true,
onStart: onStartForeground,
isForegroundMode: true,
autoStartOnBoot: true,
initialNotificationTitle: 'My Softphone',
initialNotificationContent: 'Online',
foregroundServiceTypes: [
AndroidForegroundType.phoneCall,
AndroidForegroundType.microphone,
AndroidForegroundType.mediaPlayback
],
),
);
}
//....
@pragma('vm:entry-point')
static void onStartForeground(ServiceInstance service) async {
service.on('login').listen((event) async {
// ...
SipUAListenerBackground newListener =
SipUAListenerBackground(service);
_helper.addSipUaHelperListener(newListener);
//...
}
}
}
class SipUAListenerBackground implements SipUaHelperListener{
@override
void registrationStateChanged(RegistrationState state) async {
// if state is Registerd
navigatorKey.currentState?.pushNamed('/home'); <--- currentState is null
}
}
为什么我发布不起作用的代码片段 因为这可能是最接近我想要的存档的代码
我尝试了什么
我尝试使用 Get-It 定义一个 NavigationService 类,但它也不起作用。它说 NavigationService 未在 Get-It 中注册
我尝试使用 Isolate 创建后台服务,而不是依赖 flutter 后台服务,但出现错误:
UI actions are only available on root isolate.
我需要你的帮助
The issue with navigatorKey.currentState being null stems from Flutter's background services being isolated from the main UI. Background services cannot directly access the UI thread, which includes manipulating the navigation state. This is why using FlutterBackgroundService or Isolates doesn’t permit UI changes like navigating between screens.
One workaround is to utilize Flutter’s Stream or EventChannel to send data from the background service to the main UI, which then listens for that event and performs the navigation. Here's a structured approach you can follow:
Use Stream or EventChannel for Communication: Set up a stream or event channel to allow the background service to communicate with the main isolate. Then, your AuthProvider (or any other provider) listens for changes and handles the navigation.
Listen in AuthProvider: Add a listener in AuthProvider that listens for successful registration or login states, and when these states are detected, navigate to the Home screen.
Here’s how you can implement it:
1. Modify BackgroundService to Use Stream
Use a StreamController to send login events.
import 'dart:async';
class BackgroundService {
static final StreamController<String> _loginController = StreamController<String>.broadcast();
static Stream<String> get loginStream => _loginController.stream;
static Future<void> initializeService() async {
final service = FlutterBackgroundService();
await service.configure(
androidConfiguration: AndroidConfiguration(
autoStart: true,
onStart: onStartForeground,
isForegroundMode: true,
autoStartOnBoot: true,
initialNotificationTitle: 'My Softphone',
initialNotificationContent: 'Online',
),
);
}
@pragma('vm:entry-point')
static void onStartForeground(ServiceInstance service) async {
service.on('login').listen((event) async {
// Example login event detection
if (event == 'successful_login') {
_loginController.add('login_successful');
}
});
}
}
2. Listen for the Stream in AuthProvider
In your AuthProvider (or other provider), listen to the stream and trigger navigation when the event is received.
import 'package:flutter/material.dart';
import 'background_service.dart';
class AuthProvider with ChangeNotifier {
AuthProvider() {
_listenToLoginStream();
}
void _listenToLoginStream() {
BackgroundService.loginStream.listen((event) {
if (event == 'login_successful') {
navigatorKey.currentState?.pushNamed('/home');
}
});
}
}
3. Update MyApp to Use the AuthProvider
Since AuthProvider is already used in MyApp, it will listen for background service events and handle navigation.
4. Trigger the Background Service Login Event
Make sure your background service sends the 'login' event when the user logs in. For example, in SipUAListenerBackground:
class SipUAListenerBackground implements SipUaHelperListener {
@override
void registrationStateChanged(RegistrationState state) async {
if (state == RegistrationState.registered) {
BackgroundService.loginStream.add('login_successful'); // Send event to UI
}
}
}