Flutterバックエンド構築のステップバイステップガイド

Step-by-step guide to build a Flutter backend
Step-by-step guide to build a Flutter backend

この記事では、Googleによって作られたオープンソースのUIソフトウェア開発キットであるFlutterについて説明する。

Flutterを使うメリットとデメリットを探り、Flutterアプリのためのさまざまなバックエンドオプションを紹介する。

最後に、Back4appsのBaaS(Backend as a Service)機能を使って、Flutterアプリのバックエンドを構築する方法を学びます。

Flutterとは何か?

Flutterは、Android、iOS、Web、Linux、macOS、Windowsのネイティブなアプリケーションを素早く構築できるクロスプラットフォーム開発フレームワークです。

Flutterを使えば、プラットフォーム固有のアプリケーションを構築する複雑な作業の多くがバイパスされることがわかるだろう。Flutterは高速なパフォーマンスと美しいUIウィジェットでも知られている。

Flutterチーム自身は、この技術を次のように定義している;

Googleによるオープンソースのフレームワークで、単一のコードベースからネイティブにコンパイルされた美しいマルチプラットフォームアプリケーションを構築できる。

Flutterの利点と限界トップ3

メリット制限事項
Flutterは、アプリの開発期間を短縮するための、すぐに使える幅広い機能を備えた高速フレームワークです。Flutterアプリは、React Nativeなどの他のフレームワークで作られたアプリよりも大きくなる傾向がある。
FlutterアプリはAndroidとiOSの両方で動作するクロスプラットフォームなので、開発の時間とコストを節約できます。Flutterは比較的新しいフレームワークで、コミュニティも比較的小さい。そのため、必要なときにヘルプやサポートを見つけるのは難しいかもしれない。
Flutterは初心者でも簡単に学べる。始めるための素晴らしいドキュメントがある。Flutterは、JavaやJavaScriptのような他の言語ほど広く知られていないDartプログラミング言語を使用しています。そのため、利用できるパッケージが限定されるかもしれない。

バックエンドのタイプとは?

サーバーサイドのタスクを処理する適切なバックエンドオプションを選択することは、アプリケーションを構築する上で非常に重要です。

どのタイプのバックエンドにも長所があり、アプリケーションの特定のニーズがバックエンドの選択の指針になるはずです。

以下のサブセクションでは、バックエンドのさまざまなオプションについて、その内容、仕組み、そしてアプリケーションのニーズに最適な方法について説明します。

IaaS

IaaSは、多くのユーザーを抱える大規模なアプリケーションを扱う場合、採用を検討すべきバックエンドオプションだ。IaaSとは、Infrastructure as a Serviceの略で、クラウド・コンピューティング・モデルの一つである。

クラウド・コンピューティングとは、サーバー、ストレージ、アプリケーションなどのコンピューティング・リソースを、サードパーティのプロバイダーがインターネット経由で提供するモデルである。

これらのリソースはオンデマンドでアクセスでき、従量課金制です。IaaSでは、クラウド・プロバイダーが主要な基礎となるコンピューティング・インフラストラクチャを維持し、お客様はアプリケーションのデータ、オペレーティング・システム、その他すべてのバックエンド要件を構成するための完全な制御を行うことができます。

このため、コンピューティングリソースの増減によるスケーリングが必要なアプリケーションのバックエンドオプションとして適している。

PaaS

Platform-as-a-Service(PaaS)とInfrastructure-as-a-Service(IaaS)は、異なる目的を持つ2つの異なるクラウド・コンピューティング・モデルである。どちらも柔軟性とスケーラビリティを提供する一方で、アプリケーションの開発とデプロイメントにおける異なるニーズに対応している。

PaaSバックエンドは、サーバー、ネットワーク、ストレージの複雑な管理を抽象化し、完全な開発環境を提供します。PaaSは、インフラ管理を気にすることなく、アプリケーションの構築と保守に集中したい場合に最適です。

バース

