8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Flutter Web で Firebase JavaScript SDK が使えるのか試してみた

Last updated at Posted at 2020-12-14

概要

こちらは Flutter #2 Advent Calendar 2020 の 14日目の記事です。

まだ、本格的に開発で使っていないのですが、iOS/Androidのアプリ開発に加えてゆくゆくWebアプリも開発できる予定のマルチプラットフォーム Flutter をキャッチアップ中で調査したり触ったりしております。

先日、12/2に開催された PORT Firebase × Flutter オンライン に参加しました。

そこで気になったことが、iOS/Androidのビジネスロジック( /lib 配下のDartクラス )とは分離してしまうことになるものの、Flutter Web に Firebase JavaScript SDK が組み込めて使えるのか調査してみることにしました。

前提

Flutter と Firebase の入門的な話(前提知識やスタートガイドなどの情報)は割愛いたしますmm
公式のドキュメントがしっかり解説されており、参考になる記事も増えてきているため、本記事以外を参考によろしくお願いします。

また Flutter Web は、公式が正式版をまだ公開しておらず、ベータ版で提供されています。
そのため、本記事は責任を一切負えないため、参考程度に使用してください。

Flutter と Firebase をどう管理するか

まずは、Building a web application with Flutter の内容を済ませておき、flutter createでプロジェクト用意しておく。

その後にfirebase initしますが、同じ階層でFirebaseも一緒に管理するとなると困難になり、挙動が変わる原因にもなりかねないため以下のようにディレクトリを分けてFlutterリソースとFirebaseリソースを管理すると良いでしょう。

 

Firebase JavaScript SDK

 

Firebaseコンソールのダッシュボードに表示されている↑Webアプリの追加を済ませて、設定画面からJavascript SDKの組み込み方法を確認する。

  

このまま Firebase Hosting で Flutter Web リソースをアップして対応まで考えると左の図で良いのですが、そもそも使えるのかわからないので、まずは右のCDN版で実行して使えることを確かめていきます。

Firebase SDK snippet

上記右画像のFirebase SDK snippetに書かれている組み込み方法をそのまま書いて実行してみたところ次のようにエラーで正常動作しませんでした。

flutter/web/index.html
<!DOCTYPE html>
<html>
<head>
  <base href="/">

  <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="flutter_web_sample">
  <link rel="apple-touch-icon" href="icons/Icon-192.png">

  <!-- Favicon -->
  <link rel="icon" type="image/png" href="favicon.png"/>

  <title>flutter_web_sample</title>
  <link rel="manifest" href="manifest.json">
</head>
<body>
  <script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('flutter-first-frame', function () {
        navigator.serviceWorker.register('flutter_service_worker.js');
      });
    }
  </script>
  <script src="main.dart.js" type="application/javascript"></script>

  <!-- The core Firebase JS SDK is always required and must be listed first -->
  <script src="https://www.gstatic.com/firebasejs/8.2.0/firebase-app.js"></script>

  <script>
    // Your web app's Firebase configuration
    var firebaseConfig = {
      apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      authDomain: "flutter-server-app.firebaseapp.com",
      projectId: "flutter-server-app",
      storageBucket: "flutter-server-app.appspot.com",
      messagingSenderId: "01234567890",
      appId: "0:01234567890987654321:web:abcd01234efghi56789"
    };
    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);
  </script>
</body>
</html>

スクリーンショット 2020-12-14 18.29.45.png

$ flutter run -d chrome
Running "flutter pub get" in flutter...                          1,117ms
Launching lib/main.dart on Chrome in debug mode...
Syncing files to device Chrome...                                  37.3s
Debug service listening on ws://127.0.0.1:58489/XXXXXXXXXXXX=/ws

Warning: Flutter's support for web development is not stable yet and hasn't
been thoroughly tested in production environments.
For more information see https://flutter.dev/web

🔥  To hot restart changes while running, press "r" or "R".
For a more detailed help message, press "h". To quit, press "q".
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following JSNoSuchMethodError was thrown building MyApp(dirty):
TypeError: Cannot read property 'MaterialApp' of undefined

The relevant error-causing widget was:
  MyApp file:///Users/TAKUYA_AIR/flutter-projects/flutter_web_sample/flutter/lib/main.dart:4:10

When the exception was thrown, this was the stack:
packages/flutter_web_sample/main.dart 11:12                              build
packages/flutter/src/widgets/framework.dart 4749:28                      build
packages/flutter/src/widgets/framework.dart 4675:15                      performRebuild
packages/flutter/src/widgets/framework.dart 4369:5                       rebuild
packages/flutter/src/widgets/framework.dart 4654:5                       [_firstBuild]
packages/flutter/src/widgets/framework.dart 4649:5                       mount
packages/flutter/src/widgets/framework.dart 3615:13                      inflateWidget
packages/flutter/src/widgets/framework.dart 3380:18                      updateChild
packages/flutter/src/widgets/binding.dart 1203:16                        [_rebuild]
packages/flutter/src/widgets/binding.dart 1174:5                         mount
packages/flutter/src/widgets/binding.dart 1116:16                        <fn>
packages/flutter/src/widgets/framework.dart 2730:19                      buildScope
packages/flutter/src/widgets/binding.dart 1115:12                        attachToRenderTree
packages/flutter/src/widgets/binding.dart 954:24                         attachRootWidget
packages/flutter/src/widgets/binding.dart 936:7                          <fn>
dart-sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart 48:19  internalCallback

