firebase / flutterfire

🔥 A collection of Firebase plugins for Flutter apps.
https://firebase.google.com/docs/flutter/setup
BSD 3-Clause "New" or "Revised" License
8.71k stars 3.97k forks source link

[firebase_messaging] 6.0.9 - Navigate to a screen when notification is opened is bypassed by default screen #2309

Closed giacomomasseron closed 4 years ago

giacomomasseron commented 4 years ago

Describe the bug I need to navigate to second screen when notification is opened.

If I do it in onLaunch function, the problem is that the time the app is launched, the code in the function is executed and the default screen has been shown instead the second one.

So what the user sees is the second screen for a decimal of seconds, and after that the app launches the default screen.

To Reproduce Steps to reproduce the behavior:

_firebaseMessaging.configure(
    onLaunch: (Map<String, dynamic> message) async {
        // ... navigate to NO default screen
    }
);
TahaTesser commented 4 years ago

Hi @GiacomoK Did you define route for custom screen? can you please provide your flutter doctor -v and flutter run --verbose? Also, to better address the issue, would be helpful if you could post a minimal code sample to reproduce the problem Thank you

giacomomasseron commented 4 years ago

Hi @GiacomoK Did you define route for custom screen?

Yes, the route is defined and working.

can you please provide your flutter doctor -v and flutter run --verbose

╔════════════════════════════════════════════════════════════════════════════╗ ║ A new version of Flutter is available! ║ ║ ║ ║ To update to the latest version, run "flutter upgrade". ║ ╚════════════════════════════════════════════════════════════════════════════╝

[√] Flutter (Channel stable, v1.12.13+hotfix.8, on Microsoft Windows [Versione 6.1.7601], locale it-IT) • Flutter version 1.12.13+hotfix.8 at H:\flutter • Framework revision 0b8abb4724 (8 weeks ago), 2020-02-11 11:44:36 -0800 • Engine revision e1e6ced81d • Dart version 2.7.0

[√] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at H:\Android\sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 28.0.3 • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java • Java version OpenJDK Runtime Environment (build 1.8.0_212-release-1586-b04) • All Android licenses accepted.

[√] Android Studio (version 3.6) • Android Studio at C:\Program Files\Android\Android Studio • Flutter plugin version 44.0.2 • Dart plugin version 192.7761 • Java version OpenJDK Runtime Environment (build 1.8.0_212-release-1586-b04)

[√] Connected device (1 available) • SM A510F • 33004dc9aa4493e1 • android-arm • Android 7.0 (API 24)

• No issues found!

flutter run --verbose is very long, do you need I copy here?

This is the code of main.dart:

// ... import

final navigatorKey = new GlobalKey<NavigatorState>();

final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();

///
/// Navigation Middleware: manage navigation after action is dispatched
///
void navigationMiddleware(
    Store<AppState> store,
    dynamic action,
    NextDispatcher next,
    ) {
  next(action);

  if (action is MyAction) {
    navigatorKey.currentState.push(
        MaterialPageRoute(
            builder: (context) => SecondScreen(appState: store.state, id: action.id)
        )
    );
  }
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final persistor = Persistor<AppState>(
    storage: FlutterStorage(),
    serializer: JsonSerializer<AppState>(AppState.fromJson),
  );

  final initialState = await persistor.load();

  final store = Store<AppState>(
    appReducer, /* Function defined in the reducers file */
    initialState: initialState ?? AppState.initial(),
    middleware: [persistor.createMiddleware(), navigationMiddleware],
  );

  FlutterError.onError = (FlutterErrorDetails details) async {
    if (isInDebugMode) {
      FlutterError.dumpErrorToConsole(details);
    } else {
      Zone.current.handleUncaughtError(details.exception, details.stack);
    }
  };

  runZoned<Future<void>>(() async {
    runApp(MyApp(store: store));
  }, onError: (error, stackTrace) {
    _reportError(error, stackTrace);
  });
}

class MyApp extends StatefulWidget {
  final Store<AppState> store;

  const MyApp({Key key, this.store}) : super(key: key);

  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  var _location = new Location();

  Future<void> onSelectNotification(String payload) async {
    if (payload != null) {
      var message = jsonDecode(payload);
      widget.store.dispatch(new MyAction(message['id']));
    }
  }

  @override
  void initState() {
    super.initState();
    initPlatformState();

    _location.onLocationChanged.listen((LocationData currentLocation) {
      widget.store.dispatch(new ActionGeoLocationChanged(currentLocation.latitude, currentLocation.longitude));
    });

    ///
    /// FIREBASE CODE
    ///
    _firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        UpdateServerHelper.setPushNotificationTokenRead(message['data']['notification_uid']);
      },
      onLaunch: (Map<String, dynamic> message) async {
        void justWait({@required int numberOfSeconds}) async {
          await Future.delayed(Duration(seconds: numberOfSeconds));
        }

        int waitSecs = 3;
        await justWait(numberOfSeconds: waitSecs);

        UpdateServerHelper.setPushNotificationTokenRead(message['notification_uid'] != null ? message['notification_uid'] : message['data']['notification_uid']);

        widget.store.dispatch(new MyAction(message['id']));
      },
      onResume: (Map<String, dynamic> message) async {
        UpdateServerHelper.setPushNotificationTokenRead(message['notification_uid'] != null ? message['notification_uid'] : message['data']['notification_uid']);

        widget.store.dispatch(new MyAction(message['id']));
      },
    );
    _firebaseMessaging.requestNotificationPermissions(
        const IosNotificationSettings(sound: true, badge: true, alert: true));
    _firebaseMessaging.onIosSettingsRegistered
        .listen((IosNotificationSettings settings) {
    });

    _firebaseMessaging.getToken().then((String token) async {
      assert(token != null);

      widget.store.dispatch(new ActionPushNotificationTokenCreated(token));

      UpdateServerHelper.updatePushNotificationToken(token);
    });
  }

  /// Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    if (!mounted) return;
  }

  @override
  Widget build(BuildContext context) {
    return new  StoreProvider<AppState>(
        store: widget.store,
        child: ... widget
    );
  }
}

As you can see I use a middleware and to try to solve my problem I wait for 3 secs before dispatching the action.

essuraj commented 4 years ago

is this the only way to open a notification when the app is terminated? we have the same issue, have a splash screen and animation for 1.5 seconds so adding a wait of 2 seconds or else the page isnt routing. onResume works fine

google-oss-bot commented 4 years ago

Hey @GiacomoK. We need more information to resolve this issue but there hasn't been an update in 7 weekdays. I'm marking the issue as stale and if there are no new updates in the next 7 days I will close it automatically.

If you have more information that will help us get to the bottom of this, just add a comment!

google-oss-bot commented 4 years ago

Since there haven't been any recent updates here, I am going to close this issue.

@GiacomoK if you're still experiencing this problem and want to continue the discussion just leave a comment here and we are happy to re-open this.