BaaS(Backend-as-a-Service)バックエンドは、すぐに使えるバックエンド・サービスと機能を提供するため、バックエンド・インフラを管理することなく、アプリケーションのユーザー・エクスペリエンスの構築と強化に集中することができます。

BaaSを使えば、開発者はAPIを通じてユーザー認証、データベース、ストレージなどの機能にアクセスすることができ、バックエンドサーバーのセットアップやメンテナンスが不要になる。

アプリに完璧にフィットする既成のパズルのピースを使うようなもので、時間と労力を節約できる。

要するに、BaaSは開発プロセスを簡素化し、開発者はアプリケーションのユーザーと接する側面に集中できる一方、重い仕事を処理するためにあらかじめ構築されたバックエンド・サービスに頼ることができる。

Backend as a Serviceを使ってFlutterバックエンドを構築する方法

このセクションでは、Flutterアプリケーションのバックエンドの構築を始める方法について説明します。Back4appプラットフォームは、スケーラブルでセキュアなバックエンドアプリケーションを構築するのに最適なオプションで、柔軟でデプロイも簡単です。

Back4appの概要

Back4AppはBaaS(Backend-as-a-Service)プラットフォームであり、完全なバックエンドインフラストラクチャを提供することで、モバイルおよびWebアプリケーション開発を簡素化します。

Back4Appを使えば、アプリケーションのフロントエンド機能の構築に集中することができます。

このプラットフォームは、データベース、API、クラウド機能など、すぐに使える幅広いバックエンド・サービスを提供している。

Back4appの主な特徴/利点は以下の通り:

  • リレーショナル・データベースとノンリレーショナル・データベース
  • RESTおよびGraphQL API
  • ライブクエリ
  • 幅広い認証オプション
  • スケーラブルなホスティング
  • プッシュ通知とEメール通知

Back4Appは、アプリのサーバーサイドコンポーネントを開発するためのオープンソースキットであるParseサーバーを使用しています。複数のテクノロジーをサポートこのリファレンスガイドでは、Back4Appがサポートしている様々なテクノロジーをリストアップしています。

プロジェクト紹介

このガイドの目的は、FlutterアプリケーションをサポートするBack4appバックエンドを構築することです。アプリケーションはParseサーバーSDKを使ってセットアップされたバックエンドに接続し、やり取りします。

あなたが作成するアプリケーションは、ユーザーが連絡先を作成したり読んだりできるシンプルな連絡先アプリです。これらの連絡先は、Back4appのPostgreSQLデータベースを使用して保存されます。

ユーザーはアプリに連絡先の情報を入力することで、新しい連絡先を追加できる。

このガイドが終わるころには、あなたはその方法をしっかりと理解していることだろう:

  • Back4appプラットフォームでバックエンドアプリケーションを構築する
  • 構造化されたBack4appデータベースに書き込む
  • Parseのバックエンドセキュリティの基本を扱う。

前提条件

このガイドに従うには、以下の前提条件を満たす必要がある:

  • Dart言語とFlutterフレームワークに精通していること
  • Flutterでステートを操作する知識
  • アプリを実行するためのデバイス・シミュレータまたはエミュレータ。iOSならXcode、AndroidならAndroid Studio。
  • リレーショナル・データベースと非リレーショナル・データベースの基本的な理解

アプリ作成

バックエンドを作成するにはBack4appのアカウントが必要です。アカウントをお持ちでない場合は、無料の アカウントに サインアップしてください。

すでにBack4appのアカウントを持っている場合は、ログインして新しいアプリを作成してください。サービスオプションとしてBackend as a Serviceを選択してください。

back4appの新規アプリ作成オプションの種類

これでスケーラブルなBaaSバックエンドが構築される。アプリにユニークな名前をつけることをお忘れなく。データベースのオプションとして、Back4appはPostgreSQLを提供しています。

PostgreSQLは、人気のあるオープンソースのリレーショナルデータベース管理システム(RDBMS)です。スケーラビリティ、信頼性、高いパフォーマンス、セキュリティで知られています。

