システム開発部のTです。
久々の投稿になります。
今回、FlutterでWebアプリを開発したときに遭遇した文字化けの問題について記載いたします。
なお、本件ではFlutterで作成したアプリをWebブラウザで動作させたときのみ文字化けが発生しております。自分の環境ではiOS、Androidのネイティブアプリでは文字化けは確認できておらず、Webブラウザでのみ発生しているため、本件ではWebブラウザで動作させた場合の対応のみといたします。
文字化けについて
まずは、以下を御覧ください。

皆さんのなかにも、上記の現象を経験されている方がいらっしゃるのではないでしょうか。
(※上記の文字化けは通称「豆腐」と呼ばれています・・・)
上記画面から1秒未満で以下の正常な画面になります。

これが本来の画面です。
上記はアプリ起動時の最初に表示される画面になりますが、
画面表示直後の一瞬ですが、上にも記載した文字化けの画面になります。
今回は、この文字化けを解消する手段を書いていきます。
日本語対応のフォントを設定する
シンプルですが、この方法がもっとも近道な対応になります。
想定になりますが、Flutterのデフォルトのフォントが日本語対応のフォントではないため、
本件の事象が発生していると思われます。
それであれば、最初から日本語対応フォントの設定を追加することで本件の事象を回避できるのでは?
と思った次第です。実際に設定後に動作させたところ、文字化けすることなくアプリの起動をさせることができましたので、その方法を書いていきたいと思います。
参考にしたのは、以下のFlutter公式ページになります。
https://docs.flutter.dev/cookbook/design/fonts
日本語フォントを取得する
今回は以下のGoogleFontからダウンロードします。
「Noto Sans Japanese」というのがあるので、それをダウンロードしてください。
https://fonts.google.com/noto/specimen/Noto%20Sans%20JP
「Noto_Sans_JP.zip」というのがダウンロードされるので、それを解凍します。
中身は以下の内容になっているかと思います。

アプリにフォントファイルをインポート
アプリのプロジェクトにassetsフォルダを生成し、その下にfontsフォルダを生成します。
fontsフォルダに先程のフォントファイル(拡張子がotf)をコピーしてください。
最終的には以下のようになります。

フォントの設定を追加
pubspec.yamlを開いてフォントの設定を追加します。
設定については、公式のページに詳細が記載されています。
https://docs.flutter.dev/cookbook/design/fonts
上記のページをもとに以下の内容で追加しました。
fonts:
- family: NotoSansJP
fonts:
- asset: assets/fonts/NotoSansJP-Black.otf
weight: 900
- asset: assets/fonts/NotoSansJP-Bold.otf
weight: 700
- asset: assets/fonts/NotoSansJP-Light.otf
weight: 300
- asset: assets/fonts/NotoSansJP-Medium.otf
weight: 500
- asset: assets/fonts/NotoSansJP-Regular.otf
weight: 400
- asset: assets/fonts/NotoSansJP-Thin.otf
weight: 100
familyの「NotoSansJP」については任意の文字列を設定します。
今回はわかりやすく「NotoSansJP」にしています。
上記のweight値については、以下のフォントページの「Thin 100」という記述をweight値としています。

フォントファミリーをテーマに設定する
上記の設定をMaterialAppのthemeに設定します。
return MaterialApp(
title: 'Custom Fonts',
theme: ThemeData(fontFamily: 'NotoSansJP'),
home: const MyHomePage(),
);
ThemeDataのfontFamilyにアプリ設定ファイル上に定義した「NotoSansJP」を設定します。
以上で設定完了です。
アプリを実行してみてください。
アプリを実行
アプリを実行すると、文字化けすることなく、以下の内容で表示されると思われます。

また、左がフォント追加前で、右がフォント追加後ですが、日本語表示としても違和感が無くなりました。


2つのレンダリングモードについて
Webブラウザ上で実行するにあたり、Flutterでは以下の2つのレンダリングモードで実行されています。
- HTML renderer
- CanvasKit renderer
通常、デフォルト設定ではPCのブラウザではCanvasKitが、モバイルではHTMLのモードで動作するようになっているようです。
任意でのモード切り替えについては、以下を参照ください。
https://docs.flutter.dev/development/tools/web-renderers
今回の問題ですが、CanvasKitで起動させた場合に不具合が起きたのですが、これをHTMLモードに切り替えることで、不具合が起きなくなります。
ただ、HTMLのレンダリングの場合、DOMベース(HTML、CSSなど)でのレンダリングになるため、若干意図しない画面のレイアウトが崩れてしまう可能性もあります。私自身も、オブジェクトに対してマウスオーバー時に指定しているUIが意図しない形で表示されるという現象がありました。
HTMLレンダリング自体は、Canvaskitよりも軽量なメリットもありますが、HTMLレンダリング選択前提とした動作検証は念入りに実施することをおすすめします。
まとめ
いかがだったでしょうか。
今回はWebアプリでの対応のためにフォントを設定しましたが、ネイティブアプリで設定するのにも役に立つはずですので、お試しいただければと思います。
以上です、ありがとうございました。