モバイルアプリをデバッグする

2023年4月26日

開発環境
OS:Windows 11
SDK:VS Code + flutter 3.7.5

事前準備

モバイルアプリをデバッグする場合、エミュレータか、実機を使います。

実機を使うなら、実機とPCをケーブルでつなげるだけでデバイスが自動で認識され、

デバッグできますが、エミュレータを使う場合はエミュレータ自体を事前に作成しておく必要があります。

Androidの場合だとAndroid Studioを立ち上げ、Deveice Managerでデバイスイメージを作成します。

OSバージョン、端末(スクリーンサイズ)、スペックと選択を進めれば作成できます。

エミュレータでデバッグする

エミュレータの作成が終わったらVSCodeでFlutterプロジェクトを立ち上げます。

デバッグの実行方法は2通りあります。

実行方法1)ボタン操作

まずはエミュレータを選択します。

画面下のバーにあるデバイス表示部をクリックします。

すると先ほど作成したエミュレータの一覧が表示されるようになります。

デバッグで使用したいエミュレータを選択します。

エミュレータを選択したら、デバッグを実行します。

画面左上のデバッグ起動(▷)で「Flutter(対象端末)」を選択し、クリックすればデバッグが起動します。

その2)ターミナルコマンド

まずはターミナルでデバイス一覧を表示します。

flutter device

表示された一覧から対象機種を選び、機種IDを指定してデバッグ起動コマンドを入力します。

flutter run -d (機種ID)

※ターミナルでデバッグ起動した場合はターミナルに「q」を入力して終了します。

デバッグ起動するとエミュレータ内でアプリが起動します。

実機でデバッグする

実機でデバッグする場合は実機とPCをケーブルで接続します。

実機が自動で認識されデバイス一覧に表示されます。

デバッグの起動方法はエミュレータと同様です。

ボタン操作でもターミナルコマンドでもどちらも起動できます。

起動するとスマホの画面上にアプリが表示されます。

メイン画面

今回は以上です。

Riverpodを使ってみる

2023年4月30日

開発環境
OS:Windows 11
SDK:VS Code + flutter 3.7.5

パッケージとは

Flutterで実装するうえでかかせないのがパッケージです。

Flutterのベース機能はUIに特化されているため、アプリの機能性、操作性を拡張させるような実装を行うにはパッケージをインストールする必要があります。

Webを表示させたい、画像を表示させたい、データ管理を行いたい、など、

ベースロジックで対応しきれない場合は、Pub.devから適切なパッケージを探し、インストールします。

今回は状態管理を行うパッケージ、Riverpodを利用してアプリを作ります。

パッケージをインストールする

インストール手順は簡単です。

コマンドプロンプト(ターミナル)でパッケージ(flutter_riverpod)をインストールしたい当該プロジェクトフォルダに移動し、下記コマンドを実行します。

flutter pub add flutter_riverpod

プロジェクトにパッケージがインストールされます。

パッケージはpubspec.yamlで管理されており、yamlファイル内に指定したパッケージが追加されます。

逆にpubspec.yamlにインストールしたいパッケージを追記し、下記コマンドを実行してもパッケージをインストールすることができます。

flutter pub get

実装してみる

flutter create test2で作成したサンプルプログラムをRiverpodで置き換えてみます。

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

final countProvider = StateProvider((ref) => 0);

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends ConsumerWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  void _incrementCounter(WidgetRef ref) {
    ref.read(countProvider.notifier).state++;
  }

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              ref.watch(countProvider).toString(),
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {_incrementCounter(ref);},
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

まずパッケージを使用するためにパッケージをimportします。

Riverpodを適用するためのポイントは3点です。

1)ProviderScopeで適用範囲とするクラスを指定する

2)StatefulWidget → CunsumerWidget へ置き換える

3)buildの引数にWidgetRefを追加する

あとはStateProviderを定義して参照、更新します。

値を参照する ref.read(定義名).state

値を参照する(更新検知) ref.watch(定義名).state

値を更新する ref.read(定義名.notifier).state = 更新値 

実行すると下記のようになりました。

setStateを使用したサンプルプログラムと同じ動きになります。

またRiverpodの優れた点は別ページに遷移しても変わらず参照できる点です。

下記のようにページ遷移を実装します。

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:test2/pages/nextpage.dart';

final countProvider = StateProvider((ref) => 0);

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends ConsumerWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  void _incrementCounter(WidgetRef ref) {
    ref.read(countProvider.notifier).state++;
  }

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              ref.watch(countProvider).toString(),
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            ElevatedButton(onPressed: (){Navigator.push(context, MaterialPageRoute(builder: (context) => const NextPage()));}, child: const Text('next'))
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {_incrementCounter(ref);},
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:test2/main.dart';