Back4appのベータ版PostgreSQLオプションを使用すると、これらの機能と利点を利用することができます。

アプリ名とSQLデータベースオプションで新規アプリ作成モーダル

ビルドの段階はすぐに終わるはずです。ビルドが終わると、アプリケーションのダッシュボードに移動します。

PostgreSQLデータベース

Back4Appでは、アプリのデータを表すクラスやフィールドを定義することができます。PostgreSQLはリレーショナルデータベースを使用し、ユーザーのデータを構造化して保存します。

前述したように、私たちのFlutterアプリは複数の連絡先を保存できる連絡帳になる。PostgreSQLデータベースはリレーションを保持する。このアプリの妥当なデータモデルは、連絡先クラスと連絡先の都市ZipCodeだろう。

Contactモデルから始めましょう。連絡先テーブルにはさまざまなフィールドが必要です;

  • コンタクトID/オブジェクトID
  • 名称
  • 電話番号
  • 郵便番号

データモデル・テーブルは次のようになる;

連絡先

フィールドデータタイプ制約条件
コンタクトIDINTEGERPRIMARY KEY
名称ストリングNOT NULL
電話番号INTEGERNOT NULL
郵便番号ポインターNOT NULL

郵便番号

フィールドデータタイプ制約条件
オブジェクトIDINTEGERPRIMARY KEY
郵便番号INTEGERNOT NULL

Contact オブジェクトは、contactIdを主キーとして、連絡先情報を格納します。namephoneNumberzipCodeフィールドは必須項目です (NOT NULL)、

このデータモデルは、連絡先アプリのテーブル間のリレーションを作成し、連絡先情報を管理し、各連絡先に複数のフィールドを関連付けることを可能にします。

Back4appアプリでこの2つのクラスを作成するには、ダッシュボードの左上にある「クラスを作成」ボタンを押してください。

アプリのダッシュボードにクラスボタンを作成する

クラス名を「Contact」とし、「必須項目ですか」オプションを「On」に切り替えます。

新しいカラムモーダルの作成と追加

Contactのデータフィールドのカラムを作成し、ZipCodeクラスも同様に作成します。Back4appでは、作成した各カラムをカスタマイズすることができます。

管理パネル

Back4Appは、管理パネルと呼ばれる直感的なGUI(グラフィカル・ユーザー・インターフェイス)を提供し、アプリケーションのバックエンドを簡単に管理できます。

管理者パネルは、データを監視、編集、分析するための強力なツールであり、アプリ管理のための貴重な資産です。

アプリの管理パネルには、アプリ内でアクセスできます。アプリのダッシュボードの “More“の下に“Admin Panel“というボタンまたはリンクがあります。そこで管理アプリのオンとオフを切り替えることができます。

管理アプリにアクセスするためのユーザー名とパスワードを入力します。

管理アプリを設定する最後のステップは、パネルへのアクセスに使用するドメイン名を選択することです。

このガイドでは、flutter-backend.admin.back4app.comを例にしている。

提供されたドメインをブラウザで開くと、管理ダッシュボードにログインできるようになります。

Back4app Admin Appの詳細については、公式ドキュメントをご覧ください。

アプリのセキュリティ

現在、あなたのバックエンドアプリは完全に脆弱であり、その中の情報はクライアント側から改ざんされる可能性がある。

本番段階でこれを防ぐには、規制とアクセス許可を設定すればよい。

クラスがどのように作成されるかを制御し、クライアント側からのクラス作成を許可しないようにするには、ダッシュボード>アプリ設定に移動し、クライアント・クラス作成の場所を見つけます。アプリは現在、作成した2つのクラスしか必要としないため、このオプションをオフに切り替えます。

オフに切り替えるとポップアップが表示されます。これはアプリの変更を確認し、保存するためのものです。

クライアント・クラス作成認証のトグル・スイッチ

