Flutter 一人でアプリ開発日記

(2025/9/27更新)
筆者が、Flutterを用いて自分1人でアプリ開発をしている中で、日々直面した事案(エラー・不具合への対応がメインです)を日記的・備忘録的につづっています(Flutter以外の話も若干あります)。
※本ページは、「Flutter エラー・バグ日記」(2021/8/31〜2025/8/3)の後継ページです。
※文字数が多くなる内容は、別ページへのリンクで掲載しています。
単に筆者(自分)の理解不足・スキル不足による事象も多々含まれます。。
些細なことでも、もし同じ問題にぶつかった方にヒントになれば、という思いで書いています。
ライトな日記思考なので、詳細説明はしておらず、基本、テキストのみで画像とかを載せていないケースもあります。
解説記事ではないものも含まれ、解決していない内容や、その時々の間違った解釈を述べてしまっている可能性が大いにありますので、何卒、ご了承ください。
複数のFlutterアプリで「Google Playの16KB ページサイズ要件」に対応
(2025/9/27)
「Microsoft 365 Personal」を「Microsoft 365 Personal Classic」へ切替え
(2025/9/23)
アプリ開発の補助役として、役立ってくれている「Microsoft 365」ですが、料金値上げの通知が来ました。
2025 年 2 月 14 日より、サブスクリプションMicrosoft 365 Personal 料金が年額 JPY 14,900 から 年額 JPY 21,300 に値上げされます
との事で、2月以降、更新のタイミングで値上げが決まっていたようです。
6,000円近くの値上げはキツイけど仕方ないか、、、と諦めかけていた中、試しに調べてみたところ、下記のような情報が、多く見つかりました(有益な情報を上げてくださり、大変助かりますm(_ _)m)。
実は、AIの「Copilot」を搭載したことによる値上げであり、AI(Copilot)が不要なら、値段据え置きの「Classic版」に切替可能という事です。
早速、プランの切替をしようとしましたが、まだ過渡期のためか、ネット上の情報も様々で、単純には切替できず、苦労しました。。。
そもそも、Microsoftアカウントの「サブスクリプションの管理」画面には、
- プランの切り替え
- 定期請求を無効にする
- サブスクリプションのキャンセル
という3つの似通った項目(ボタン)があり、混乱しました。。
てっきり「プランの切り替え」から手続するのかと思いきや、ここでは、月払いか年払いかの変更しかできません。。
調べると、多くのネット上の情報(例えばこちら)では、「サブスクリプションのキャンセル」から切替手続きできる、と書かれていましたが、自分の場合は、「サブスクリプションのキャンセル」を押しても、しばらく画面が読込状態になった後、また同じ画面に戻ってしまい、手続きできませんでした。
結局、筆者(自分)のケースでは、「定期請求を無効にする」から、Classicプランへの切替画面に遷移できました。
※下記情報が筆者のケースに合致していたので、大変助かりましたm(_ _)m。
以上で、なんとか無事、「Microsoft 365 Personal Classic」への切替を完了できました。
間違って「Microsoft 365 Personal」を完全解約してしまうと、Classicプランへの切替はできないそうなので、ヒヤヒヤしました。
Autocompleteで候補リストを入力欄の下方ではなく、上方に表示させたい
(2025/9/5)
「TextField」や「TextFormField」に、入力候補を表示してくれる「Autocomplete」は、とても便利、かつ外部パッケージではなく、Flutter標準のクラスなので、よく使っています。
しかし、テキスト入力欄が画面下部にある場合を想定し、候補表示を、入力欄の下方ではなく上方に表示させようとしたところ、思いのほか、苦労しました。
まず調べたところ、下記スレッドに情報があり、「optionsViewOpenDirection」というプロパティに、「OptionsViewOpenDirection.up」を設定すれば良いと分かりました。
しかし、これを設定すると、なぜか候補が表示されなくなりました。。
Chat-GPTに尋ねると、「optionsViewOpenDirection」プロパティは使用せず、「optionsViewBuilder」プロパティに設定している「ListView」を、
「FractionalTranslation(translation: const Offset(0, -1.0),・・・)」でラップして、表示位置を上にズラすと良い、と提案されました。
やってみると、確かに上にズレて表示できるものの、候補表示を触っても、スクロールや選択ができません。
どうやらこの方法だと、タッチ判定の位置が上にズレてくれないようです。
その後、試行錯誤しましたが、結論としては、
- 候補表示の「ListView」を「Align」でラップし、
- 「alignment」プロパティを「Alignment.bottomLeft」 ※Alignment.bottomCenterやAlignment.bottomRightでも可
にすれば、上方に表示できました。
元々、「Align」でラップしていましたが、「Alignment.topLeft」にしてしまっていたのが、不具合の要因でした。
色々試して分かったのですが、例えば、入力欄が画面最下部にあり、キーボード非表示の状態にすると、「Alignment.topLeft」(「topRight」や「topCenter」も同じ)では、画面の上端に候補が表示され、「Alignment.centerLeft」にすると、画面の中央あたりに候補が表示されました。
キーボードが表示されたり、入力欄を画面中央に置いたりすれば、更に全体が上にズレるので、「Alignment.topLeft」や「Alignment.centerLeft」にすると、候補リストが画面から見えない位置に飛んでしまう、という事のようです。
ご参考に、DartPad上で試せるAutocomplete上方表示のコード例を掲載します(クリックすると開きます)。
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ Autocomplete<String>( optionsViewOpenDirection: OptionsViewOpenDirection.up, optionsBuilder: (TextEditingValue textEditingValue) { if (textEditingValue.text == '') { return const Iterable<String>.empty(); } return ['apple', 'banana', 'cherry'] .where((String option) { return option.contains(textEditingValue.text.toLowerCase()); }); }, fieldViewBuilder: (BuildContext context, TextEditingController textEditingController, FocusNode focusNode, VoidCallback onFieldSubmitted) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), child: TextField( controller: textEditingController, focusNode: focusNode, decoration: const InputDecoration( border: OutlineInputBorder(), labelText: 'フルーツを入力', ), ), ); }, optionsViewBuilder: (BuildContext context, AutocompleteOnSelected<String> onSelected, Iterable<String> options) { return Align( alignment: Alignment.bottomLeft, // ←これが重要:リストを上方向に展開 child: Material( elevation: 4.0, child: SizedBox( height: 200.0, child: ListView.builder( itemCount: options.length, itemBuilder: (BuildContext context, int index) { final String option = options.elementAt(index); return ListTile( title: Text(option), onTap: () { onSelected(option); }, ); }, ), ), ), ); }, ), const SizedBox(height: 50.0), ], ), ), ), ); } }
App Store Connectで、何度も「契約の更新」ダイアログが出て先に進めない
(2025/8/27)
「iOSアプリ」右側の「+」ボタンから新規バージョンを作成しようとすると、今まで見たことがない
「契約の更新」
という、文章が何も書かれていないダイアログが表示されました。
ダイアログ右下には、「OK」(記憶が不確かで、、「キャンセル」だったかもしれません。。)というボタンのみがあり、押してもダイアログが消えるだけで、また新規バージョン作成ボタンを押すと、同じダイアログが表示される状況に。。
何度やっても同じで、新規バージョンが作成できなくなってしまいました。
Apple Developerの契約は更新済なので、おかしいと思いましたが、試しにブラウザで、現状のApp Store Connectの画面を再読込みしてみたところ、「契約の更新」のダイアログが表示されなくなり、無事、新規バージョンが作成できるようになりました。
「何だったのだろう...」と思い、ネット上を調べると、自分の状況に近い記事を上げてくださっていました。
こちらの情報によると、契約内容の確認をすれば解消されたようですが、自分の場合は、契約情報は既に「有効」となっており、クリックもできない状態だったので、やや状況が異なっているようです。
ともかく解決したので良かったですが、文章も何も無いダイアログが、何度も表示されたのには戸惑いました。
iOSシミュレーターで画面遷移時にアプリがフリーズ
(2025/8/25)
iOSシミュレーターで、アプリのテストをしていたら、突然、特定の画面に遷移する所で、アプリがフリーズする状況になりました。
Xcodeのデバッグウィンドウには、エラーログは見られず、理由がわかりません。。。
いったんアプリを強制終了・再起動しようとすると、macの画面上に、エラーを知らせるウィンドウが表示されたので、とりあえずログを保存。
その後、アプリを再起動しても、やはり同じところでフリーズ。
さらに、アプリを一旦アンインストールし、再ビルドしても、やはり同じところでフリーズしました。
そこで、先ほど保存したエラーログを覗いてみると、膨大な量に唖然。。
そこで、そのままChat-GPTに読んでもらったところ、下記のような回答でした(長いので、一部抜粋)。
クラッシュしたスレッドは com.apple.UIKit.pasteboard.cache-queue で、スタックには FlutterPlatformPlugin clipboardHasStrings(クリップボード有無確認) が載っています。アプリ終了・バックグラウンド遷移中に UIPasteboard への同期的問い合わせ が発生し、応答待ちでハング→Watchdog が Kill、という筋書きが濃厚です。
(iOS では Pasteboard 同期が切れている/許可待ち等の状態で、同期呼び出しが詰まると起きやすい既知パターンです。)
・・・(中略)・・・
画面に TextField 等があり、Flutter エンジンが貼り付け可否のために clipboardHasStrings を照会→ちょうど バックグラウンド遷移や終了処理 と競合。
・・・(以下略)・・・
なるほど、、、確かに遷移先の画面にはTextFieldがあり、画面遷移時に、クリップボードに特定の文字列を保持する処理を行っていました。
そこで、テキスト入力全般がおかしくなっているのでは?と思い、試しに、シミュレーターにプリインストールされているApple純正の「リマインダー」を起動すると、やはりテキスト入力画面に行く所でフリーズしました。
ここでようやく、シミュレーター自体の問題だと気づき、「Device」→「Restart」でシミュレーターを再起動すると、無事、フリーズ現象は解消されました。
自分で、あの膨大なログを見ていたら、とても気付けなかったと思うので、やはりChat-GPTに読んでもらえるのは、大変ありがたいです。
Google Playからのインストールで内部テスト版からリリース版に戻したい
(2025/8/15)
アプリの更新版をリリースする際は、更新前に保持していたデータが壊れないかを確認したい所です。
しかし、一度、Google Play Consoleから内部テスト版をテスターアカウントに配信してしまうと、Google Play上でリリース版に戻せないので、いつも困っていました。
発生していた問題
内部テスト版を配信すると、Google Playのアプリページには「(内部用ベータ版)」と表示され、内部テスト版しかインストールできません。
別のGoogleアカウントでログインしても、同じデバイスを使っている場合は、同様に内部テスト版が表示されてしまいます。。
※まれにリリース版を表示できることもありますが、再現できません。。
Google公式ヘルプ(アプリのベータ版プログラムの登録を解除する)では、[アプリとデバイスの管理] → [ベータ版] から解除できると案内されていますが、筆者の端末では「ベータ版」という項目が表示されませんでした。
テスター登録を一時的に解除する方法もありますが、反映に時間がかかり、再度内部テストを行う際には再登録が必要になるため、手間がかかります。
また、開発環境から直接端末に旧バージョンをインストールする方法もありますが、Google Play経由の環境とは厳密に異なります(あくまで、Google Playからインストールした環境で、更新前後の挙動を確認したく...)。
解決方法:アカウントを一時的にログアウトする
試行錯誤(AIへの相談やネット調査)の結果、最も手軽だったのが「デバイスから一時的にテスターアカウントをログアウトする」方法でした。
手順は以下の通りです。
- Android端末の 設定 を開く
- パスワードとアカウント を選択
- 対象のGoogleアカウントを選択
- アカウントを削除 を実行
これで、Google Playを開くと「(内部用ベータ版)」は表示されなくなりました。即時反映されるため、待つ必要もありません。
内部テストを再開したい場合は、同じく「パスワードとアカウント」から削除したアカウントを追加すれば、すぐにテスター状態に復帰できました。
(他にもっと良い方法があるかもしれませんが、筆者にとってはこの方法が最も手軽でした。)
speech_to_textで日本語が英字で認識されてしまう
(2025/8/13)
リリースしたアプリ(全てFlutterで開発)
個人アプリ開発で役立ったもの
おすすめの学習教材
\超初心者向けでオススメな元Udemyの講座/
\キャンペーン時を狙えば安価で網羅的な内容が学べる(日本語訳あり)/
\Gitの基礎について無料で学べる/
おすすめの学習書籍
\実用的。image_pickerに関してかなり助けられた/
\Dartの基礎文法を素早くインプットできる/