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.69k stars 3.97k forks source link

🐛 [firebase-messaging ] [web] - Error on getToken() the first time #11798

Closed daniel-jaramillo-expe closed 11 months ago

daniel-jaramillo-expe commented 11 months ago

Bug report

Describe the bug When I run the project for the first time, it is unable to get the FCM Token. It is needed that the page to be reloaded.

Steps to reproduce

Steps to reproduce the behavior:

  1. Accept notifications permissions
  2. See that FCM Token is not fetched
  3. Reload the page
  4. See that FCM Token is correctly fetched

Expected behavior

It would be expected that as soon as the app get permisions to receive notifications, it can get the FCM Token successfully

Sample project

Run the firebase_messaging repo example at: https://pub.dev/packages/firebase_messaging/example


Additional context

I'm running on Windows 11 Pro Version 22H2. Tested on Chrome and Firefox: Google Chrome Versión 118.0.5993.118 (Build oficial) (64 bits) Firefox 119.0 (64-bit)

See console logs:

Click To Expand ``` Launching lib\main.dart on Chrome in debug mode... This app is linked to the debug service: ws://127.0.0.1:62567/xeq4Usia_2E=/ws Debug service listening on ws://127.0.0.1:62567/xeq4Usia_2E=/ws Connecting to VM Service at ws://127.0.0.1:62567/xeq4Usia_2E=/ws Error: AbortError: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker 2 dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 327:10 createErrorWithStack dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 337:28 _throw dart-sdk/lib/core/errors.dart 120:5 throwWithStackTrace dart-sdk/lib/async/zone.dart 1386:11 callback dart-sdk/lib/async/schedule_microtask.dart 40:11 _microtaskLoop dart-sdk/lib/async/schedule_microtask.dart 49:5 _startMicrotaskLoop dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 181:15 ```

Flutter doctor

Run flutter doctor and paste the output below:

Click To Expand ``` [√] Flutter (Channel stable, 3.13.6, on Microsoft Windows [Versi¢n 10.0.22621.2428], locale es-CO) [√] Windows Version (Installed version of Windows is version 10 or higher) [√] Android toolchain - develop for Android devices (Android SDK version 33.0.0) [√] Chrome - develop for the web [X] Visual Studio - develop Windows apps X Visual Studio not installed; this is necessary to develop Windows apps. Download at https://visualstudio.microsoft.com/downloads/. Please install the "Desktop development with C++" workload, including all of its default components [√] Android Studio (version 2021.3) [√] IntelliJ IDEA Community Edition (version 2022.2) [√] VS Code (version 1.83.1) [√] Connected device (4 available) [√] Network resources ```

Flutter dependencies

Run flutter pub deps -- --style=compact and paste the output below:

Click To Expand ``` Dart SDK 3.1.3 Flutter SDK 3.13.6 web_push_test 1.0.0+1 dependencies: - cupertino_icons 1.0.6 - firebase_core 2.20.0 [firebase_core_platform_interface firebase_core_web flutter meta] - firebase_messaging 14.7.2 [firebase_core firebase_core_platform_interface firebase_messaging_platform_interface firebase_messaging_web flutter meta] - flutter 0.0.0 [characters collection material_color_utilities meta vector_math web sky_engine] - flutter_local_notifications 16.1.0 [clock flutter flutter_local_notifications_linux flutter_local_notifications_platform_interface timezone] - http 0.13.6 [async http_parser meta] dev dependencies: - flutter_lints 2.0.3 [lints] - flutter_test 0.0.0 [flutter test_api matcher path fake_async clock stack_trace vector_math async boolean_selector characters collection material_color_utilities meta source_span stream_channel string_scanner term_glyph web] transitive dependencies: - _flutterfire_internals 1.3.10 [collection firebase_core firebase_core_platform_interface flutter meta] - args 2.4.2 - async 2.11.0 [collection meta] - boolean_selector 2.1.1 [source_span string_scanner] - characters 1.3.0 - clock 1.1.1 - collection 1.17.2 - dbus 0.7.8 [args ffi meta xml] - fake_async 1.3.1 [clock collection] - ffi 2.1.0 - firebase_core_platform_interface 5.0.0 [collection flutter flutter_test meta plugin_platform_interface] - firebase_core_web 2.8.1 [firebase_core_platform_interface flutter flutter_web_plugins js meta] - firebase_messaging_platform_interface 4.5.11 [_flutterfire_internals firebase_core flutter meta plugin_platform_interface] - firebase_messaging_web 3.5.11 [_flutterfire_internals firebase_core firebase_core_web firebase_messaging_platform_interface flutter flutter_web_plugins js meta] - flutter_local_notifications_linux 4.0.0+1 [dbus ffi flutter flutter_local_notifications_platform_interface path xdg_directories] - flutter_local_notifications_platform_interface 7.0.0+1 [flutter plugin_platform_interface] - flutter_web_plugins 0.0.0 [flutter characters collection material_color_utilities meta vector_math web] - http_parser 4.0.2 [collection source_span string_scanner typed_data] - js 0.6.7 [meta] - lints 2.1.1 - matcher 0.12.16 [async meta stack_trace term_glyph test_api] - material_color_utilities 0.5.0 [collection] - meta 1.9.1 - path 1.8.3 - petitparser 5.4.0 [meta] - plugin_platform_interface 2.1.6 [meta] - sky_engine 0.0.99 - source_span 1.10.0 [collection path term_glyph] - stack_trace 1.11.0 [path] - stream_channel 2.1.1 [async] - string_scanner 1.2.0 [source_span] - term_glyph 1.2.1 - test_api 0.6.0 [async boolean_selector collection meta source_span stack_trace stream_channel string_scanner term_glyph] - timezone 0.9.2 [path] - typed_data 1.3.2 [collection] - vector_math 2.1.4 - web 0.1.4-beta - xdg_directories 1.0.3 [meta path] - xml 6.3.0 [collection meta petitparser] ```

