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

🐛 Cloud Messaging Web Doesn't work with documentation and Flutter 2.2.0 #6372

Closed JohnGalt1717 closed 3 years ago

JohnGalt1717 commented 3 years ago

Bug report

Describe the bug The documentation outlines a process that is confusing to start with (it's this, except it isn't that, it's this if you're doing background notifications) that doesn't show the actual order of things in the index.html file for flutter.

And in Flutter 2.2.0 the index.html has significantly changed, so it isn't possible to follow the instructions.

The result is that background notifications don't work as described and cause "The application is not registered" or "The object messaging is null" depending on how you attempt to intuit how to do this now.

Steps to reproduce

Steps to reproduce the behavior:

  1. Create a new flutter 2.2.0 project
  2. Follow the instructions
  3. Note that you can't follow the instructions and the entire process doesn't show you what goes in what order in the index.html file anyhow.

Expected behavior

I would expect 3 things:

  1. Full documentation that shows a complete template index.html for the initial setup, and then a full example of the altered file to get background notifications working properly that works with the latest public release and notes going forward of changes for future versions if there is any.

  2. An example app that works that we can use to test putting our own credentials in that shows the entire setup process.

  3. That the documentation would have been updated to 2.2.0 when it was released at google i/o.

And thus it would just work following the instructions.

Flutter doctor

Run flutter doctor and paste the output below:

