0

Goal I want to creating a background service to listen for registration. And if user successfully logged in then it will redirect to home page widget

Code snippet Here is my current code snippet work with the registration goal but not the navigation

in 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,
          ));
        },
      ),
    );
  }
}

in 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
  }

}

Why i post the not working code snippet Because this is probably the closest code to archive what i want

What i tried

I tried to use Get-It to define a NavigationService class but it didn't work too. It said NavigationService is not registed in Get-It

I tried to use Isolate to create background service instead of relying on flutter background service but i got error: UI actions are only available on root isolate.

I need your help

  • Can anyone tell me why the currentState is null in my closest code snippet
  • And if you can't then how can we work with navigation in foreground service (I did look it up but nothing seem working for me)

Update

  • I need to navigate the application using foreground service and i also need to pass object to the navigation code because my routes need some parameters

1 Answer 1

0
        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
    }
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

It's not my requirement tho. Because i want to navigate even if the application is terminated. And if i use the stream-listener method then it won't work because the listener will be terminated as the application killed. Thank you for help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.