タグ: web

  • Flutter Webでの Firebase API Key の読み込み クロスプラットフォーム対応

    Flutter Webでの Firebase API Key の読み込み クロスプラットフォーム対応

    Flutter でWebで動作させる場合にAPI Keyを直書きしない方法について解説します。

    通常 index.html にそのまま書けば動作します。

    <body>
      <script src="flutter_bootstrap.js" async></script>
      <script>
        const apiKey = "{{API_KEY}}"; // Dartコードで置換
        const script = document.createElement('script');
        script.src = `https://maps.googleapis.com/maps/api/js?key=ここにAPI KEYベタ打ち`;
        document.head.appendChild(script);
      </script>
    </body>

    しかしこれだと、Gitなどでの管理ができなくなってしまうため、.env ファイルから読み出したいところです。しかしindex.html から直接.env を参照することはできません。

    解決方法

    プラットフォームごとの処理を追加

    Web の場合は以下のファイルを読み込むようにします。 lib の直下に utils ディレクトリを作成し、web_utils.dart を作成しました。

    このようにファイルを分けることで、
    import ‘dart:html’ as html;
    が使えるようになります。

    このパッケージはWebのみで動作するため、他のプラットフォームのコードに含められないからです。

    // ignore: avoid_web_libraries_in_flutter
    import 'dart:html' as html;
    
    void addGoogleMapsScript(String apiKey) {
      final script = html.ScriptElement()
        ..src = 'https://maps.googleapis.com/maps/api/js?key=$apiKey&callback=initMap'
        ..type = 'text/javascript'
        ..async = true
        ..defer = true;
      html.document.body!.append(script);
    }

    Web 以外(iOS, Android)の場合の処理を書いたファイルも用意します。utils ディレクトリに stub_utils.dart を作成。以下のように書きました。

    void addGoogleMapsScript(String apiKey) {
      // モバイルプラットフォームでは何もしない
    }

    main.dart での処理

    flutter_dotenv パッケージを追加します。

    flutter pub add flutter_dotenv
    import 'package:flutter/material.dart';
    import 'package:firebase_core/firebase_core.dart';
    import 'package:flutter_dotenv/flutter_dotenv.dart';
    import 'firebase_options.dart';
    import 'widgets/bottom_nav_layout.dart';
    import 'package:flutter/foundation.dart' show kIsWeb;
    
    // 条件付きインポート
    import 'utils/web_utils.dart'
      if (dart.library.html) 'utils/web_utils.dart'
      if (dart.library.io) 'utils/stub_utils.dart';
    
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      
      // 環境変数を読み込む
      await dotenv.load(fileName: ".env");
    
      // Firebaseの初期化
      await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform,
      );
    
      // Webの場合のみGoogle Mapsスクリプトを追加
      if (kIsWeb) {
        final apiKey = dotenv.env['GOOGLE_MAPS_API_KEY'];
        if (apiKey != null && apiKey.isNotEmpty) {
          addGoogleMapsScript(apiKey);
        } else {
          print('Error: GOOGLE_MAPS_API_KEY is not set in the .env file.');
        }
      }
    
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Anonymous Login Demo',
          theme: ThemeData(
            useMaterial3: true,
            colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),
          ),
          home: const BottomNavLayout(currentIndex: 0),
        );
      }
    }

    firebase console で web を追加

    firebase console でモバイルだけでなく、webを追加して、apikey を発行しましょう。

    これを.envに追加します。

    .evn ファイルの設定

    以下のように設定します。
    api_key_here のところで先ほど設定したapi key を入力しましょう。

    GOOGLE_MAPS_API_KEY=your_google_maps_api_key_here
    
    # Firebase iOS Configuration
    FIREBASE_IOS_API_KEY=your_firebase_ios_api_key_here
    FIREBASE_IOS_APP_ID=your_firebase_ios_app_id_here
    FIREBASE_IOS_MESSAGING_SENDER_ID=your_firebase_ios_messaging_sender_id_here
    FIREBASE_IOS_PROJECT_ID=your_firebase_ios_project_id_here
    FIREBASE_IOS_STORAGE_BUCKET=your_firebase_ios_storage_bucket_here
    FIREBASE_IOS_BUNDLE_ID=your_firebase_ios_bundle_id_here
    
    # Firebase Web Configuration
    FIREBASE_WEB_API_KEY=your_firebase_web_api_key_here
    FIREBASE_WEB_AUTH_DOMAIN=your_firebase_web_auth_domain_here
    FIREBASE_WEB_PROJECT_ID=your_firebase_web_project_id_here
    FIREBASE_WEB_STORAGE_BUCKET=your_firebase_web_storage_bucket_here
    FIREBASE_WEB_MESSAGING_SENDER_ID=your_firebase_web_messaging_sender_id_here
    FIREBASE_WEB_APP_ID=your_firebase_web_app_id_here
    FIREBASE_WEB_MEASUREMENT_ID=your_firebase_web_measurement_id_here

    firebase の設定 firebase_options.dart

    プラットフォームごとに api key を切り分けるのに使います。

    import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
    import 'package:flutter/foundation.dart' show defaultTargetPlatform, kIsWeb, TargetPlatform;
    import 'package:flutter_dotenv/flutter_dotenv.dart';
    
    /// Default [FirebaseOptions] for use with your Firebase apps.
    class DefaultFirebaseOptions {
      static FirebaseOptions get currentPlatform {
        if (kIsWeb) {
          return web;
        }
        switch (defaultTargetPlatform) {
          case TargetPlatform.android:
            throw UnsupportedError('DefaultFirebaseOptions have not been configured for android.');
          case TargetPlatform.iOS:
            return ios;
          case TargetPlatform.macOS:
            throw UnsupportedError('DefaultFirebaseOptions have not been configured for macos.');
          case TargetPlatform.windows:
            throw UnsupportedError('DefaultFirebaseOptions have not been configured for windows.');
          case TargetPlatform.linux:
            throw UnsupportedError('DefaultFirebaseOptions have not been configured for linux.');
          default:
            throw UnsupportedError('DefaultFirebaseOptions are not supported for this platform.');
        }
      }
    
      static final FirebaseOptions ios = FirebaseOptions(
        apiKey: dotenv.env['FIREBASE_IOS_API_KEY']!,
        appId: dotenv.env['FIREBASE_IOS_APP_ID']!,
        messagingSenderId: dotenv.env['FIREBASE_IOS_MESSAGING_SENDER_ID']!,
        projectId: dotenv.env['FIREBASE_IOS_PROJECT_ID']!,
        storageBucket: dotenv.env['FIREBASE_IOS_STORAGE_BUCKET']!,
        iosBundleId: dotenv.env['FIREBASE_IOS_BUNDLE_ID']!,
      );
    
      static final FirebaseOptions web = FirebaseOptions(
        apiKey: dotenv.env['FIREBASE_WEB_API_KEY']!,
        authDomain: dotenv.env['FIREBASE_WEB_AUTH_DOMAIN']!,
        projectId: dotenv.env['FIREBASE_WEB_PROJECT_ID']!,
        storageBucket: dotenv.env['FIREBASE_WEB_STORAGE_BUCKET']!,
        messagingSenderId: dotenv.env['FIREBASE_WEB_MESSAGING_SENDER_ID']!,
        appId: dotenv.env['FIREBASE_WEB_APP_ID']!,
        measurementId: dotenv.env['FIREBASE_WEB_MEASUREMENT_ID'],
      );
    }

Home
About
Blog
Works
Contact