Click To Expand ``` PASTE OUTPUT INSIDE HERE ``` [√] Flutter (Channel beta, 2.2.0, on Microsoft Windows [Version 10.0.19043.1052], locale en-US) [!] Android toolchain - develop for Android devices (Android SDK version 30.0.3) X Android license status unknown. Run `flutter doctor --android-licenses` to accept the SDK licenses. See https://flutter.dev/docs/get-started/install/windows#android-setup for more details. [√] Chrome - develop for the web [√] Visual Studio - develop for Windows (Visual Studio Enterprise 2019 16.10.0) [√] Android Studio (version 4.1.0) [√] VS Code (version 1.56.2) [√] Connected device (4 available) --- ### Flutter dependencies Run `flutter pub deps -- --style=compact` and paste the output below:
Click To Expand ``` PASTE OUTPUT INSIDE HERE ``` Dart SDK 2.13.0 Flutter SDK 2.2.0 www 1.0.0+1 dependencies: - api_client 0.0.1 [flutter http rxdart flutter_auth_client reactive_mvvm] - bootstrap_grid 2.0.0 [flutter] - chewie 1.0.0 [cupertino_icons flutter video_player wakelock] - cupertino_icons 1.0.2 - device_info_plus 1.0.1 [flutter device_info_plus_platform_interface device_info_plus_linux device_info_plus_macos device_info_plus_web device_info_plus_windows] - file_picker 3.0.2+2 [flutter flutter_web_plugins flutter_plugin_android_lifecycle plugin_platform_interface] - firebase_core 1.3.0 [firebase_core_platform_interface firebase_core_web flutter meta] - firebase_messaging 10.0.1 [firebase_core firebase_core_platform_interface firebase_messaging_platform_interface firebase_messaging_web flutter meta] - flutter 0.0.0 [characters collection meta typed_data vector_math sky_engine] - flutter_auth_client 0.0.1 [flutter http flutter_secure_storage flutter_appauth flutter_appauth_web retry shared_preferences rxdart] - flutter_typeahead 3.1.1 [flutter flutter_keyboard_visibility] - font_awesome_flutter 9.0.0 [flutter] - get_it 7.1.3 [async collection] - graphview 1.0.0-nullsafety.1 [flutter collection] - injectable 1.4.0 [get_it] - material_floating_search_bar 0.3.4 [flutter meta] - reactive_mvvm 0.0.1 [flutter rxdart] - share_plus 2.0.1 [meta mime flutter share_plus_platform_interface share_plus_linux share_plus_macos share_plus_windows share_plus_web] - shared_library 0.0.1 [flutter flutter_localizations intl http shared_preferences bootstrap_grid retry rxdart flutter_auth_client api_client reactive_mvvm staccato_localizations font_awesome_flutter file_picker flutter_chips_input date_field chewie video_player video_player_web_hls get_it share_plus firebase_core firebase_messaging device_info_plus] - staccato_localizations 0.0.1 [flutter intl flutter_localizations api_client] - url_launcher 6.0.3 [flutter url_launcher_platform_interface url_launcher_linux url_launcher_macos url_launcher_windows url_launcher_web] - video_player 2.1.1 [meta video_player_platform_interface video_player_web flutter flutter_test] - video_player_web_hls 0.1.10 [flutter flutter_web_plugins meta video_player_platform_interface js] dev dependencies: - build_runner 1.12.2 [args async build build_config build_daemon build_resolvers build_runner_core code_builder collection crypto dart_style glob graphs http_multi_server io js logging meta mime path pedantic pool pub_semver pubspec_parse shelf shelf_web_socket stack_trace stream_transform timing watcher web_socket_channel yaml] - effective_dart 1.3.1 - flutter_native_splash 1.1.8+4 [image meta path xml yaml universal_io] - flutter_test 0.0.0 [flutter test_api path fake_async clock stack_trace vector_math async boolean_selector characters charcode collection matcher meta source_span stream_channel string_scanner term_glyph typed_data] - injectable_generator 1.2.2 [build source_gen path glob analyzer code_builder dart_style injectable collection] dependency overrides: - font_awesome_flutter 9.0.0 [flutter] transitive dependencies: - _fe_analyzer_shared 18.0.0 [meta] - analyzer 1.2.0 [_fe_analyzer_shared cli_util collection convert crypto glob meta package_config path pub_semver source_span watcher yaml] - archive 3.1.2 [crypto path] - args 2.0.0 - async 2.6.1 [meta collection] - boolean_selector 2.1.0 [source_span string_scanner] - build 2.0.0 [analyzer async convert crypto glob logging meta path] - build_config 0.4.7 [checked_yaml json_annotation meta path pubspec_parse yaml] - build_daemon 2.1.10 [built_collection built_value http_multi_server logging pedantic path pool shelf shelf_web_socket stream_transform watcher web_socket_channel] - build_resolvers 2.0.0 [analyzer build crypto graphs logging path package_config pool pub_semver stream_transform] - build_runner_core 6.1.12 [async build build_config build_resolvers collection convert crypto glob graphs logging meta path package_config pedantic pool timing watcher yaml] - built_collection 5.0.0 - built_value 8.0.4 [built_collection collection fixnum] - characters 1.1.0 - charcode 1.2.0 - checked_yaml 2.0.1 [json_annotation source_span yaml] - cli_util 0.3.0 [meta path] - clock 1.1.0 - code_builder 3.7.0 [built_collection built_value collection matcher meta] - collection 1.15.0 - convert 3.0.0 [typed_data] - crypto 3.0.0 [collection typed_data] - dart_style 2.0.0 [analyzer args path pub_semver source_span] - date_field 2.0.0 [flutter intl] - device_info_plus_linux 1.0.1 [device_info_plus_platform_interface file flutter meta] - device_info_plus_macos 1.0.1 [device_info_plus_platform_interface flutter] - device_info_plus_platform_interface 1.0.2 [flutter meta plugin_platform_interface] - device_info_plus_web 1.0.1 [device_info_plus_platform_interface flutter_web_plugins flutter] - device_info_plus_windows 1.0.1 [device_info_plus_platform_interface ffi flutter win32] - fake_async 1.2.0 [clock collection] - ffi 1.0.0 - file 6.1.0 [meta path] - firebase_core_platform_interface 4.0.1 [collection flutter meta plugin_platform_interface] - firebase_core_web 1.1.0 [firebase_core_platform_interface flutter flutter_web_plugins js meta] - firebase_messaging_platform_interface 3.0.2 [firebase_core flutter meta plugin_platform_interface] - firebase_messaging_web 2.0.2 [firebase_core firebase_core_web firebase_messaging_platform_interface flutter flutter_web_plugins js meta] - fixnum 1.0.0 - flutter_appauth 1.0.0 [flutter flutter_appauth_platform_interface] - flutter_appauth_platform_interface 3.0.0 [flutter plugin_platform_interface] - flutter_appauth_web 0.0.1 [flutter flutter_web_plugins http flutter_appauth_platform_interface pointycastle] - flutter_chips_input 2.0.0 [flutter] - flutter_keyboard_visibility 5.0.0 [meta flutter_keyboard_visibility_platform_interface flutter_keyboard_visibility_web flutter] - flutter_keyboard_visibility_platform_interface 2.0.0 [flutter meta plugin_platform_interface] - flutter_keyboard_visibility_web 2.0.0 [flutter_keyboard_visibility_platform_interface flutter_web_plugins flutter] - flutter_localizations 0.0.0 [flutter intl characters clock collection meta path typed_data vector_math] - flutter_plugin_android_lifecycle 2.0.0 [flutter] - flutter_secure_storage 4.1.0 [meta flutter] - flutter_web_plugins 0.0.0 [flutter js characters collection meta typed_data vector_math] - glob 2.0.0 [async collection file path pedantic string_scanner] - graphs 1.0.0 - http 0.13.1 [http_parser meta path pedantic] - http_multi_server 3.0.0 [async] - http_parser 4.0.0 [charcode collection source_span string_scanner typed_data] - image 3.0.2 [archive meta xml] - intl 0.17.0 [clock path] - io 1.0.0 [meta path string_scanner] - js 0.6.3 - json_annotation 4.0.1 - logging 1.0.0 - matcher 0.12.10 [stack_trace] - meta 1.3.0 - mime 1.0.0 - package_config 2.0.0 [path] - path 1.8.0 - path_provider_linux 2.0.0 [path xdg_directories path_provider_platform_interface flutter] - path_provider_platform_interface 2.0.1 [flutter meta platform plugin_platform_interface] - path_provider_windows 2.0.0 [path_provider_platform_interface meta path flutter ffi win32] - pedantic 1.11.0 - petitparser 4.1.0 [meta] - platform 3.0.0 - plugin_platform_interface 2.0.0 [meta] - pointycastle 3.0.0-nullsafety.2 [collection] - pool 1.5.0 [async stack_trace] - process 4.1.1 [file path platform] - pub_semver 2.0.0 [collection] - pubspec_parse 1.0.0 [checked_yaml collection json_annotation pub_semver yaml] - retry 3.1.0 - rxdart 0.26.0 - share_plus_linux 2.0.0 [share_plus_platform_interface file flutter meta url_launcher] - share_plus_macos 2.0.0 [share_plus_platform_interface flutter] - share_plus_platform_interface 2.0.0 [flutter meta mime plugin_platform_interface] - share_plus_web 2.0.0 [share_plus_platform_interface url_launcher flutter flutter_web_plugins meta] - share_plus_windows 2.0.0 [share_plus_platform_interface flutter meta url_launcher] - shared_preferences 2.0.5 [meta flutter shared_preferences_platform_interface shared_preferences_linux shared_preferences_macos shared_preferences_web shared_preferences_windows] - shared_preferences_linux 2.0.0 [flutter file meta path path_provider_linux shared_preferences_platform_interface] - shared_preferences_macos 2.0.0 [shared_preferences_platform_interface flutter] - shared_preferences_platform_interface 2.0.0 [flutter] - shared_preferences_web 2.0.0 [shared_preferences_platform_interface flutter flutter_web_plugins meta] - shared_preferences_windows 2.0.0 [shared_preferences_platform_interface flutter file meta path path_provider_platform_interface path_provider_windows] - shelf 1.1.0 [async collection http_parser path stack_trace stream_channel] - shelf_web_socket 1.0.1 [shelf stream_channel web_socket_channel] - sky_engine 0.0.99 - source_gen 1.0.0 [analyzer async build dart_style glob meta path pedantic source_span] - source_span 1.8.1 [collection path term_glyph] - stack_trace 1.10.0 [path] - stream_channel 2.1.0 [async] - stream_transform 2.0.0 - string_scanner 1.1.0 [charcode source_span] - term_glyph 1.2.0 - test_api 0.3.0 [async boolean_selector collection meta path source_span stack_trace stream_channel string_scanner term_glyph matcher] - timing 1.0.0 [json_annotation] - typed_data 1.3.0 [collection] - universal_io 2.0.4 [collection crypto meta typed_data] - url_launcher_linux 2.0.0 [flutter] - url_launcher_macos 2.0.0 [flutter] - url_launcher_platform_interface 2.0.2 [flutter plugin_platform_interface] - url_launcher_web 2.0.0 [url_launcher_platform_interface meta flutter flutter_web_plugins] - url_launcher_windows 2.0.0 [flutter] - vector_math 2.1.0 - video_player_platform_interface 4.1.0 [flutter meta flutter_test] - video_player_web 2.0.0 [flutter flutter_web_plugins meta video_player_platform_interface] - wakelock 0.4.0 [flutter meta wakelock_macos wakelock_platform_interface wakelock_web] - wakelock_macos 0.1.0 [flutter flutter_web_plugins wakelock_platform_interface] - wakelock_platform_interface 0.2.0 [flutter meta] - wakelock_web 0.2.0 [flutter flutter_web_plugins js wakelock_platform_interface] - watcher 1.0.0 [async path pedantic] - web_socket_channel 2.0.0 [async crypto stream_channel] - win32 2.0.4 [ffi] - xdg_directories 0.2.0 [meta path process] - xml 5.1.1 [collection meta petitparser] - yaml 3.1.0 [collection source_span string_scanner] ---
markusaksli-nc commented 3 years ago