class NextPage extends ConsumerWidget {
  const NextPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("next page"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times on Main page:',
            ),
            Text(
              ref.watch(countProvider).toString(),
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),// This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

実行すると下記となります。

メイン画面
次画面

次ページにおいてもメイン画面の値を参照できます。

ちなみに複雑な状態管理を行うにはStateNotifierProviderを使用します。

今回は以上です。

モバイルアプリをリリースする

2023年4月8日

開発環境
OS:Windows 11
SDK:VS Code + Flutter 3.7.5

Flutterでモバイルアプリとしてビルドするのに必要な環境

Flutterはモバイルアプリ開発をメインとして使用されるフレームワークです。

Webへのデプロイもできますが、モバイルアプリとしてリリースすることも可能です。

モバイルアプリとしてリリースするためにはAndroid、iOSのビルド環境が別途必要です。

Androidアプリをビルドしたい場合はAndroid Studioを、

iOSアプリをビルドしたい場合はXcodeをインストールする必要があります。

ただし、Xcodeはmacしかインストールできないため、

Flutterの強みであるAndroid、iOSの同時リリースを行えるのはmacだけとなります。

この点においてFlutter開発をする前にPC選びを慎重に行う必要があります。

ビルドする

Androidアプリを作成するためのビルドコマンドは以下となります。

flutter build appbundle

ビルドが完了すると下記にaabファイルが生成されます。

(プロジェクトフォルダ)/build/app/outputs/bundle/release/app-release.aab

また、iOSアプリを作成するためのビルドコマンドは以下です。

flutter build ios

ビルドが完了したあとXcodeでarchiveを行い、ipaファイルを生成します。

ExportOptions.plistを用意しておくと下記コマンドでアーカイブまで実行してくれるようです。(自分は使ったことがありません。

flutter build ipa

今回は以上です。

デプロイしてインターネットで公開する

2023年4月8日

開発環境
OS:Windows 11
SDK:VS Code + flutter 3.7.5

デプロイ=サーバーに配置する

flutter runでローカル環境で動かし、デバッグが完了したらネットに公開します。

手軽にネットに公開するならFirebaseが便利です。

Firebaseにデプロイするまでの流れは以下となります。

1.Firebaseでプロジェクトを作成する

2.Firebase CLIをインストールする

3.Firebaseにログイン、初期化する

4.Firebaseプロジェクトにデプロイする

プロジェクトを作成する

Firebaseにアクセスしたらログインし、デプロイするためのプロジェクトを作成します。

お試しで使うならSparkプラン(無料版)で問題ありません。

プロジェクトを作成したら、Hostingを選択し、「始める」を押下します。

あとはFirebaseプロジェクトのナビゲーションに従います。

初期設定

初期設定としてFirebase CLIのインストール、Firebaseへのログイン、初期化があります。

すべてコマンドプロンプトでコマンド操作で行います。

Flutterプロジェクトのディレクトリに移動してコマンド入力します。

操作コマンド
CLIインストールnpm install -g firebase-tools
Firebaseログインfirebase login
Firebase初期化firebase init
Firebase初期設定コマンド一覧

デプロイする

Firebaseの初期設定が終わったあとはFlutterプロジェクトをビルドしてデプロイします。

まずはFlutterプロジェクトをビルドします。

flutter build web

ビルドが完了したらデプロイします。

firebase deploy –only hosting

これでインターネットに公開されました。

公開アドレスはFirebaseプロジェクトのHostingを選択するとドメインとして表示されます。

今回は以上です。

ページを移動する

2023年3月26日

開発環境
OS:Windows 11
SDK:VS Code + flutter 3.7.5

ページ移動=画面遷移とは

1画面にアプリの機能を全て集約すると見た目が煩雑となり、操作性が悪くなります。

そこで機能を分別し、機能ごとに画面を構成します。

そして、操作に合わせて適切な画面を表示するようことでアプリの機能が全て満たせるよう実装できるわけです。

この操作に合わせて適切な画面を表示することを画面遷移と呼びます。

画面遷移ロジック

画面遷移を行うにはNavigatorクラスを使用します。

基本的なロジックは下記となります。

Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => const (遷移先画面クラス)()),
  );

ボタンをタップする、状態が変わるなどのトリガーが発生した際に上記ロジックをコールすれば指定した画面に遷移できます。

実装してみる

テキストを表示するだけのサブ画面を作成します。

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

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: Container(
            width: double.infinity,
            height: double.infinity,
            alignment: Alignment.center,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: const [
                Text('Sub Page')
            ],)
          ),
    );
  }
}

