Open16

flutter トラブルシュート 覚書

wakewake

Text がはみ出る (Overflow)

Text(
  'over flowed text',
  overflow: TextOverflow.fade, // fade, clip, etc...
);

それでも用意した領域からはみ出る

Text(
  'over flowed text',
  overflow: TextOverflow.fade,
  softWrap: false,
);
wakewake

トップページへ戻り、そこからは戻れないようにしたい

ユーザーを切り替えた時など、普通にトップページに戻ると過去のユーザーに表示していたページが残る。

Navigator.of(context).pushNamedAndRemoveUntil(
  '/home',
  (r) => false,
);

RemoveUntil系はコールバックの返り値がtrueになるまで繰り返しNavigatorに残るページを削除する。

wakewake

タブを移動するたびにページを生成をやり直したくない

ページ生成のために通信したりしていると特に。
https://qiita.com/taki4227/items/e3c7e640b7986a80b2f9

AutomaticKeepAliveClientMixinを使ったやり方がすごく楽。

class PageState extends State<Page> with AutomaticKeepAliveClientMixin { // ←追加
  
  bool get wantKeepAlive => true; // ←追加

  
  Widget build(BuildContext context) {
  super.build(context); // ←追加
  }
}

これ追加するだけ

wakewake

Firebase Analytics データが来ない

どうもデータ送信は纏めて行っている様子

  • iOSは操作したあと、iPhoneホームに戻ると送信されやすい
  • Androidは(シミュレーターのみ確認)操作したあと、シミュレーターを終了させるときに送信されやすい
wakewake

localization でのエラー

https://flutter.dev/docs/development/accessibility-and-localization/internationalization
公式docにしたがっていたものの、自動生成されるはずのapp_localizations.dartやそのディレクトリなどが生成されなかった時は

flutter gen-l10n

を実行する

その後

import 'package:flutter_gen/gen_l10n/app_localizations.dart';

の追加でdoesn't existと言われましたが、VSCodeの再起動で消えます。
ただしAppLocalizationクラス"自体"の補完は効かないみたい。

おまけ

出典元の2つ目の回答にありますが、上記を行った上であればlocalizationsDelegates:supportedLocales:はAppLocalizationが自動生成してくれるので、公式docのようにわざわざ列挙する必要はもうないみたいです。

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class MyApp extends StatelessWidget {

  
  Widget build(BuildContext context) {
    return MaterialApp(
+      localizationsDelegates: AppLocalizations.localizationsDelegates,
-      localizationsDelegates: [
-        GlobalMaterialLocalizations.delegate,
-        GlobalWidgetsLocalizations.delegate,
-        GlobalCupertinoLocalizations.delegate,
-      ],
+      supportedLocales: AppLocalizations.supportedLocales,
-      supportedLocales: [
-        const Locale('en', ''),
-        const Locale('jp', ''),
-      ],
      title: 'My app',
      home: ... ,
    );
  }
}

出典

https://stackoverflow.com/questions/65182393/why-is-flutter-not-generating-the-internationalization-files

wakewake

List<dynamic> to List<String>

Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<String>'
jsonDecode後によく困るやつ

List<dynamic> data = ["aaa", "bbb", "ccc"];
List<String> strings = data.cast<String>().toList();
wakewake

AppStoreの短縮URLが欲しい

数年前の情報が沢山出てきて、appleのマーケティング用のサイトから短縮URLが取得できるような案内が多いが、現在は提供していない様子。

bitlyでappstoreのURLを短縮しようとするとapple.co/...となります。
正規ではないんでしょうが見栄えは○

wakewake

Flutter × Firebase アナリティクスから自分を除外したい

Firebaseの作るGAでは「ビュー」が作成されない設定っぽいのでipでのフィルタリング等ができない。
なのでプログラム上でAnalyticsをdisableにする方法を取る

除外したい開発用のデバイスのIDを取得

device_info_plusを使う

Future<String> _getDeviceId() async {
  if (Platform.isIOS) {
    final info = await DeviceInfoPlugin().iosInfo;
    return (info.identifierForVendor!);
  } else {
    final info = await DeviceInfoPlugin().androidInfo;
    return (info.androidId!);
  }
}

これをprint()するなどして自分のデバイスIDを取得して、どこか参照できる場所に置いておく。

Analyticsをdisable

ハードコードを避けるために下の例ではflutter_dotenvTEST_DEVICE_IDという名前にカンマ区切りで除外したいデバイスのIDを置いている。

void main() async {
  await Firebase.initializeApp();
  final excludeIds = dotenv.env['TEST_DEVICE_ID']!.split(',');
  if (kDebugMode || excludeIds.contains(await _getDeviceId())) {
    FirebaseAnalytics().setAnalyticsCollectionEnabled(false);
  }
  runApp(MyApp());
}

本当はコード外でやりたいけどね😩

wakewake

カスタムURLスキームを設定したらAndroid側でアプリアイコンが消え開けなくなった

https://develop.hateblo.jp/entry/android-app-icon-home

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
+           </intent-filter>
+           <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="カスタムスキーム" />
            </intent-filter>

intent-filterは分けないといけない

wakewake

firebase hosting でデプロイしたapp-ads.txtが認識されない

  • Admobで見ると「robots.txtが原因でクロールできない」と言われる。
  • 「詳細」か何かのリンクを押すとどんなrobots.txtを設定すればいいか書いてある。
  • robots.txtを設置しても「robots.txtが原因でクロールできない」が変わらない
    • ブラウザやUAをクロールbotにしたcurlでアクセスしてもちゃんと取得できるのに

解決

robots.txtを設置してから5日くらい放置したら認識された。
Admobで手動更新できるけど、更新されたrobots.txtが反映されてadmobが認識するまでは時間がかかるっぽい。時間返して!

wakewake

share_plusで画像を保存しようとしたときに落ちる

OSの共有メニューを呼び出してくれるPackage: share_plus

公式の説明が不足していて設定が足りてないことに気づかずハマった。
類似Packageのshare_extendには書いてあったのでそちら参照。
以下の設定を付け足すと正常に動作する

iOS

<project root>/ios/Runner/Info.plist

<key>NSPhotoLibraryAddUsageDescription</key>
<string>describe why your app needs access to write photo library</string>

Android

<project root>/android/app/src/main/AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

READは要らない気もするが?

wakewake

String.fromEnvironmentで値が取得できない

String.fromEnvironmentconstを付けたときしか正しい動作が保証されない」と、コード内コメントでも説明されていたのに気付かなかった。

This constructor is only guaranteed to work when invoked as const. It may work as a non-constant invocation on some platforms which have access to compiler options at run-time, but most ahead-of-time compiled platforms will not have this information.

つまり、以下のようにアクセサを作って使うことが出来ない

enum EnvDef {
  flavor,
  appName,
  appIdSuffix,
  ;

  String get value => String.fromEnvironment(name);

  
  toString() => value;
}