snovaのブログ

主にプログラミングやデジタルコンテンツについて書きます。最近はPython, Flutter, VRに興味があります。

Flutterから利用できるFirebaseサービスをカウンターアプリで実践(準備編)

はじめに

Firebaseを利用することで、データの保存や同期、アプリの認証、メッセージの通知、アプリの分析、パフォーマンス測定などの機能を簡単にモバイルアプリに追加することが出来ます。 FlutterでコーディングするときもFirebaseを使うことができますが、個人的にFirebaseのサービスをうまく活用できていないと感じていました。

そこで、今回Flutterから利用できるFirebaseの機能をカウンターアプリに実装し、内容をシリーズとしてまとめてみました。

目次

シリーズの内容

可能な限り毎日連載していきます。 また、順番は前後する可能性があります。

回数 内容 リンク
第0回 準備編 イマココ
第1回 Analytics ブログ
第2回 Firebase Crashlytics ブログ
第3回 Firebase Performance Monitoring ブログ
第4回 Firebase Remote Config ブログ
第5回 Firebase Authentication ブログ
第6回 Cloud Firestore ブログ
第7回 Firebase Realtime Database ブログ
第8回 Cloud Storage for Firebase ブログ
第9回 Firebase Cloud Messaging ブログ
第10回 Firebase In-App Messaging ブログ
第11回 Firebase ML ブログ
第12回 Cloud Functions for Firebase ブログ
第13回 Firebase Hosting ブログ
第14回 Firebaseのその他のサービス ブログ

開発環境

項目 内容
PC Macbook Air(M1)
Flutter 3.0.1
Firebase 11.0.1
FlutterFire 0.2.2+2

準備

まずは、カウンターアプリを作成します。

flutter create counter_firebase

Firebase CLIのセットアップが行われているものとし、必要なコマンドラインツールをインストールします。

firebase login
dart pub global activate flutterfire_cli

Firebase Consoleからプロジェクトを作成します。 このとき、Google Analyticsは有効にしてください。

アプリをFirebaseに接続します。

flutterfire configure

選択内容は以下の通り。

# プロジェクトを選択
? Select a Firebase project to configure your Flutter application with ›
❯ counterfirebase-*** (counterFirebase)

# プラットフォームの選択。全てにチェックが入っているか確認
? Which platforms should your configuration support (use arrow keys & space to select)? ›
✔ android
✔ ios
✔ macos
✔ web

# android/build.gradleの更新を行うかどうか
? The files android/build.gradle & android/app/build.gradle will be updated to apply Firebase configuration and gradle build plugins. Do you want to continue? (y/n) › yes

pubspe.yamlfirebase_coreを追加します。

dependencies:
  firebase_core: ^1.17.0

Firebaseの構成を最新のものにします。

flutterfire configure

main.dartにFirebaseのパッケージを導入し、初期化します。

import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

このとき、lib/firebase_option.dartにはAPIキーなどが記載されているので、パブリック状態のリポジトリにアップロードしないように注意してください。 (コミットする前に.gigignoreに記述するなどの対策を行う。)

コード全文

最初に作成されるカウンターアプリから以下の通り変更しています。

  • カウントアップをRiverpodで行う
  • ホームページ画面からノーマルカウンターに遷移する

main.dart

/// Flutter関係のインポート
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

/// Firebase関係のインポート
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';

/// 他ページのインポート
import 'package:counter_firebase/normal_counter_page.dart';

/// メイン
void main() async {
  /// Firebaseの初期化
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  /// runApp w/ Riverpod
  runApp(const ProviderScope(child: MyApp()));
}

/// Providerの初期化
final counterProvider = StateNotifierProvider<Counter, int>((ref) {
  return Counter();
});

class Counter extends StateNotifier<int> {
  Counter() : super(0);

  /// カウントアップ
  void increment() => state++;
}

/// MaterialAppの設定
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Counter Firebase',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class MyHomePage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('My Homepage'),
      ),
      body: ListView(
        padding: const EdgeInsets.all(10),
        children: <Widget>[
          ElevatedButton(
            child: Container(
              padding: const EdgeInsets.all(10),
              child: const Text('ノーマルカウンター'),
            ),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (context) => const NormalCounterPage()),
              );
            },
          ),
        ],
      ),
    );
  }
}

normal_counter_page.dart

/// Flutter
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

/// Other Page
import 'package:counter_firebase/main.dart';

class NormalCounterPage extends ConsumerStatefulWidget {
  const NormalCounterPage({Key? key}) : super(key: key);

  @override
  NormalCounterPageState createState() => NormalCounterPageState();
}

class NormalCounterPageState extends ConsumerState<NormalCounterPage> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final counter = ref.watch(counterProvider);

    return Scaffold(
      appBar: AppBar(
        title: const Text('Homepage'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          ref.read(counterProvider.notifier).increment();
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

GitHubのページを貼ります。

github.com

参考

firebase.google.com

flutter.dev

riverpod.dev

Google Play and the Google Play logo are trademarks of Google LLC.