あとはメイン画面にボタンを配置し、ボタンをタップするとサブ画面に遷移するようにします。

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        width: double.infinity,
        height: double.infinity,
        alignment: Alignment.center,
        child: Column(
          children: <Widget>[
            Expanded(
              flex: 1,
              child: Container(
                alignment: Alignment.center,
                child:Image.asset('images/sample.jpg'),),),
            Expanded(
              flex :1,
              child: Container(
                alignment: Alignment.center,
                child: ElevatedButton(
                  onPressed: () {
                    Navigator.push(
                      context, MaterialPageRoute(builder: (context) => const SubPage())
                    );
                  },
                  style: ElevatedButton.styleFrom(
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(5),
                    ),
                  ),
                  child: const Text('Next Page'),
                  ),))
          ],
        ),
      ),
    );
  }

実際にWebで実行してみると以下の通りです。

メイン画面
サブ画面

「Next Page」ボタンをタップするとサブ画面に遷移します。

Navigatorクラスには他にも幾つかのメソッドが用意されています。

メソッド挙動
push遷移前の画面を残し、遷移先画面を表示する
pushReplacement遷移前の画面を残さず、遷移先画面を表示する
pushNamed指定したルートの画面を表示する(Route登録必要)
pop画面を消去する

用途に合わせ、使い分けることができます。

今回は以上です。

Widgetを構成する

2023年3月19日

開発環境
OS:Windows 10
SDK:VS Code + flutter 3.7.5

Widgetとは

Widgetとは画面を構成するUI要素です。

Widgetを組み合わせることで画面を構築できます。

基本的なWidget一覧

基本的なレイアウト系と操作系を把握しておけば一通りの画面が作れます。

(レイアウト系)

Widget役割
Column行(縦)配置
Row列(横)配置
Expanded画面フルサイズ配置
Align指定配置
Stack重ね配置
Containerコンテナ
レイアウト系一覧

(操作系)

Widget役割
Textテキスト表示
Image画像表示
Iconアイコン表示
GestureDetector操作系コンテナ
ElevatedButtonボタン
操作系一覧

Widgetを組み合わせる

例えば画面を2等分し、画面上に画像を配置し、画面下にテキストを配置するなら

以下のようになります。

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        width: double.infinity,
        height: double.infinity,
        alignment: Alignment.center,
        child: Column(
          children: <Widget>[
            Expanded(
              flex: 1,
              child: Container(
                alignment: Alignment.center,
                child:Image.asset('images/sample.jpg'),),),
            Expanded(
              flex :1,
              child: Container(
                alignment: Alignment.center,
                child: const Text('sample', textAlign: TextAlign.center,),))
          ],
        ),
      ),
    );
  }

まず画面フルサイズのコンテナを配置します。
その中にColumnを配置して上下2分割し、Expandedで1対1になるよう画像とテキストを配置しています。

実際にWebで実行してみると以下の通りです。

Widgetの良い所はイメージ通りに組み合わせることができるところ。

更にコンテナ内にRowなどを配置し、画面構成を豊かにしていくことができます。

今回は以上です。

サンプルアプリを作成してみる

2023年2月23日

開発環境
OS:Windows 10
SDK:VS Code + flutter 3.7.5

事前準備

Flutter開発に必要なソフトウェアをインストールし、環境設定を行います。

必要なソフトウェアについてはこちらを参照してください。

コマンドライン

Flutterの基本操作をコマンドラインで行えるよう覚えておくと便利です。

コマンド動作
flutter create (プロジェクト名)プロジェクト名のフォルダが作られ、フォルダ内にサンプルプログラム一式が出力される
flutter devices実行可能なデバイス一覧が表示される
flutter run -d (デバイス名)指定したデバイスでアプリを起動する
flutter build (ビルド対象)ビルド対象に指定したアプリを生成する
ビルド対象は、apk/ios/webなど
flutter upgradeflutterを最新バージョンに更新する
flutter cleanビルド構成を消去する
flutter pub add (パッケージ名)外部パッケージを指定して取得する
flutter pug get外部パッケージを取得する
コマンドライン一覧

サンプルプログラムを作成する

まずはコマンドプロンプトを起動します。(Wndowsマーク+Rで検索窓を表示し、cmdと入力)

cdコマンドでプロジェクトを作成したい場所に移動した後、flutterコマンドを入力します。

「sample」という名のプロジェクトを作成してみます。

flutter create sample

createコマンド結果

コマンドを入力するとsampleフォルダが作成され、基本的なソースコード一式が出力されます。

sampleプロジェクト構成

これでベースとなるサンプルアプリのソースコードの完成です。

sampleフォルダに移動し、flutterコマンドを入力します。

chromeブラウザで動かしてみます。

flutter run -d chrome

runコマンド結果

カウンターアプリが起動しました。