FlutterでCRUD APIをテストする

このセクションでは、あなたのアプリのバックエンドAPI関数とデータベースを、あなたが構築するFlutterアプリケーションでテストします。Flutterアプリケーションのユーザーインターフェイスを構築するところから始めます。

Flutterアプリを初期化するには、Flutter SDKをコンピュータにインストールする必要があります。

Flutterの公式Get Started Docsに従って、Flutter SDKとFlutterアプリケーションのビルドに必要なツールをWindowsまたはMacマシンにインストールしよう。

Flutterアプリケーションを初期化するには、ターミナルで以下のコマンドを実行する:

#Initialize your Flutter app
flutter create my_flutter_app

#Run your Flutter app
flutter run

これらのコマンドは、簡単なFlutterアプリケーションを構築するための足場となり、起動する。

このガイドをシンプルにするために、main.dartファイルにはFlutterアプリケーションを実行するためのコードのほとんどが含まれている。このガイドの目的ではないので、ここではFlutterのコードについては触れない。

main.dartのコードをすべて以下のように書き換える:

import 'dart:ffi';

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final keyApplicationId = 'appID';
  final keyClientKey = 'clientKey';
  final keyParseServerUrl = '<https://parseapi.back4app.com>';

  await Parse().initialize(keyApplicationId, keyParseServerUrl,
      clientKey: keyClientKey, debug: true);

  runApp(MaterialApp(
    title: 'Contacts',
    theme: ThemeData(
      primaryColor: Colors.white,
    ),
    home: ContactsApp(),
  ));
}

class ContactsApp extends StatefulWidget {
  const ContactsApp({Key? key}) : super(key: key);

  @override
  // ignore: library_private_types_in_public_api
  _ContactsAppState createState() => _ContactsAppState();
}

class _ContactsAppState extends State<ContactsApp> {
  List<Contact> contacts = [];
  String? selectedZipCode; // Initialize with a default value

  @override
  void initState() {
    super.initState();
    selectedZipCode = '1234'; // Initialize with a default value
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Contacts'),
      ),
      body: ListView.builder(
        itemCount: contacts.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(contacts[index].name),
            subtitle: Text(contacts[index].phoneNumber),
            trailing: IconButton(
              icon: const Icon(Icons.delete),
              onPressed: () {
                setState(() {
                  contacts.removeAt(index);
                });
              },
            ),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _showAddContactDialog();
        },
        child: const Icon(Icons.add),
      ),
    );
  }

  void _showAddContactDialog() async {
    showDialog(
      context: context,
      builder: (context) {
        String name = '';
        String phoneNumber = '';

        return AlertDialog(
          title: const Text('Add Contact'),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              TextField(
                decoration: const InputDecoration(labelText: 'Name'),
                onChanged: (value) {
                  name = value;
                },
              ),
              TextField(
                decoration: const InputDecoration(labelText: 'Phone Number'),
                onChanged: (value) {
                  phoneNumber = value;
                },
              ),
              // Checkbox for Zip Code
              ListTile(
                title: const Text('Select Zip Code'),
                subtitle: Column(
                  children: [
                    RadioListTile(
                      title: const Text('1234'),
                      value: '1234',
                      groupValue: selectedZipCode,
                      onChanged: (value) {
                        setState(() {
                          selectedZipCode = value;
                        });
                        print(selectedZipCode);
                      },
                    ),
                    RadioListTile(
                      title: const Text('4321'),
                      value: '4321',
                      groupValue: selectedZipCode,
                      onChanged: (value) {
                        setState(() {
                          selectedZipCode = value;
                        });
                        print(selectedZipCode);
                      },
                    ),
                  ],
                ),
              ),
            ],
          ),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: const Text('Cancel'),
            ),
            ElevatedButton(
              onPressed: () async {
                setState(() {
                  contacts.add(Contact(
                    name: name,
                    phoneNumber: phoneNumber,
                    zipCode: selectedZipCode as String,
                  ));
                });

                // Save the contact to Back4App
                final contact = ParseObject('Contact');
                contact.set('name', name);
                contact.set('phoneNumber', phoneNumber);
                contact.set(
                    'zipCode',
                    (ParseObject('ZipCode')..objectId = selectedZipCode.objectId)
                        .toPointer());

                await contact.save();

                // ignore: use_build_context_synchronously
                Navigator.of(context).pop();
              },
              child: const Text('Save'),
            ),
          ],
        );
      },
    );
  }
}

