如何将 Flutter 项目迁移到 Firebase version-9 modern web modular style

How to migrate Flutter project to Firebase version-9 modern web modular style

我在初始化 FirebaseFlutter 项目时遇到问题,而我刚刚更新了我的 firebase-toolsfirebase 版本 9 这是 现代网络模块化风格 已经一周了,没有任何帮助 flutter 的文档仍然根据版本 8这是旧式兼容类型,当我遵循 firebase 文档时,它更新了它的抛出错误。我需要你的帮助 firebase 和 flutter 专家请提供一些解决方案。

我得到的两个错误是,

core.dart:56 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'app')
    at Object.app$ [as app] (core.dart:56)
    at initializeApp (firebase_core_web.dart:68)
    at initializeApp.next (<anonymous>)
    at runBody (async_patch.dart:84)
    at Object._async [as async] (async_patch.dart:123)
    at firebase_core_web.FirebaseCoreWeb.new.initializeApp (firebase_core_web.dart:28)
    at initializeApp (firebase.dart:42)
    at initializeApp.next (<anonymous>)
    at runBody (async_patch.dart:84)
    at Object._async [as async] (async_patch.dart:123)
    at Function.initializeApp (firebase.dart:38)
    at main$ (main.dart:9)
    at main$.next (<anonymous>)
    at runBody (async_patch.dart:84)
    at Object._async [as async] (async_patch.dart:123)
    at main$ (main.dart:7)
    at main (web_entrypoint.dart:19)
    at main.next (<anonymous>)
    at async_patch.dart:45
    at _RootZone.runUnary (zone.dart:1613)
    at _FutureListener.thenAwait.handleValue (future_impl.dart:155)
    at handleValueCallback (future_impl.dart:707)
    at Function._propagateToListeners (future_impl.dart:736)
    at _Future.new.[_completeWithValue] (future_impl.dart:542)
    at future.dart:401
    at _RootZone.runUnary (zone.dart:1613)
    at _FutureListener.then.handleValue (future_impl.dart:155)
    at handleValueCallback (future_impl.dart:707)
    at Function._propagateToListeners (future_impl.dart:736)
    at _Future.new.[_completeWithValue] (future_impl.dart:542)
    at async._AsyncCallbackEntry.new.callback (future_impl.dart:580)
    at Object._microtaskLoop (schedule_microtask.dart:40)
    at _startMicrotaskLoop (schedule_microtask.dart:49)
    at async_patch.dart:166

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
js_primitives.dart:30 The following JSNoSuchMethodError was thrown building MyApp(dirty):
js_primitives.dart:30 TypeError: Cannot read properties of undefined (reading 'app')
js_primitives.dart:30 
js_primitives.dart:30 The relevant error-causing widget was:
js_primitives.dart:30   MyApp file:///C:/Users/Neha/AndroidStudioProjects/devcom/lib/main.dart:10:10
js_primitives.dart:30 
js_primitives.dart:30 When the exception was thrown, this was the stack:
js_primitives.dart:30 C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 236:49  throw_
js_primitives.dart:30 packages/firebase_core_web/firebase_core_web.dart 73:3                                                                     _catchJSError
js_primitives.dart:30 packages/firebase_core_web/src/firebase_core_web.dart 138:13                                                               app
js_primitives.dart:30 packages/firebase_core/src/firebase.dart 55:41                                                                             app
js_primitives.dart:30 packages/firebase_auth/src/firebase_auth.dart 38:47                                                                        get instance
js_primitives.dart:30 packages/devcom/auth.dart 12:51                                                                                            new
js_primitives.dart:30 packages/devcom/main.dart 17:13                                                                                            build
js_primitives.dart:30 packages/flutter/src/widgets/framework.dart 4648:28                                                                        build
js_primitives.dart:30 packages/flutter/src/widgets/framework.dart 4574:15                                                                        performRebuild
js_primitives.dart:30 packages/flutter/src/widgets/framework.dart 4267:5                                                                         rebuild
js_primitives.dart:30 packages/flutter/src/widgets/framework.dart 4553:5                                                                         [_firstBuild]
js_primitives.dart:30 packages/flutter/src/widgets/framework.dart 4548:5                                                                         mount
js_primitives.dart:30 packages/flutter/src/widgets/framework.dart 3611:13                                                                        inflateWidget
js_primitives.dart:30 packages/flutter/src/widgets/framework.dart 3363:18                                                                        updateChild
js_primitives.dart:30 packages/flutter/src/widgets/binding.dart 1189:16                                                                          [_rebuild]
js_primitives.dart:30 packages/flutter/src/widgets/binding.dart 1159:5                                                                           mount
js_primitives.dart:30 packages/flutter/src/widgets/binding.dart 1104:16                                                                          <fn>
js_primitives.dart:30 packages/flutter/src/widgets/framework.dart 2535:19                                                                        buildScope
js_primitives.dart:30 packages/flutter/src/widgets/binding.dart 1103:12                                                                          attachToRenderTree
js_primitives.dart:30 packages/flutter/src/widgets/binding.dart 936:24                                                                           attachRootWidget
js_primitives.dart:30 packages/flutter/src/widgets/binding.dart 917:7                                                                            <fn>
js_primitives.dart:30 C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart 48:19       internalCallback
js_primitives.dart:30 
js_primitives.dart:30 ════════════════════════════════════════════════════════════════════════════════════════════════════