darshankawar commented 11 months ago

Thanks for the report. I am able to replicate this running the plugin example on web. Tried the same on mobile wherein, the said error doesn't occur. Also, this isn't specific to Windows, as I am on mac and the error is replicable on it. Upon hot restarting the app, the token is generated successfully.

/cc @russellwheatley

tontonanrakyat commented 11 months ago

@daniel-jaramillo-expe I have the same issue two days ago. But then I realized that FirebaseMessaging.instance.requestPermission is future method, so I have to make await before get the result.

 Future<void> requestPermission() async {
    NotificationSettings settings = await FirebaseMessaging.instance.requestPermission(
      alert: true,
      announcement: false,
      badge: true,
      carPlay: false,
      criticalAlert: false,
      provisional: false,
      sound: true,
    );
    debugPrint('User granted permission: ${settings.authorizationStatus}');
    if (settings.authorizationStatus == AuthorizationStatus.authorized) {
      final fcmToken = await _instance.getToken(vapidKey: kIsWeb ? webPushCertificate : null);
      debugPrint('fcmToken => $fcmToken');
    }
  }

I hope it can solve your problem.

russellwheatley commented 11 months ago

@daniel-jaramillo-expe I have the same issue two days ago. But then I realized that FirebaseMessaging.instance.requestPermission is future method, so I have to make await before get the result.

 Future<void> requestPermission() async {
    NotificationSettings settings = await FirebaseMessaging.instance.requestPermission(
      alert: true,
      announcement: false,
      badge: true,
      carPlay: false,
      criticalAlert: false,
      provisional: false,
      sound: true,
    );
    debugPrint('User granted permission: ${settings.authorizationStatus}');
    if (settings.authorizationStatus == AuthorizationStatus.authorized) {
      final fcmToken = await _instance.getToken(vapidKey: kIsWeb ? webPushCertificate : null);
      debugPrint('fcmToken => $fcmToken');
    }
  }

I hope it can solve your problem.

@daniel-jaramillo-expe - does this resolve your issue?

daniel-jaramillo-expe commented 11 months ago

@russellwheatley yes, it is in fact a synchrony problem as @tontonanrakyat states. To test it, I just change _TokenMonitor class in permissions.dart repo example file to this

class _TokenMonitor extends State<TokenMonitor> {
  String? _token;
  late Stream<String> _tokenStream;

  void setToken(String? token) {
    print('FCM Token: $token');
    setState(() {
      _token = token;
    });
  }

  @override
  void initState() {
    super.initState();
    getToken();
    _tokenStream = FirebaseMessaging.instance.onTokenRefresh;
    _tokenStream.listen(setToken);
  }

  void getToken() { // This a new method
    FirebaseMessaging.instance
        .getToken(
            vapidKey:
                'BHPVRHXKku9DXdy1X_WY-Bfdy4gf0WuTctbfqCwktI9kVTAYwos-FGsWInnl96P13sXiOd09JxHNGACpjRhTcZc')
        .then(setToken);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        widget._builder(_token),
        ElevatedButton(onPressed: getToken, child: const Text('Get token')) // This a new button
      ],
    );
  }
}

After accepting the required permissions, if I hit the new Get token button, it fetches the token correctly. Thanks! 😊

adar2378 commented 11 months ago

Still, I get this error even with await getToken. It happens only on first time when I request it. Similar issue on firebaseJS https://github.com/firebase/firebase-js-sdk/issues/5797

