😚

【Flutter】クレデンシャル情報を.envファイルで取得し、ネイティブファイルで利用する方法【GoogleMap】

2023/01/25に公開
1

アプリ開発をする際に、API Keyなどの第三者に知られてはいけない情報(クレデンシャル情報)を扱う場面があるかと思います。
このようなクレデンシャル情報は、プログラムにハードコーディングするのではなく、.envなどの環境設定ファイルから読み込んで使用することがアプリ開発の鉄則です。

もしハードコーディングしてそのままGitにコミットしてしまった日には地獄を見ます。笑
Gitの履歴を見れば誰でもクレデンシャル情報が知れてしまうので。笑

ということで今回は、FlutterでGoogleMapを実装するケースを想定し、API Keyを.envファイルから読み込みMapを表示してみたいと思います。

GoogleMapをFlutterで実装する際、iOSやAndroidのネイティブファイルにAPI Keyを入力する必要がありますが、この際にFlutterの.envライブラリから取得した情報を使用する方法をご紹介します。

ソースコード

こちらにソースコードを載せています。もし必要であればご覧ください〜
https://github.com/ryota-dev/FlutterConfig_GoogleMap

この記事を読んでわかること

  • Flutterで.envファイルからクレデンシャル情報を取得し、ネイティブファイルで使用する方法

使用するライブラリ

flutter_configのほかにflutter_dotenvというライブラリが有名ですが、今回はネイティブファイルで.envファイルを読み込むという要件があるため、flutter_configを採用します。
(もし要望があればflutter_dotenvの使い方記事も書こうかな)

ライブラリをインストール

flutter_config

flutter pub add flutter_config

GoogleMapライブラリ

flutter pub add google_maps_flutter

GoogleMapWidget作成

main.dartにGoogleMapWidgetを作成

main.dart
class GoogleMapWidget extends StatefulWidget {
  const GoogleMapWidget({super.key});

  
  State<GoogleMapWidget> createState() => _GoogleMapWidgetState();
}

class _GoogleMapWidgetState extends State<GoogleMapWidget> {
  final Completer<GoogleMapController> _controller =
      Completer<GoogleMapController>();

  static const CameraPosition _kGooglePlex = CameraPosition(
    target: LatLng(35.68126232447219, 139.76712479827628),
    zoom: 15,
  );

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Google Map Flutter Config'),
      ),
      body: GoogleMap(
        mapType: MapType.normal,
        initialCameraPosition: _kGooglePlex,
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
      ),
    );
  }
}

ルートディレクトリに.env作成、環境変数設定

.env
.env
IOS_MAP_API_KEY=YOUR IOS API KEY HERE
ANDROID_MAP_API_KEY=YOUR ANDROID API KEY HERE

iOS側の設定

AppDelegate.swift変更

ios/Runner/AppDelegate.swift

AppDelegate.swift
import UIKit
import Flutter
import GoogleMaps
import flutter_config // ここ追記

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GMSServices.provideAPIKey(FlutterConfigPlugin.env(for: "IOS_MAP_API_KEY")) // ここ追記
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

Android側の設定

AndroidManifest.xml変更

android/app/src/main/AndroidManifest.xml

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.flutter_config_google_map">
   <application
        android:label="flutter_config_google_map"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        ...
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
        <meta-data android:name="com.google.android.geo.API_KEY"
               android:value="@string/ANDROID_MAP_API_KEY"/> // ここ追記
    </application>
</manifest>

build.gradle変更

android/app/build.gradle

build.gradle
...

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
apply from: project(':flutter_config').projectDir.getPath() + "/dotenv.gradle" // ここ追記

...

最終的なソースコード

main.dart
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: GoogleMapWidget(),
    );
  }
}

class GoogleMapWidget extends StatefulWidget {
  const GoogleMapWidget({super.key});

  
  State<GoogleMapWidget> createState() => _GoogleMapWidgetState();
}

class _GoogleMapWidgetState extends State<GoogleMapWidget> {
  final Completer<GoogleMapController> _controller =
      Completer<GoogleMapController>();

  static const CameraPosition _kGooglePlex = CameraPosition(
    target: LatLng(35.68126232447219, 139.76712479827628),
    zoom: 15,
  );

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Google Map Flutter Config'),
      ),
      body: GoogleMap(
        mapType: MapType.normal,
        initialCameraPosition: _kGooglePlex,
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
      ),
    );
  }
}

結果

iOS、Androidともに.envファイルからAPI Keyを読み込み、GoogleMapを表示することができました。
実際に使用する際は、.envファイルを.gitignore対象にしてGitの管理対象から外すようにしてください。

iOS

Android

Discussion

笹口翔伍笹口翔伍

素晴らしい記事をありがとうございます。
ios, androidと同様に、~/web/index.html にもAPIキーを設定することが可能だと思います。(参考)

このhtmlファイル内に記載するAPIキーを.envから読み取る方法については、何かお考えがあるかお聞きしたいです。よろしくお願いたします。