カテゴリー: Flutter

  • 【Flutter】primarySwatch: Colors.blue,はもう古い。これからは〇〇の時代

    【Flutter】primarySwatch: Colors.blue,はもう古い。これからは〇〇の時代

    Flutterで

    final ThemeData darkTheme = ThemeData(
      fontFamily: 'NotoSansJP',
      primarySwatch: Colors.blue,
    );

    のようにprimarySwatch は使えなくなっています。

    どうすれば良いか?

    現在(25年5月)全体の色変更するには

    final ThemeData darkTheme = ThemeData(
      fontFamily: 'NotoSansJP',
      colorScheme: ColorScheme.fromSeed (
        seedColor: Colors.blue, 
        brightness: Brightness.dark, 
        dynamicSchemeVariant: DynamicSchemeVariant.tonalSpot
      ),
    );

    のように colorScheme を使用する必要があります。

    • 全体の所謂メインカラーを調整するには seedColor を使用してください。
    • ダークモードの設定はColorScheme内でbrightness: Brightness.darkのように指定すればOK
    • トーン(色合い)を変更するにはdynamicSchemeVariant を設定します。

    各プロパティの値については公式ドキュメントを参考にするのが一番です!

    デフォルトの状態

    各色の設定については公式ドキュメントの中断あたりにある例がめちゃくちゃわかりやすいです。ぜひ参考に

    参考

    https://api.flutter.dev/flutter/material/ColorScheme-class.html

    https://api.flutter.dev/flutter/material/MaterialColor-class.html

  • Flutter App icon を設定する

    Flutter App icon を設定する

    iOS, Android でアプリリリースするタイミングでアイコンが必要になります。

    iOSの場合は Runner.xcworkspace に自分で設定してしまうと、リリース時にエラーの原因になります。

    今回はflutterの安全なアイコンの設定方法についてです。

    やり方

    最小構成は以下の通りです。

    pubspec.yaml に追加します。(それぞれのプラットフォームごとに対応させるにはこちらを参考ください:https://pub.dev/packages/flutter_launcher_icons)

    dev_dependencies:
      flutter_launcher_icons: "^0.14.3"
    
    flutter_launcher_icons:
      android: "launcher_icon"
      ios: true
      image_path: "assets/icon/icon.png"

    できたらパッケージを実行します。

    flutter pub get
    dart run flutter_launcher_icons

    実行して、VSCodeのiosディレクトリの上で右クリック、Xcode で開きます。

    そうすると、アイコンがセットされているのを確認できます。

    参考

    https://pub.dev/packages/flutter_launcher_icons

  • Flutter iOSでビルドできない No such module ‘Flutter’ Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

    Flutter iOSでビルドできない No such module ‘Flutter’ Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

    Flutter で iOS用にbuild するも下記のエラーが AppDelegate.swift で起こってしまい、実行できません。

    No such module ‘Flutter’

    Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

    この記事はこれの解決方法です。

    解決方法

    Flutter プロジェクトのキャッシュを削除します。依存関係の問題を解消するために行います。

    flutter clean

    pubspec.yaml に従ってパッケージのダウンロードや更新、依存関係のセットアップを行います。

    flutter pud get

    ios ディレクトリに移動ます。

    cd ios

    ios/Podfile に基づいて Pods/ フォルダを作成します。また、ios/Podfile.lockを更新し、依存関係のバージョンを固定します。

    pod install

    xcode を書きコマンドで開きます。 Runner.xcodeproj ではないので注意⚠️

    open Runner.xcworkspace

    これで解決しない場合

    flutter をアップグレードしてみましょう。(私はこれで解決しました……。トホホ)アップグレードしたらまた、clean, pub get, pod install の手順を踏んでください。

    flutter upgrade

  • XCode 環境変数追加 Edit Scheme…

    XCode 環境変数追加 Edit Scheme…

    Flutter のプロジェクトで

    import Flutter
    import UIKit
    import GoogleMaps
    
    @main
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        GMSServices.provideAPIKey(ProcessInfo.processInfo.environment["MY_API_KEY"]!)
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }
    Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

    のエラーが出ました。

    この際直打ちのAPIキーはやめて、環境変数に設置することにしました。

    やり方

    XCodeでプロジェクト名のところをクリックすると Edit Scheme… という項目があるのでクリックします。

    Environment Variables のところに + ボタンを押して、追加します。

    GOOGLE_MAPS_API_KEY
    
    hogehogehogehogehogehogehogeho

    みたいな感じで Name, Value に設定しました。

    その後、AppDelegate .swiftを以下のように書き換えました。

    import Flutter
    import UIKit
    import GoogleMaps
    
    @main
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        
          // Xcode の環境変数から APIキー を取得
          if let apiKey = ProcessInfo.processInfo.environment["GOOGLE_MAPS_API_KEY"], !apiKey.isEmpty {
              GMSServices.provideAPIKey(apiKey)
          } else {
              fatalError("Google Maps API Key is missing. Please set GOOGLE_MAPS_API_KEY in Xcode's Environment Variables.")
          }
    
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }
    

    これで動作しました!やったー

  • 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 build iOS error ビルドできない

    Flutter build iOS error ビルドできない

    flutter build ios

    としたところ、以下のようなエラーが出てきた。

    ══════════ No valid code signing certificates were found You can connect to your Apple Developer account by signing in with your Apple ID in Xcode and create an iOS Development Certificate as well as a Provisioning Profile for your project by:   1- Open the Flutter project's Xcode target with        open ios/Runner.xcworkspace   2- Select the 'Runner' project in the navigator then the 'Runner'   target      in the project settings   3- Make sure a 'Development Team' is selected under Signing &   Capabilities > Team.      You may need to:          - Log in with your Apple ID in Xcode first          - Ensure you have a valid unique Bundle ID          - Register your device with your Apple Developer Account          - Let Xcode automatically provision a profile for your app   4- Build or run your project again   5- Trust your newly created Development Certificate on your iOS   device      via Settings > General > Device Management > [your new      certificate] > Trust  For more information, please visit:   https://developer.apple.com/library/content/documentation/IDEs/Conce   ptual/   AppDistributionGuide/MaintainingCertificates/MaintainingCertificates   .html  Or run on an iOS simulator without code signing ══════════════════════════════════════════════════════════════════════ ══════════ No development certificates available to code sign app for device deployment
    ══════════
    No valid code signing certificates were found
    You can connect to your Apple Developer account by signing in with
    your Apple ID
    in Xcode and create an iOS Development Certificate as well as a
    Provisioning
    Profile for your project by:
      1- Open the Flutter project's Xcode target with
           open ios/Runner.xcworkspace
      2- Select the 'Runner' project in the navigator then the 'Runner'
      target
         in the project settings
      3- Make sure a 'Development Team' is selected under Signing &
      Capabilities > Team.
         You may need to:
             - Log in with your Apple ID in Xcode first
             - Ensure you have a valid unique Bundle ID
             - Register your device with your Apple Developer Account
             - Let Xcode automatically provision a profile for your app
      4- Build or run your project again
      5- Trust your newly created Development Certificate on your iOS
      device
         via Settings > General > Device Management > [your new
         certificate] > Trust
    
    For more information, please visit:
      https://developer.apple.com/library/content/documentation/IDEs/Conce
      ptual/
      AppDistributionGuide/MaintainingCertificates/MaintainingCertificates
      .html
    
    Or run on an iOS simulator without code signing
    ══════════════════════════════════════════════════════════════════════
    ══════════
    No development certificates available to code sign app for device
    deployment
    

    解決法

    terminal で ios/Runner.xcworkspace ファイルを開く

    open ios/Runner.xcworkspace
    XCode
    こんな感じで xcode が立ち上がる。

    Xcodeで「Runner」プロジェクトを選択

    「Signing & Capabilities」タブを開く

    私の場合、久しぶりのストアアップロードで規約に同意していないのが原因でした。

    Unable to process request – PLA Update available
    You currently don’t have access to this membership resource. To resolve this issue, agree to the latest Program License Agreement in your developer account.

    StoreConnectから同意したらできました。

    “Automatically manage signing”(自動管理) をチェック

    「Team」のプルダウンから Apple Developer アカウントを選択

    「Provisioning Profile」が作成されるのを確認

    以上です。

    再度以下のコマンドでビルドしなおしましょう。

    flutter build iOS

  • 【Flutter】WebでいうところのDivタグ

    【Flutter】WebでいうところのDivタグ

    FlutterでHTMLの <div> タグのような機能を持つウィジェットはいくつかあります。

    1. Container(基本のDiv)

    最も基本的な <div> の代わりになるのが Container です。

    Container(
    
      width: 200,
    
      height: 100,
    
      color: Colors.blue,
    
      child: Center(
    
        child: Text("Container", style: TextStyle(color: Colors.white)),
    
      ),
    
    )

    • CSSの div に最も近い要素
    • 幅・高さ・背景色などを指定できる

    2. SizedBox(幅・高さだけ指定)

    CSSの <div style=”width: 100px; height: 100px;”> のように、幅と高さだけ指定するなら SizedBox が便利です。

    SizedBox(
    
      width: 100,
    
      height: 100,
    
      child: Center(child: Text("SizedBox")),
    
    )
    • 背景色なしのシンプルなブロックを作れる

    3. Column / Row(複数の要素を並べる)

    <div> で要素を縦・横に並べるなら Column や Row を使います。

    Column(
    
      children: [
    
        Text("上のテキスト"),
    
        Container(
    
          width: 100,
    
          height: 50,
    
          color: Colors.blue,
    
          child: Center(child: Text("青いボックス")),
    
        ),
    
      ],
    
    )
    • 縦方向に要素を並べる(横方向なら Row)

    4. Stack(重ねる)

    <div> の position: absolute; に相当するのが Stack です。

    Stack(
    
      children: [
    
        Container(width: 200, height: 100, color: Colors.blue),
    
        Positioned(
    
          left: 50,
    
          top: 20,
    
          child: Text("重ねたテキスト", style: TextStyle(color: Colors.white)),
    
        ),
    
      ],
    
    )
    • 要素を自由に配置できる

    5. Expanded(親の幅いっぱいにする)

    CSSの width: 100% に相当するのが Expanded です。

    Row(
    
      children: [
    
        Expanded(child: Container(height: 50, color: Colors.red)),
    
        Expanded(child: Container(height: 50, color: Colors.blue)),
    
      ],
    
    )
    • 親の幅いっぱいに広げる(flex-grow: 1 のような動き)

    6. Flexible(割合で幅を調整)

    CSSの flex: 2 1 auto; のような動きをするのが Flexible です。

    Row(
    
      children: [
    
        Flexible(flex: 2, child: Container(height: 50, color: Colors.red)),
    
        Flexible(flex: 1, child: Container(height: 50, color: Colors.blue)),
    
      ],
    
    )
    • 要素の幅を割合で調整できる

    結論

    目的 Flutterのウィジェット

    <div> の基本機能Container
    サイズのみ指定SizedBox
    要素を縦に並べるColumn
    要素を横に並べるRow
    要素を重ねるStack
    幅を親に合わせる (width: 100%)Expanded
    幅の割合を調整 (flex)Flexible

    Flutterでは Container が最も <div> に近いが、レイアウトに応じて Column / Row / Stack も活用するのがポイント

  • Flutter で Firebase を使うには?導入までのコマンド紹介

    Flutter で Firebase を使うには?導入までのコマンド紹介

    これは何?

    FlutterでFirebaseを使う場合のコマンドの紹介です。

    環境

    • AppleSilicon M1 MacBookAir
    • macOS
    • firebase cli version 13.23.0 
    • Flutter version 3.24.4

    やり方

    1 プロジェクトの作成

    firebase のページにアクセスして、プロジェクトを作成しましょう。

    https://console.firebase.google.com

    firebase

    2 Firebase Cli の設定

    環境ごとに異なると思いますので、各々公式のガイドを参考に進めてください。

    3 CLIの初期操作

    firebase login

    このコマンドでブラウザが立ち上がり、Googleのアカウントの選択と権限の確認が出てきます。

    firebase projects:list

    ログインの確認も兼ねて上記コマンドを実行してみてください。
    ステップ1で作ったプロジェクト名と projectID などが出てくると思います。ProjectID はこの後使うのでコピーしておきましょう。

    4 Flutterへの設定

    まずFlutterプロジェクトのあるディレクトリへ移動しましょう。

    cd あなたのFlutterプロジェクトのディレクトリ

    次に下記コマンドを実行してパッケージを追加します。

    flutter pub add firebase_core

    つづて下記コマンドを実行します。

    dart pub global activate flutterfire_cli

    このコマンドを実行した後、パスを通す必要があります。
    AppleSilicon mac をお使いの方はターミナルはzshだと思いますので下のコマンドを実行します。

    echo 'export PATH="$PATH:$HOME/.pub-cache/bin"' >> ~/.zshrc

    できたら、保存したzshの設定をターミナルに読み込ませるのに下記コマンドを実行します。

    source ~/.zshrc

    最後に以下コマンドを実行します。[さっきコピーしたID]のところは自分のIDで入れ替えてください。

    flutterfire configure --project=さっきコピーしたID

    実行すると

    ✔ Which platforms should your configuration support

    これはどのプラットフォームで使うのか聞かれています。
    スペースを押すとチェックを外せます。
    全部のプラットフォームで使うならこのままEnterを押して進みます。

    次に

    ? Which Android application id (or package name) do you want to use for this configuration, e.g. ‘com.example.app’?

    と聞かれます。これはAndroidのビルドIDなのですが、com.自分の名前.アプリ名 と言った感じでOKです。

    以上でFlutterで使えるようになります。
    お疲れ様でした!

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

    【実況】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 キーを押すと実行できます。

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

Home
About
Blog
Works
Contact