FarzaneGhb commented 11 months ago

hi. i have the same issue. I get this error: "Error: AbortError: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker " when I run my Flutter app for the first time on Chrome browser, but if I restart the app or refresh the browser page, the error disappears.

tontonanrakyat commented 11 months ago

Hi all... After upgrade to latest flutter and all packages, I have the same problem again. (it happened after "flutter clean") But I can handle this with "deleteToken()" before "requestPermission()".

  Future<void> requestPermission() async {
    try {
      NotificationSettings settings = await _instance.requestPermission();
      debugPrint('User granted permission: ${settings.authorizationStatus}');
      if (settings.authorizationStatus == AuthorizationStatus.authorized) {
        if (kIsWeb) {
          await _instance.deleteToken();
        }

        //! not works on web
        _instance.onTokenRefresh.listen(
          (fcmToken) => debugPrint('fcmToken [stream] => $fcmToken'),
          onError: (err) => debugPrint(err),
        );

        _instance
            .getToken(vapidKey: kIsWeb ? webPushCertificate : null)
            .then((value) => debugPrint('fcmToken [future] => $value'));
      }
    } catch (e) {
      debugPrint(e.toString());
    }
  }

And I found that "onTokenRefresh" not works on web, but works properly on android

adar2378 commented 11 months ago

Hi all... After upgrade to latest flutter and all packages, I have the same problem again. (it happened after "flutter clean") But I can handle this with "deleteToken()" before "requestPermission()".

  Future<void> requestPermission() async {
    try {
      NotificationSettings settings = await _instance.requestPermission();
      debugPrint('User granted permission: ${settings.authorizationStatus}');
      if (settings.authorizationStatus == AuthorizationStatus.authorized) {
        if (kIsWeb) {
          await _instance.deleteToken();
        }

        //! not works on web
        _instance.onTokenRefresh.listen(
          (fcmToken) => debugPrint('fcmToken [stream] => $fcmToken'),
          onError: (err) => debugPrint(err),
        );

        _instance
            .getToken(vapidKey: kIsWeb ? webPushCertificate : null)
            .then((value) => debugPrint('fcmToken [future] => $value'));
      }
    } catch (e) {
      debugPrint(e.toString());
    }
  }

And I found that "onTokenRefresh" not works on web, but works properly on android

Thanks, using deleteToken before getToken works, this error does not show up

FarzaneGhb commented 11 months ago

Hi all... After upgrade to latest flutter and all packages, I have the same problem again. (it happened after "flutter clean") But I can handle this with "deleteToken()" before "requestPermission()".

  Future<void> requestPermission() async {
    try {
      NotificationSettings settings = await _instance.requestPermission();
      debugPrint('User granted permission: ${settings.authorizationStatus}');
      if (settings.authorizationStatus == AuthorizationStatus.authorized) {
        if (kIsWeb) {
          await _instance.deleteToken();
        }

        //! not works on web
        _instance.onTokenRefresh.listen(
          (fcmToken) => debugPrint('fcmToken [stream] => $fcmToken'),
          onError: (err) => debugPrint(err),
        );

        _instance
            .getToken(vapidKey: kIsWeb ? webPushCertificate : null)
            .then((value) => debugPrint('fcmToken [future] => $value'));
      }
    } catch (e) {
      debugPrint(e.toString());
    }
  }

And I found that "onTokenRefresh" not works on web, but works properly on android

Deleting the token worked for me too. Thank you.

RomanIvn commented 11 months ago

[firebase_messaging/token-unsubscribe-failed] Messaging: A problem occurred while unsubscribing the user from FCM: FirebaseError: Messaging: A problem occurred while unsubscribing the user from FCM: Requested entity was not found. . (messaging/token-unsubscribe-failed).

Deleting a token that doesnt exists causes an error.

Will wait for a real fix for this issue, as of right now the examples and documentations are wrong so how can this be closed?

darshankawar commented 11 months ago

@RomanIvn This seems to be a different issue than the one reported in this issue. You may file a separate issue for better tracking.

adar2378 commented 10 months ago

[firebase_messaging/token-unsubscribe-failed] Messaging: A problem occurred while unsubscribing the user from FCM: FirebaseError: Messaging: A problem occurred while unsubscribing the user from FCM: Requested entity was not found. . (messaging/token-unsubscribe-failed).

Deleting a token that doesnt exists causes an error.

Will wait for a real fix for this issue, as of right now the examples and documentations are wrong so how can this be closed?

This only happens in iOS I believe when the user has not seen notification permission. You can solve it via getNotificationSettings method. If you see that user was shown the permission dialog from ios before and it was granted then you can delete it otherwise don't need to delete token for iOS.