右下の「+」をタップするとカウントアップするというシンプルなアプリです。

画面レイアウトやカウントアップなどの処理はソースコードlib/main.dartに定義されています。

基本的にFlutterアプリを作成するときは、このサンプルコードをベースにlibフォルダにdartファイルを追加していくなどしてアプリをカスタマイズしていきます。

今回は以上です。

Flutter開発環境を構築する

2023年2月23日

開発環境
OS:Windows 10
SDK:VS Code + flutter 3.3.10

Flutter開発に必要なもの

まずはFlutter開発を行うときにインストールする必要があるものを列挙します。

・Flutter

開発環境の基礎となるフレームワークです。

開発言語dartで書かれたソースコードを解析し、アプリを生成します。

Windows版インストール

MAC版インストール

・VS Code

ソースコードを書くためのエディタですが、プラグインの導入をサポートしたり、テスト実行、デバッグ、アプリ生成などがVS Code内でできます。

言わば、統合開発環境(IDE)の役割を果たします。

インストール

・Android Studio

Androidアプリを生成するときに必要となるAndroidアプリ開発環境です。

インストール

・Xcode

iOSアプリを生成するときに必要となるiOSアプリ開発環境です。

XcodeはMacでしか動作しないため、Windowsにインストールすることはできません。

インストール

作成対象と開発PC(OS)との関係を整理すると以下のようになります。

【凡例】〇:作成できる、✖:作成できない

作成対象WindowsMac補足
Webサイト特になし
AndroidアプリAndroid Studio
インストール必要
iOSアプリXcode
インストール必要
OS別対応表

FlutterでWebサイトを作るだけであれば、Flutterのみインストールすれば作成できます。

ですが、エディターとしてVS Codeを使うと開発効率が上がるのでおススメです。

スマホアプリを作成する場合は、Android Stuido、Xcodeのインストールが必要です。

また、Flutterの最大のメリットでもある1つのソースコードからAndroidアプリとiOSアプリを生成したい場合はMacで開発する必要があります。

今回は以上です。

Flutter Webをスマホ画面に適応させる

2023年2月12日

開発環境
OS:Windows 10
SDK:VS Code + flutter 3.3.10

概要

PC画面とスマホ画面、2画面分のWidgetを用意し、使い分ける

Flutter WebはPCからアクセスするとは限らない

FlutterでAndroidアプリやiOSアプリを作るならスマートフォン利用前提になるので

画面構成は基本的には縦配置のみの考慮でいいはずです。

ですが、Flutter Webの場合、ブラウザでアクセスするため、

PCとスマホ、どちらからでも利用できるよう想定しなれけばいけません。

つまり横配置を前提としてPC画面用Widget、横配置を前提としたスマホ用Wiget、

2パターンの画面構成に対応したWidgetを用意する必要があります。

PC用Widgetとスマホ用Widget

まずはPC用とスマホ用、それぞれの画面構成を作成します。

それぞれWidgetを関数化しておくと便利です。

(PC用Wigetの作成例)

  Widget _createPCView(BuildContext context)  {
    return Align(
      alignment: Alignment.topLeft,
      child: Container(
        width: 250,
        height: 200,
        margin: const EdgeInsets.all(10),
        decoration: BoxDecoration(
          color: Colors.yellow,
          border: Border.all(color: Colors.grey, width: 1),
          borderRadius: BorderRadius.circular(5.0)
        ),
        child: Column(
          children: [
           ・・・
          ],)
      ),
    );
  }

(スマホ用Widgetの作成例)

   Widget _createMobileView(BuildContext context)  {
    return Align(
      alignment: Alignment.bottomCenter,
      child: Container(
        width: double.infinity,
        height: 80,
        margin: const EdgeInsets.only(bottom: adHeight),
        decoration: BoxDecoration(
          color: Colors.yellow,
          border: Border.all(color: Colors.grey, width: 1),
          borderRadius: BorderRadius.circular(5.0)
        ),
        child: Column(
          children: [
           ・・・
          ],)
      ),
    );
  }

画面サイズでWidget使い分ける

あとは画面サイズを取得し、サイズによってWidgetを使い分けます。

画面サイズの取得には、MediaQuery.of(context).sizeを使用します。

またPCとスマートフォンの画面サイズの境界値は400とします。

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final screenSize = MediaQuery.of(context).size;
    return Scaffold(
      body: Container(
        width: double.infinity,
        height: double.infinity,
        alignment: Alignment.center,
        child: screenSize.width > screenWidth? _createPCView(context) : _createMobileView(context)
      )
    );
  }

これでPCとスマートフォンどちらにも対応できます。

実際にWeb画面をスマートフォンとPCで表示すると以下のようになります。

https://messageexchanger-fa3e1.web.app