main.dart:

import 'package:flutter/material.dart';
import 'package:devcom/auth.dart';
import 'package:devcom/auth_provider.dart';
import 'package:devcom/root_page.dart';
import 'package:firebase_core/firebase_core.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  Firebase.initializeApp();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return AuthProvider(
      auth: Auth(),
      child: MaterialApp(
        title: 'Flutter login demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: RootPage(),
      ),
    );
  }
}

index.html :

<!DOCTYPE html>
  <html>
  <head>
    <!-- <script src="https://www.gstatic.com/firebasejs/9.0.1/firebase-app.js" type = "module"></script>
    <script src="https://www.gstatic.com/firebasejs/9.0.1/firebase-analytics.js" type = "module"> </script>
    <script src="https://www.gstatic.com/firebasejs/9.0.1/firebase-auth.js" type = "module"></script> -->
    <meta charset="UTF-8">
    <meta content="IE=Edge" http-equiv="X-UA-Compatible">
    <meta name="description" content="A new Flutter project.">
  
    <!-- iOS meta tags & icons -->
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="apple-mobile-web-app-title" content="devcom">
    <link rel="apple-touch-icon" href="icons/Icon-192.png">
  
    <!-- Favicon -->
    <link rel="shortcut icon" type="image/png" href="favicon.png" />
  
    <title>Devcom</title>
    <link rel="manifest" href="manifest.json">
  </head>
<body >
  <!-- The core Firebase JS SDK is always required and must be listed first -->
 
<script type="module"> 
  import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.0.1/firebase-app.js';
  import {  } from 'https://www.gstatic.com/firebasejs/9.0.1/firebase-auth.js';
  import { getAnalytics } from "https://www.gstatic.com/firebasejs/9.0.1/firebase-analytics.js";


    const firebaseConfig = {
     apiKey: "...",
      authDomain: "......",
      databaseURL: ".....",
      projectId: "...",
      storageBucket: "",
      messagingSenderId: "",
      measurementId: "",
      appId: "1:.........:web:...........",
    };
    
    const app = initializeApp({ firebaseConfig });
// const app = getAnalytics({ firebaseConfig })    
</script>
 
 <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 () {
        // 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>
</html>

Firebase 的 Flutter Web 绑定构建在 v9 之前的版本 API 之上。据我在 Github 仓库中看到的,没有 discussion has been started on porting them to v9 yet. I'd recommend leaving it to the library's authors to decide when the best time is to migrate to the v9 modular API style, and use v8 until then as shown in the FlutterFire documentation on adding the Firebase SDKs to your web app.

如果您已经坚持要迁移到 v9,则可以使用它的 -compat 版本,它将以前的 API 样式固定在新的模块化版本上。这将允许您使用最新版本,尽管它不会为您提供新模块化 API.

的(完整)尺寸优势

您的 flutter 代码不符合文档的建议,尤其是在何处以及如何调用 Firebase.initializeApp();

这是直接来自 docs 的片段:

import 'package:flutter/material.dart';

// Import the firebase_core plugin
import 'package:firebase_core/firebase_core.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(App());
}

/// We are using a StatefulWidget such that we only create the [Future] once,
/// no matter how many times our widget rebuild.
/// If we used a [StatelessWidget], in the event where [App] is rebuilt, that
/// would re-initialize FlutterFire and make our application re-enter loading state,
/// which is undesired.
class App extends StatefulWidget {
  // Create the initialization Future outside of `build`:
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {
  /// The future is part of the state of our widget. We should not call `initializeApp`
  /// directly inside [build].
  final Future<FirebaseApp> _initialization = Firebase.initializeApp();

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      // Initialize FlutterFire:
      future: _initialization,
      builder: (context, snapshot) {
        // Check for errors
        if (snapshot.hasError) {
          return SomethingWentWrong();
        }

        // Once complete, show your application
        if (snapshot.connectionState == ConnectionState.done) {
          return MyAwesomeApp();
        }

        // Otherwise, show something whilst waiting for initialization to complete
        return Loading();
      },
    );
  }
}

如您所见,在调用 runApp(App()); 之后 调用该函数。 Firebase.initializeApp(); return 不仅是 Future<FirebaseApp>(您的代码中没有 await),它还是主要小部件状态的一部分。