こんにちは。『スタディサプリ for SCHOOL』 の開発に携わっている @koji-1009 です。 この記事はスタディサプリProduct Team Advent Calendar 2024 14日目の記事になります。カレンダー2週目も今日で終わりです。
本稿ではFlutterKaigi 2024に参加し、登壇した際の内容の補足などをします。特に、セッション時間の関係で省いたものが多いWeb対応について書きます!
FlutterKaigi 2024
FlutterKaigiは、エンジニアが主役のFlutterカンファレンスです。Flutter開発者有志による実行委員会により開催されています。 2021年と2022年はオンラインのみの開催でしたが、2023年よりオンラインとオフラインのハイブリッドイベントになっています。
株式会社リクルートは2023年に続き、2024年もスポンサーとして参加しました。特に2024年はセッションスポンサーとして参加しています。 筆者は21年と22年にセッション登壇、2023年に公式アプリのメインコントリビューター、そして2024年にスポンサーセッション登壇で参加しています。
セッションについて
登壇セッションはDay 1の14時50分から、A Dashルームで行われたFlutterによる効率的なAndroid・iOS・Webアプリケーション開発の事例 - スタディサプリ for SCHOOLです。 非常に広いルームだったので、前に立った時にはドキドキしました。
資料の通り、セッションでは『スタディサプリ for SCHOOL』にFlutterを導入したことで得られた知見を共有しました。 以前投稿したブログでは、AndroidとiOSのアプリをFlutter化した知見を共有しました。そのことを踏まえ、Webも含めたより包括的なセッションを意識しました。 筆者の所属するチームで起きた大きな改善効果、そして『スタディサプリ for SCHOOL』のサービスに与えた影響は、きっとFlutterを採用するか検討している方々の背中を押せるものになったのではないか、と考えています。
セッションで紹介した開発効率の向上は、各種マルチプラットフォームフレームワークを採用することで得られるものです。 「Flutterは他と比べて何がいいのか?」と問われると、これまでは「モバイルアプリエンジニア との相性が良い気がする」とぼんやり答えていたように思います。
今回のセッションの準備や発表を通して、この点をより具体的に言語化できました。 Flutterを採用したチーム開発の解像度が、より高まった印象です。 特に、Flutterを導入することで『負担感は感じにくいが、明確に負担が増える』ことを言語化できたことは、とても良い経験でした。
Flutterを導入しても、解決しなければならない問題が消えることはありません。 一方で、Flutterを活用すればするほど、より少数でアプリを開発できるようになっていきます。 開発効率が高まれば高まるほど、客観的に見れば、1エンジニアにかかる負担は高まっていきます。
負担は高まっているはずなのですが、1エンジニアとしての日々を振り返ってみると、負担感が高まった印象はありません。 むしろFlutterを採用したことで、これまで以上にアプリが開発しやすくなった、そんな印象すら抱きます。 チームメンバーとリプレースを振り返ってみても、この印象は一致していました。
結果として、担当する領域が増えるのにも関わらず、負担感を感じにくい環境を作り上げることができます。 こうして、一人一人が能力を発揮しやすくなり、結果としてチーム全体で開発効率が高まっていく。 Flutterを採用したことによりチーム内に生まれた好循環を、セッションを通して示せたのではないかと考えています。
資料を作成するにあたっては、社内の多くの方々にお世話になりました。 特に所属チームの方々には、インタビューや資料のレビューなど、多くのサポートをいただきました。 この場を借りて、御礼申し上げます。
Flutter Web対応について
さて、FlutterKaigiの場で話し足りなかった内容があります。Flutter Webです。
『スタディサプリ for SCHOOL』がFlutter Webを採用した際には、採用を躊躇うような不具合は発生しませんでした。しかし、対応に苦心したものがいくつかあります。本記事では、その中でも印象深かったFont問題について掘り下げます。
CanvasKit x ヒラギノ角ゴシック
CanvasKit上でヒラギノ角ゴシックを利用すると、Bold
にした文字の意図しない箇所が太くなったりかすれたりする問題です。
これはSkiaの問題がCanvasKit経由で *1 Flutter Webに持ち込まれています。
この問題は「Systemからfontを読み込んだ際に、どのようにVariable Fontとして扱うか」の考慮漏れにより発生していたようです。SkiaのIssueと修正コミット *2 を確認すると、従来font単体をチェックしていた処理を、fileをチェックし含まれるfaceごとにfontをチェックしているように読めます。 *3
この対応により、Skiaで問題が解決した、と報告されています。 しかしSkiaの修正がCanvasKitにいつ取り込まれてリリースされるか分からなかったため、暫定的に、WebではNoto Sans JPを適用することにしました。
HTMLレンダラー x iOS x Noto Sans JP
iOSでCanvasKitを利用しようとすると、メモリー使用量が多すぎる問題にぶつかります。
この問題は2021年に起票されていますが、2024年12月現在でも解決されていません。このため、iPhone向けにFlutter Webのアプリケーションを提供しようとすると、CanvasKitではなくHTMLレンダラーを利用する必要が生じます。
ではHTMLレンダラーを利用すれば全てが解決するかと言えば、そうもいきません。iOSにてHTMLレンダラーを指定すると、Noto Sans JPを指定した時にweightが意図せず太くなってしまう問題を踏んでしまいます。
HTMLレンダラーは廃止が予定されており、この問題が解消される見込みはありません。このため、HTMLレンダラーではSystem Fontを利用することとしました。HTMLレンダラーであれば、適切にSystem Fontを読み込むことができるため、先述の問題が起きることはありません。 また、System Fontを利用すると読み込み時の通信量を削減することもできます。モバイルデバイス向けであれば、System Fontを利用することのメリットは大きいでしょう。
実装を紹介すると、次のようなコードになります。
ThemeData get appTheme { final baseTheme = ThemeData(); final TextTheme textTheme; if (kIsWeb) { textTheme = isCanvasKit ? GoogleFonts.notoSansJpTextTheme(baseTheme.textTheme) : baseTheme.textTheme; } else { textTheme = baseTheme.textTheme; } return baseTheme.copyWith( textTheme: textTheme, ); }
HTMLレンダラー x Android x System Font
さてiOSでHTMLレンダラーの指定をした場合、AndroidでもHTMLレンダラーを利用することになります。 また前述の理由から、System Fontを設定することとしました。すると、Android端末に同梱されているFontの問題が登場します。
AOSPに含まれているNoto Sans JPは、Regularのみになっていました。このため、iOSとAndroidのブラウザ上で見比べた時に、Androidにおいて文字が細くなる問題が生じていました。
過去形で書いたのは、この問題がAndroid 15で改善されたためです。
Android 15で試したところ、様々な箇所で文字が適切に太くなる現象が確認できました。 この問題に関しては、Android 15以降では改善されることもあるため、一旦アプリ側で対応しないこととしています。
おわりに
以上、FlutterKaigi 2024で紹介しきれなかったFlutter WebのFont問題深掘りでした。 紹介したもの以外にも、ブラウザのbackward button対応や入力中のリロード問題なども厄介でした。ただ、どれも対応ができる・できないがはっきりしており、大変ではあるものの苦慮というほどではなかったかなと思います。
この冬休みに、Flutter Webの探検に出かけてみるのはどうでしょうか? 明日のブログもお楽しみに!
*1:CanvasKitはSkiaをWebAssemblyの技術で固めたものになります
*2:https://github.com/google/skia/commit/f4905091eeb957662145bc5a70ff8f4a55d3402f でも読めます