Media

【Flutter入門講座 第6回】画面遷移・テスト・リリースまで。Navigatorとウィジェットテスト、App Store・Google Playへの公開準備

This page is available in Japanese only.

【Flutter入門講座 第6回】画面遷移・テスト・リリースまで。Navigatorとウィジェットテスト、App Store・Google Playへの公開準備

第 5 回で、メモアプリは API からの取得と端末への保存ができるようになりました。最終回の第 6 回は、

  • メモを書く画面を作り、一覧から移動して結果を受け取る(画面遷移)
  • ウィジェットテストで、操作を自動で確かめる
  • App Store・Google Play に公開するためのビルドと準備

を解説し、全 6 回をまとめます。

一覧の+をタップすると、メモを書く画面に移動する
この回で作る画面遷移(Web で動かした画面)

画面遷移: Navigator で移動して、結果を受け取る

Flutter の画面遷移は、画面を積み重ねるスタックです。Navigator.push で新しい画面を上に積み、Navigator.pop で取り除いて前の画面に戻ります。pop のときに値を渡すと、前の画面で受け取れます。

lib/memo_list_page.dart(抜粋)dart
Future<void> _openEditor(BuildContext context) async {
  final text = await Navigator.push<String>(
    context,
    MaterialPageRoute(builder: (_) => const MemoEditPage()),
  );
  if (text != null) store.add(text); // 戻るボタンで閉じたときは null
}

メモを書く画面

lib/memo_edit_page.dartdart
class MemoEditPage extends StatefulWidget {
  const MemoEditPage({super.key, this.initialText = ''});

  final String initialText;

  @override
  State<MemoEditPage> createState() => _MemoEditPageState();
}

class _MemoEditPageState extends State<MemoEditPage> {
  late final _controller = TextEditingController(text: widget.initialText);

  @override
  void dispose() {
    _controller.dispose(); // 使い終わったら片付ける
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('メモを書く')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: TextField(
          controller: _controller,
          autofocus: true,
          maxLength: 100,
          decoration: const InputDecoration(
            labelText: 'メモ',
            border: OutlineInputBorder(),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: () => Navigator.pop(context, _controller.text),
        icon: const Icon(Icons.check),
        label: const Text('保存'),
      ),
    );
  }
}
  • 入力中の文字は `TextEditingController` で読み書きします。画面を閉じるときは dispose で片付けます
  • late final は「最初に使うときに作る」変数です。widget.initialText を使って作れます
  • 画面がたくさんあるアプリでは、URL のように画面を指定できる go_router などのパッケージもよく使われます
Navigator のスタック。push で積み、pop で戻る

ウィジェットテスト: 操作を自動で確かめる

Flutter には、画面を実際に組み立てて、タップや入力をシミュレーションするウィジェットテストの仕組みが標準で入っています。この講座のメモアプリも、次のテストで動作を確かめています。

test/widget_test.dartdart
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
import 'package:memo_app/main.dart';
import 'package:memo_app/memo_repository.dart';
import 'package:memo_app/memo_store.dart';
import 'package:memo_app/quote_api.dart';

void main() {
  testWidgets('メモを追加して完了にできる', (tester) async {
    final store = MemoStore(InMemoryMemoRepository());
    final api = SuggestionApi(
      client: MockClient(
        (_) async => http.Response.bytes(utf8.encode('{"title":"テスト"}'), 200),
      ),
    );
    await tester.pumpWidget(MemoApp(store: store, api: api));

    expect(find.text('メモはまだありません'), findsOneWidget);

    // +ボタン → 入力 → 保存
    await tester.tap(find.byIcon(Icons.add));
    await tester.pumpAndSettle();
    await tester.enterText(find.byType(TextField), '牛乳を買う');
    await tester.tap(find.text('保存'));
    await tester.pumpAndSettle();

    expect(find.text('牛乳を買う'), findsOneWidget);
    expect(find.text('メモ(残り 1 件)'), findsOneWidget);

    // チェックを入れると残りが 0 件に
    await tester.tap(find.byType(Checkbox));
    await tester.pump();
    expect(find.text('メモ(残り 0 件)'), findsOneWidget);

    // API から候補を取得
    await tester.tap(find.byIcon(Icons.cloud_download_outlined));
    await tester.pumpAndSettle();
    expect(find.text('テスト'), findsOneWidget);
  });
}
bash
flutter test
実行結果text
00:00 +1: All tests passed!
  • 保存先は `InMemoryMemoRepository`、通信は `MockClient` に差し替えています。第 5 回で「外から渡せる」作りにしたのは、このためです
  • pump() は 1 回だけ描き直し、pumpAndSettle() は画面遷移などのアニメーションが終わるまで待ちます
  • コードを変えるたびに flutter test を実行すれば、「直したら別の場所が壊れた」をすぐに見つけられます