class Contact {
  final String name;
  final String phoneNumber;
  final String zipCode;

  Contact({
    required this.name,
    required this.phoneNumber,
    required this.zipCode,
  });
}

class ZipCode {
  final String zipCode;

  ZipCode({
    required this.zipCode,
  });
}

これでFlutterアプリの基本的なUIが使えるようになる。

これでBack4appの実装を開始できます。Back4appはParse Flutter SDKを使って、FlutterアプリケーションにParse Serverを統合します。

Parse Serverはオープンソースのバックエンドプラットフォームで、アプリデータを管理するためのすぐに使えるインフラを提供します。

SDKを使えば、FlutterアプリからParse Server APIと通信することができ、データのCRUD操作(Create、Read、Update、Delete)やユーザーセッションの管理、その他のサーバーサイドの機能処理を簡単に行うことができます。

Parse SDKを使うには、Flutterプロジェクトのpubspec.yamlファイルに依存関係としてインストールしてください。

Parseサーバーを指定します:

dependencies:
	# Parse SDK
  parse_server_sdk_flutter: ^5.1.1

  flutter:
    sdk: flutter

インデントが正確であることを確認してください。.yamlファイルは大文字と小文字の区別とインデントに非常に敏感です。

指定された依存関係をインストールするコマンドを実行する:

flutter pub get

main.dartに移動し、追加したParse SDKをインポートします:

import 'package:parse_server_sdk_flutter/parse_server_sdk_flutter.dart';

void main() async{
  WidgetsFlutterBinding.ensureInitialized();
	// code for runApp()

  const keyApplicationId = 'YOUR_APPLICATION_ID_HERE';
  const keyClientKey = 'YOUR_CLIENT_KEY_HERE';
  const keyParseServerUrl = '<https://parseapi.back4app.com>';

  await Parse().initialize(keyApplicationId, keyParseServerUrl,
      clientKey: keyClientKey, debug: true);
}

ここで、main.dartファイルに ParseSDk をインポートします。また、main()内で Parse().initialize() を呼び出して Parse を初期化します。これは非同期プログラムなので、main() にasync キーワードを付けます。

Application_IdClient Keyのプレースホルダは、実際の値に置き換える必要があります。これらはバックエンドと通信するためのアプリケーション認証情報です。

これらのキーを取得するには、Back4appのダッシュボードからApp Settings>Security & Keysに移動してください。そしてプレースホルダーをそれぞれのキーに置き換えてください。

アプリを実行すると、main()が実行され、Parseがアプリで初期化され、FlutterアプリがBack4appバックエンドに接続されます。

ContactおよびZipCodeクラスへの書き込み

ここでは、アプリのクライアント側からデータベース内のクラスを作成し、書き込む方法を学びます。ContactクラスとBirthdayクラスを作成するために、main.dart.Contact()を修正します。

昇格ボタン・ウィジェットのonPressed()メソッドの内部で、ParseObject()を使用してContacts クラスの新しいインスタンスを作成します:

final contact = ParseObject('Contact');
contact.set('name', name);
contact.set('phoneNumber', phoneNumber);

final ParseResponse parseResponse = await contact.save();

if (parseResponse.success) {
   final contactId = (parseResponse.results!.first as ParseObject).objectId!;
		print('Object created: $contactId');

	} else {
      print('Object created with failed: ${parseResponse.error.toString()}');
    }

