見出し画像

Flutterを使ってみた感想

こんにちは、インです。グロービスで学習サービスを作っているエンジニアです。1年ぐらいFlutterを使ってきたので、その感想、起こりやすいミスや解決Tipsなどをまとめました。

使ってみた感想

生産性が高い

  • 静的型付け言語Dartで開発するので、リファクタリングする時やlibrary、frameworkの内部実装を確認する時に非常に効率的です。もちろん、強力な型推論があるので、毎回、型を明示的に宣言する必要がありません。

  • Hot reload、Hot restart機能があるので、書いたコードが直ぐ画面で反映できます。

  • 豊富なWidgetがあるので、自分でUIを実装する時間を節約できます。

学習コストが低い

  • Dartの文法がシンプルでわかりやすいので、プログラミング経験があれば、一日ぐらいで勉強できます。

  • 公式サイトにドキュメントが充実しています。

  • この一年でflutterに関する記事が爆発的なスピードで出てきて、トラブルシューティングも楽です。

楽しい

ユーザーが使う機能を効率的に開発でき、素早く価値を提供できるので、楽しいです。

注意点やTipsなど

  • UI Debug方法
    Flutter Inspectorを使うと便利です。

  • Web版の場合、テキストの選択、コピー、ページ内の検索に弱い
    テキストはデフォルトで選択、コピーできないという制限があります。
    これについては、SelectableText, SelectableHtml widgetを使って改善できます。ただwidgetに跨って選択することができません。この点については2022年のroadmapに上がってるので、改善が期待できると思います。

  • 状態管理を間違うと無限buildになる可能性がある

    • 影響:
       1. clientが死ぬ
       2. backendが超負荷になる
       3. 想定外の課金につながる
      例えば、以下のコードのような場合、build処理の状態で、watchと同時に更新を行うと、無限にbuildが実行されます。

    • 回避方法:build処理がトリガーになった状態で更新をしない

final counter = StateProvider((ref) => 1);

class Screen extends HookConsumerWidget {
 @override
 Widget build(BuildContext context, WidgetRef ref) {
   final x = ref.watch(counter);
   
   WidgetsBinding.instance?.addPostFrameCallback((_) {
     ref.read(s.notifier).state = ref.read(s.notifier).state + 1;
   });
   
   .....
var dio = Dio();
if (dio.httpClientAdapter is BrowserHttpClientAdapter) {
(dio.httpClientAdapter as BrowserHttpClientAdapter).withCredentials = true;
}
  • webアプリで外部ファイルjavascriptを呼ぶ場合、javascriptのloadが遅くて、NoSuchMethodErrorエラーになる問題
    解消案
       1. javascriptが自作の場合、index.htmlのinline scriptで書く
       2. javascriptを別ファイルにする場合、コードで動的にloadして、load完了後にflutterのmain.dart.jsをloadする
    javascriptをコードで動的にloadするサンプルコード:

function loadScript(url, callback) {
    var scriptTag = document.createElement("script")
    scriptTag.type = "text/javascript";
    scriptTag.onload = function() {
        callback()
    };
    scriptTag.src = url;
    document.body.append(scriptTag);
}

function loadMainDartJs() {
    if (scriptLoaded) {
        return;
    }
    scriptLoaded = true;
    loadScript("https://code.jquery.com/jquery-3.6.0.min.js", function() {
        var scriptTag = document.createElement('script');
        scriptTag.src = 'main.dart.js';
        scriptTag.type = 'application/javascript';
        document.body.append(scriptTag);
    });
}
  • 画像表示が失敗する可能性があるので、errorBuilderを必ず指定する
    loadが遅いときは、loadingBuilderも提供して、ユーザーのストレスを軽減しましょう。

Image.network(url, errorBuilder: (_, __, ___) => Text("画像の表示が失敗しました"))
  • Hiveを使うときに、boxをcloseすることを忘れないようにする
    webアプリを作成するときにboxをcloseしないと、別のTABを開くときにboxに設定した値が取れない現象が発生します。例えば、認証情報をhiveで管理するときに、ログインしても、別のTABでは未ログイン状態のままになります。

画像1
source mapsがないと、stack traceはminimizedされたjsで表示されてるので、問題調査にほぼ役に立たないです。
画像2
source mapsをアップロードすると、jsエラーがDartコードにmappingされてstack traceがDart上のものになります
  • webアプリで直URL指定しても、ページが開けるようにする
    riverpodなどで状態管理をするときに、直URLでページを開くときもページで使う状態を正常に設定するように工夫しないと、ページが表示できない可能性があります。

  • webアプリの場合、本番公開前にweb/index.html中の自動生成されたmeta 、titleタグを更新しておく
    自動生成されたコードは以下のような感じです。

<meta name="description" content="A new Flutter project."><!-- iOS meta tags & icons -->
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black"><meta name="apple-mobile-web-app-title" content="untitled">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<title>untitled</title>​
  • Htmlをflutter中で表示する方法
    Htmlをflutter中で表示することで既にあるhtmlコンテンツを活用することができます。slideshareの表示をコードで説明します

  Widget build(BuildContext context) {
    var url = 'https://www.slideshare.net/DataReportal/slideshelf';
    final viewTypeId = 'slide.share:$url'; // 唯一にすることが大事
    // ignore: undefined_prefixed_name
    ui.platformViewRegistry.registerViewFactory(
        viewTypeId,
        (int viewId) => IFrameElement() // html elementを生成
          ..allow = 'fullscreen'
          ..width = '100%'
          ..height = '100%'
          ..src = url);

    // HtmlElementViewを使ってhtml elementを表示
    return SizedBox(
        width: 760,
        height: 570,
        child: HtmlElementView(viewType: viewTypeId));
  }


以上になりますが、少しでも皆さんに参考になれば幸いです。



2022年8月29日 19時~
教育ビジネス×Flutter開発の勉強会を開催いたします!
ご参加をお待ちしております。

この記事が気に入ったらサポートをしてみませんか?