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'],
  );
}

coiai.netでは案件受付中です。
Vtuber、建築モデリング、EC構築、ネイティブアプリ制作、制服の制作(実は縫製業もメイン)、Vision Pro向けアプリ etc…
様々な制作開発を行っています。

ご気軽にご相談ください!

コイアイちゃんのアバター

この記事を書いたのは


Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


Home
About
Blog
Works
Contact