════════════════════════════════════════════════════════════════════════════════════════════════════

dartのエラーは、おそらくhtmlサイドでエラーになっているから連携できず影響しているんだと思って、flutter runに出ているdartに関するエラーはあまり気にしないことにしました。

公式ドキュメント

次に JavaScript SDKのスタートガイドページの ステップ 3: Firebase SDK を追加して Firebase を初期化する を確認して以下の箇所を変えてみました。すると flutter run にエラーは表示されず、やはり正常動作ではないものの結果が変わりました。

flutter/web/index.html
【省略】

  <!-- The core Firebase JS SDK is always required and must be listed first -->
  <!-- <script src="https://www.gstatic.com/firebasejs/8.2.0/firebase-app.js"></script> -->
  <script defer src="https://www.gstatic.com/firebasejs/7.23.0/firebase-app.js"></script>
  <script defer src="https://www.gstatic.com/firebasejs/7.23.0/firebase-auth.js"></script>
  <script defer src="https://www.gstatic.com/firebasejs/7.23.0/firebase-firestore.js"></script>

【省略】

 

firebase_core_web

調べていると [firebase_core_web] Uncaught ReferenceError: firebase is not defined #2826 というissueを見つけて、内容を確認すると本記事と同じく Flutter Web で Firebase を組み込んだ際の問題でした。

ただ、Closeされているものの何が原因だったのかわからずで、とりあえず思ったことを試していくことに。
以前、Flutter のセットアップの際にiOSだけエラーだったもののWebだけ開発するなら大丈夫だろうと無視していたが、結局 flutter doctor が全て正常でなければビルドできない経験がありました。
もしかすると今回も似たような感じで、Webだけ対応していてiOS/AndroidはFirebaseの対応していないからエラーになっている可能性があるなと思い、firebase_core_webを入れて確認してみるものの変化はありませんでした・・・笑汗

firebase_core_web/install

Web Installation | FlutterFire

firebase_core_web をしっかり確認していくと、ここで Flutter と Firebase を連携する際に提供しているドキュメントがあることを改めて確認(存在は知っていました笑)し、JavaScript SDK の組み込み方法が解説されている Web Installation の存在がわかりましたw

どうやらflutter_service_worker.jsmain.dart.jsの準備よりも前に Firebase を組み込むようでした。
案の定、正常動作したので試しに Firebase RemoteConfig と連携してみました。

flutter/web/index.html
【省略】

  <!-- The core Firebase JS SDK is always required and must be listed first -->
  <!-- <script src="https://www.gstatic.com/firebasejs/8.2.0/firebase-app.js"></script> -->
  <!-- <script defer src="https://www.gstatic.com/firebasejs/7.23.0/firebase-app.js"></script>
  <script defer src="https://www.gstatic.com/firebasejs/7.23.0/firebase-auth.js"></script>
  <script defer src="https://www.gstatic.com/firebasejs/7.23.0/firebase-firestore.js"></script> -->
  <script src="https://www.gstatic.com/firebasejs/7.23.0/firebase-app.js"></script>

  <script>
    // Your web app's Firebase configuration
    var firebaseConfig = {
      apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      authDomain: "flutter-server-app.firebaseapp.com",
      projectId: "flutter-server-app",
      storageBucket: "flutter-server-app.appspot.com",
      messagingSenderId: "01234567890",
      appId: "0:01234567890987654321:web:abcd01234efghi56789"
    };
    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);

    // Remote Config
    const remoteConfig = firebase.remoteConfig();
    remoteConfig.fetchAndActivate()
      .then(() => {
        const serviceName = remoteConfig.getValue('service_name');
        console.log("service_name: " + serviceName._value);
      })
      .catch((err) => {
        console.error(err);
      });
  </script>

  <script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('flutter-first-frame', function () {
        navigator.serviceWorker.register('flutter_service_worker.js');
      });
    }
  </script>

  <script src="main.dart.js" type="application/javascript"></script>

【省略】

 
 

Hosting

JavaScript SDK を調整して Hosting にアップして確認したところ問題なく動きました!

$ cd flutter
$ flutter build web
Running "flutter pub get" in flutter...                            573ms
Compiling lib/main.dart for the Web...                             29.2s

$ cd ../firebase
$ cp -r ../flutter/build/web/ public/

$ firebase deploy --only hosting

=== Deploying to 'flutter-server-app'...

i  deploying hosting
i  hosting[flutter-server-app]: beginning deploy...
i  hosting[flutter-server-app]: found 14 files in public
✔  hosting[flutter-server-app]: file upload complete
i  hosting[flutter-server-app]: finalizing version...
✔  hosting[flutter-server-app]: version finalized
i  hosting[flutter-server-app]: releasing new version...
✔  hosting[flutter-server-app]: release complete

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/flutter-server-app/overview
Hosting URL: https://flutter-server-app.web.app

スクリーンショット 2020-12-14 19.59.26.png

まとめ

Flutter に Firebase を導入される際は、 FlutterFire を参考にしましょうー!😇
 

8
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?