タグ: iOS

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

  • 【実況】Flutter Apple Silicon mac でハローワールドまで

    この記事はとりあえず公式ドキュメントに従って実行するまでを実況しています。またしても私はインターネットデブリを作る。(公式ドキュメントを読もう!)

    https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=ja#2

    環境

    • Apple Silicon M1 MacBook Air
    • 16Gb
    • Sequoia 15.0
    • Xcode Version 16.0 (16A242d)

    2024/10/10時点での実行確認

    手順

    Flutter 環境構築

    公式ドキュメントからGet Started のページに移動します。

    このページを参考にしました。

    プラットフォームごとにインストールの手順を解説してくれています。
    https://docs.flutter.dev/get-started/install

    一応 iOS を選択した。()

    rosetta 2 を使うっぽいのでインストール。

    softwarupdate --install--rosetta

    これを読んでる人は大丈夫そうですが……。

    エミュレータ用にXcode, コーディング用にVSCode はインストールしておきましょう。

    VScodeのプラグインはhttps://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter こちらが公式で推薦されていたのでインストールしておきましょう。

    上記のFlutter用の拡張機能のインストールを確認したら。

    VSCodeを使ってFlutterをInstallします。

    次にコマンドパレット[cmd + shift + P]を開いて [Flutter]と入力します。

    選択肢にある[Fluttter: New Project]を選択します。

    SDKがインストールされていない場合は右下にポップアップが出てくるので[Download SDK]を押しましょう。

    どこにSDKをインストールするかを選択できるので、ルートの下にdevelopment フォルダを用意するのがいいでしょう。 ~/development/ フォルダを選択したら[clone Flutter]を押します。

    最初のアプリを作る

    コマンドパレットを開いて flutter: new project をします。プロジェクトは好きなディレクトリを選択します。Project Name は first_flutter_app にしました。

    とりあえず素のまま実行してみる(高いとんかつも最初の一口はそのまま食べろと言われる)

    F5 キーを押すと実行できます。

    カウンターアプリが立ち上がった!! 良さげ〜