Parse Flutter SDKはParseObject()を使って、引数として渡したクラス名の新しいインスタンスを作成する。オブジェクトフィールドの名前とその値を指定してContact.set()を呼び出すと、それらのフィールドが書き込まれ、更新されます。

保存操作の結果を保持するためにParseResponseオブジェクトを作成できます。ParseResponseにはsuccessプロパティが含まれ、保存操作が成功した場合はtrue、失敗した場合はfalseとなります。

次に、contactIdという変数をnullに初期化します。この変数は、保存されたコンタクト・オブジェクトの自動生成されたobjectIdを格納するために使用されます。続いて、エラー処理を行います。

上記のコードの下に

final zipCodeObject = ParseObject('ZipCode')
    ..objectId = selectedZipCode as String;
zipCodeObject.set('zipCode', selectedZipCode);
contact.set('zipCode', zipCodeObject.toPointer());

await contact.save();
await zipCodeObject.save();

ここでは郵便番号の ParseObject を作成します。ダイアログを通して新しいコンタクトを追加するとき、このコードは適切にZipCodeオブジェクトを作成し、ContactオブジェクトのzipCodeフィールドに関連付けます。

選択された郵便番号のobjectIdを使用して、ポインタとしての関連付けを確立します。.save()メソッドを使用して、両方のオブジェクトをバックエンドに保存します。

データベースからのデータの照会/読み込み

ここでは、Flutterアプリからデータベースにクエリを送信する方法について説明します。同じ郵便番号を持つすべての連絡先を検索するクエリを作ることができる。非リレーショナルデータベースシステムでこれを実現するのはかなり複雑だろう。

検索に成功すると、Flutterアプリ内のすべての連絡先のリストを表示できます。

同じ郵便番号を持つ連絡先のリストを取得する:

Future<void> _loadContacts() async {
  final queryBuilder = QueryBuilder<ParseObject>(ParseObject('Contact'))
    ..whereEqualTo('zipCode', selectedZipCode) // Filter by zip code
    ..orderByAscending('name');

  final response = await queryBuilder.query();

  if (response.success && response.results != null) {
    final List<Contact> loadedContacts = response.results!.map((parseObject) {
      return Contact(
        name: parseObject.get('name'),
        phoneNumber: parseObject.get('phoneNumber'),
        zipCode: parseObject.get('zipCode')!.objectId,
      );
    }).toList();

    setState(() {
      //set your contacts to loadedContacts
    });
  }
}

@override
  void initState() {
    super.initState();
   
    _loadContacts(); // Load contacts when the app starts
  }

loadContactsメソッドは、Contactsクラスへのクエリーを構築し、指定された郵便番号を持つコンタクトオブジェクトを探します。

このメソッドは、’name’ フィールドに基づいた昇順で名前順に並べながら、連絡先をリストに返します。

アプリが起動すると(initState)、_loadContactsメソッドが呼び出され、選択した郵便番号の連絡先が取得されます。

結論

アプリ内のデータフローを適切に構造化できる管理されたバックエンドを持つことは絶対に必要です。Back4appを使えば、モバイルアプリケーションのバックエンドを外出先でも構築できます。

また、Back4appプラットフォームを使用して、設定されたユーザーモデルデータベースを使用してユーザー認証を実装することもできます。

Flutterとは?

Flutterは、ネイティブのようなアプリを複数のプラットフォームで作成できる開発フレームワークです。プラットフォームごとのアプリ構築を簡素化し、開発スピードの速さと美しいUIで知られています。

バックエンドのデプロイ方法は?

IaaS
PaaS
– BaaS

Flutterアプリのバックエンドを構築するには?

1. アプリ用のデータベースデータモデル構造を計画する
2. その構造を反映するデータベースを設定する
3. UIのロジックを書き、バックエンドに接続する
4. セキュリティの脆弱性をテストし、CRUD操作を行う
5. Back4appのようなデプロイプラットフォームを選ぶ
6. アプリをバックエンドにデプロイする


Leave a reply

Your email address will not be published.