リリースのビルド

バージョンを決める

アプリのバージョンは pubspec.yaml の version で決めます。+ の前が利用者に見えるバージョン、後ろがストア用の通し番号(ビルド番号)です。

pubspec.yamlyaml
version: 1.0.0+1

Android: App Bundle を作る

Google Play には App Bundle(.aab) の形式で提出します。リリース版には、アップロード用の鍵で署名する必要があります。鍵は次のコマンドで作り、パスワードとともになくさないように保管します(Git には入れません)。

bash
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA \
  -keysize 2048 -validity 10000 -alias upload

鍵の情報を android/key.properties に書き、android/app/build.gradle.kts から読み込む設定をしたら、ビルドします(設定の詳しい手順は公式ドキュメントの「Build and release an Android app」にあります)。

bash
flutter build appbundle
# → build/app/outputs/bundle/release/ に .aab ファイルができる

iOS: IPA を作る

App Store に公開するには、Apple Developer Program への登録が必要です。Xcode でチームと署名を設定してから、ビルドします。

bash
flutter build ipa
# → build/ios/archive/ と build/ios/ipa/ に出力

できたファイルは、Apple の Transporter アプリや Xcode からアップロードします。

iOS の対応バージョンに注意

Flutter は iOS 13 以降に対応していますが、使う Xcode のバージョンによっては、それより新しい対応バージョン(デプロイメントターゲット)の指定が必要になることがあります。当社の環境(Xcode 27.2)では、ios/Podfile と Xcode のプロジェクトの設定を 15.0 にしてビルドが通りました。

ios/Podfile(抜粋)ruby
platform :ios, '15.0'

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
    target.build_configurations.each do |config|
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
    end
  end
end

ストアに公開するまでの準備

ビルドのほかにも、公開までにはいくつかの準備があります。

ストアに公開するまでのチェックリスト

準備

内容

開発者の登録

Apple Developer Program(年額)・Google Play Console(初回の登録料)。会社として登録する場合は、組織の確認に日数がかかることがあります

アプリのアイコン

iOS・Android の各サイズ。flutter_launcher_icons などのパッケージでまとめて作れます

ストアの掲載情報

アプリ名・説明文・スクリーンショット・カテゴリー

プライバシー

プライバシーポリシーの URL、集めるデータの申告(App Store のプライバシー情報、Google Play のデータセーフティ)

審査

内容によっては修正を求められます。ログインが必要なアプリは、審査用のアカウントを用意します

全 6 回のまとめ

  1. Flutter とは・開発環境: 1 つの Dart のコードで iOS・Android・Web などを作れる。VS Code の拡張機能と flutter doctor で準備
  2. Dart の基本: final が基本、null 安全、名前付き引数、async/await、レコードとパターン
  3. ウィジェット: すべてがウィジェット。Scaffold で骨組み、Column・Row でレイアウト、ListView で一覧
  4. 状態管理: 画面の中は setState、アプリ全体は ChangeNotifier と ListenableBuilder
  5. 通信と保存: http で API、SharedPreferencesAsync で端末に保存。保存先や通信は差し替えられる作りに
  6. 画面遷移・テスト・リリース: Navigator、ウィジェットテスト、App Bundle と IPA、ストアの準備

ここまでで、一覧・入力・保存・通信・テストという、多くのアプリに共通する基本がそろいました。次のステップとしては、ログイン(認証)、サーバー側のデータベースとの連携、プッシュ通知、画面の多いアプリでのルーティング(go_router など)や状態管理のパッケージに進むのがおすすめです。

当社では、Flutter をはじめとしたスマートフォンアプリの開発や、業務システム・Web サービスと連携するアプリの開発を承っています。「講座を読んで試作したが、本番のアプリはプロに任せたい」「既存のシステムとつなぐアプリを作りたい」といったご相談もお気軽にどうぞ。

Flutter・スマホアプリの開発を相談する

企画・設計から、開発・ストアへの公開・公開後の保守まで対応します。フォームは 24 時間受付です

Flutter 入門講座(全 6 回)

  1. Flutter とは?できることと開発環境の作り方
  2. Dart の基本文法
  3. ウィジェットで画面を作る
  4. 状態管理の第一歩
  5. API からデータを取得し、端末に保存する
  6. 画面遷移・テスト・リリースまで(この記事)

※ Flutter・Dart・Android・Google Play は Google LLC の商標です。iOS・Xcode・App Store・Apple Developer Program は Apple Inc. の商標です。

参考

Contact

Let's talk about your project.

Web, system and app development, video and more. Get in touch with us here.

Request a quoteOther inquiries
Back to Media
Contact