There are some valid concerns here. I think the documentation can be improved by linking to the locations of the example files in question and the bit about index.html having changed is valid. The same approach as in the current documentation will work, it's just a bit harder to find the right place for the line.

In the default script tag:

  <script>
    var serviceWorkerVersion = null;
    var scriptLoaded = false;

...

    if ('serviceWorker' in navigator) {
      // Service workers are supported. Use them.
      window.addEventListener('load', function () {
        navigator.serviceWorker.register("/firebase-messaging-sw.js"); //Add this

After adding this and firebase-messaging-sw.js everything should work.

On the last part, however - there already is an official example for every FlutterFire plugin that is also linked in the documentation and contains all of this completed setup.

JohnGalt1717 commented 3 years ago

Doing this using the identical code otherwise I get:

New service worker available.
Installed new service worker.
New service worker available.
Installed new service worker.
New service worker available.
Installed new service worker.
FirebaseError: Firebase: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp() (app/no-app).
    at Object.u [as app] (https://www.gstatic.com/firebasejs/8.6.1/firebase-app.js:1:18836)
    at Object.app$ [as app] (http://localhost:45503/packages/firebase_core_web/src/interop/core.dart.lib.js:31:101)
    at new firebase_messaging_web.FirebaseMessagingWeb.new (http://localhost:45503/packages/firebase_messaging_web/firebase_messaging_web.dart.lib.js:143:64)
    at Function.registerWith (http://localhost:45503/packages/firebase_messaging_web/firebase_messaging_web.dart.lib.js:46:73)
    at Object.registerPlugins (http://localhost:45503/packages/www/generated_plugin_registrant.dart.lib.js:27:49)
    at main (http://localhost:45503/web_entrypoint.dart.lib.js:32:35)
    at main.next (<anonymous>)
    at runBody (http://localhost:45503/dart_sdk.js:37393:34)
    at Object._async [as async] (http://localhost:45503/dart_sdk.js:37424:7)
    at main (http://localhost:45503/web_entrypoint.dart.lib.js:31:18)
    at http://localhost:45503/main_module.bootstrap.js:19:10
    at Array.forEach (<anonymous>)
    at window.$dartRunMain (http://localhost:45503/main_module.bootstrap.js:18:32)
    at <anonymous>:1:8
    at Object.runMain (http://localhost:45503/dwds/src/injected/client.js:8825:21)
    at http://localhost:45503/dwds/src/injected/client.js:22713:19
    at _wrapJsFunctionForAsync_closure.$protected (http://localhost:45503/dwds/src/injected/client.js:3851:15)
    at _wrapJsFunctionForAsync_closure.call$2 (http://localhost:45503/dwds/src/injected/client.js:11063:12)
    at Object._asyncStartSync (http://localhost:45503/dwds/src/injected/client.js:3815:20)
    at main__closure1.$call$body$main__closure (http://localhost:45503/dwds/src/injected/client.js:22725:16)
    at main__closure1.call$1 (http://localhost:45503/dwds/src/injected/client.js:22652:19)
    at StaticClosure._rootRunUnary [as call$2$5] (http://localhost:45503/dwds/src/injected/client.js:4185:16)
    at _CustomZone.runUnary$2$2 (http://localhost:45503/dwds/src/injected/client.js:12436:39)
    at _CustomZone.runUnaryGuarded$1$2 (http://localhost:45503/dwds/src/injected/client.js:12383:14)
    at _ControllerSubscription._sendData$1 (http://localhost:45503/dwds/src/injected/client.js:11959:19)
    at _DelayedData.perform$1 (http://localhost:45503/dwds/src/injected/client.js:12148:59)
    at _PendingEvents_schedule_closure.call$0 (http://localhost:45503/dwds/src/injected/client.js:12197:14)
    at Object._microtaskLoop (http://localhost:45503/dwds/src/injected/client.js:4023:24)
    at StaticClosure._startMicrotaskLoop (http://localhost:45503/dwds/src/injected/client.js:4029:11)
    at _AsyncRun__initializeScheduleImmediate_internalCallback.call$1 (http://localhost:45503/dwds/src/injected/client.js:10932:9)
    at invokeClosure (http://localhost:45503/dwds/src/injected/client.js:1259:26)
    at MutationObserver.<anonymous> (http://localhost:45503/dwds/src/injected/client.js:1278:18)

Here's my body per the docs and your update:


<body>
    <script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-messaging.js"></script>

    <!-- This script installs service_worker.js to provide PWA functionality to
       application. For more information, see:
       https://developers.google.com/web/fundamentals/primers/service-workers -->
    <script>
        var serviceWorkerVersion = null;
        var scriptLoaded = false;
        function loadMainDartJs() {
            if (scriptLoaded) {
                return;
            }
            scriptLoaded = true;
            var scriptTag = document.createElement('script');
            scriptTag.src = 'main.dart.js';
            scriptTag.type = 'application/javascript';
            document.body.append(scriptTag);
        }

        if ('serviceWorker' in navigator) {
            // Service workers are supported. Use them.
            window.addEventListener('load', function () {
                navigator.serviceWorker.register("/firebase-messaging-sw.js");
                // Wait for registration to finish before dropping the <script> tag.
                // Otherwise, the browser will load the script multiple times,
                // potentially different versions.
                var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
                navigator.serviceWorker.register(serviceWorkerUrl)
                    .then((reg) => {
                        function waitForActivation(serviceWorker) {
                            serviceWorker.addEventListener('statechange', () => {
                                if (serviceWorker.state == 'activated') {
                                    console.log('Installed new service worker.');
                                    loadMainDartJs();
                                }
                            });
                        }
                        if (!reg.active && (reg.installing || reg.waiting)) {
                            // No active web worker and we have installed or are installing
                            // one for the first time. Simply wait for it to activate.
                            waitForActivation(reg.installing ?? reg.waiting);
                        } else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
                            // When the app updates the serviceWorkerVersion changes, so we
                            // need to ask the service worker to update.
                            console.log('New service worker available.');
                            reg.update();
                            waitForActivation(reg.installing);
                        } else {
                            // Existing service worker is still good.
                            console.log('Loading app from service worker.');
                            loadMainDartJs();
                        }
                    });

                // If service worker doesn't succeed in a reasonable amount of time,
                // fallback to plaint <script> tag.
                setTimeout(() => {
                    if (!scriptLoaded) {
                        console.warn(
                            'Failed to load app from service worker. Falling back to plain <script> tag.',
                        );
                        loadMainDartJs();
                    }
                }, 4000);
            });
        } else {
            // Service workers not supported. Just drop the <script> tag.
            loadMainDartJs();
        }
    </script>
</body>

Here's my firebase-messaging-sw.js which is confirmed in dev tools/networking to have loaded with no errors in console.


importScripts("https://www.gstatic.com/firebasejs/8.6.1/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/8.6.1/firebase-messaging.js");

firebase.initializeApp({
 ///properly entered values here.
});

const messaging = firebase.messaging();

The cache was cleared entirely and the service workers apps were deleted in dev tools before doing this.

In general the documentation for this reproduces a MUCH too narrow slice of the files that are being built up at each step, and the background notification instructions are separated from the rest which doesn't make much sense and makes it all more complex because it is very unclear if you're undoing some of the previous steps or just adding to. (ie. the service worker imports the script files that have script tags in the default configuration.

It would be highly desirable if this was in a single document and flowed one step to the next showing how the file gets built up directly in the documentation as you go so that you can see the overall result of the index.html file at every step.

markusaksli-nc commented 3 years ago

I don't see the https://firebase.flutter.dev/docs/installation/web#initializing-firebase script in your body? I'm guessing you are calling await Firebase.initializeApp(); on the dart side already?

Also just as a reminder every documentation page has an Edit this page button at the bottom that you can use to add any improvements you want with and submit a docs PR.

For clarity the major issues here are probably that:

JohnGalt1717 commented 3 years ago

@markusaksli-nc As far as I can tell (because the stack doesn't tell me) the app fails before it ever gets to my main.dart so I can never call await Firebase.initializeApp();

To be specific it's failing in web_entrypoint.dart which is part of dart on Future main() async {...}

And using your instructions the firebase-messaging-sw.js:

firebase.initializeApp({
 ///properly entered values here.
});

const messaging = firebase.messaging();

Isn't hit either.

So the No. 1 major issue is:

There's still no working instructions for how to use firebase messaging with Flutter 2.2.2 as demoed at google i/o.

JohnGalt1717 commented 3 years ago

Not sure it matters but if you skip all of the service worker stuff and then request notifications you get:

Error: [firebase_messaging/failed-service-worker-registration] Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker for scope ('http://localhost:45503/firebase-cloud-messaging-push-scope') with script ('http://localhost:45503/firebase-messaging-sw.js'): ServiceWorker script evaluation failed .

Which appears to be trying to load the file and register the service worker at time of request for ability to notify indicating (to me) that somehow the firebase app should be registered immediately, but then the service worker file should be registering a service worker itself, which the current file doesn't appear to do that...

markusaksli-nc commented 3 years ago

Well as I mentioned it doesn't look like you've added the firebase initialization script into index.html as well?

JohnGalt1717 commented 3 years ago

uh... the docs say to add the service worker which has that code.

The firebase-messaging-sw.js literally has those commands in it.

Hence the issue here. I'm still at a loss as to what a working Flutter 2.2 project looks like with full background notifications. The documentation is disjointed and thus isn't at all clear what actually gets you to success.

So what is supposed to be in firebase-messaging-sw.js if that initialization script is in index.html?

russellwheatley commented 3 years ago

Hey @JohnGalt1717, I've updated the example index.html in line with the latest flutter 2.2.0 generated web index.html which will allow you to receive background messages. I've also updated the docs to direct users to the example in order to demonstrate how it works. Hope it helps.

JohnGalt1717 commented 3 years ago

@russellwheatley Thank you so much! I put a comment on the check in for you to consider. Otherwise I believe it is now working and it's far more obvious. I think my cognitive dissonance was the requirement to register firebase twice (in the index.html and in the service worker)