Flutter 3.50の変更点まとめ — iOSのタッチ遅延を1フレーム短縮、Android Intentの検証強化
はじめに
2026年11月11日、Flutter 3.50 と Dart 3.14 がリリースされました。188人(うち初参加69人)による1,200以上のコミットを含む大型リリースです。
公式ブログの冒頭で強調されているのは、ネイティブ連携(direct native interop)の stable 化です。ただ、r/FlutterDev で反応が集まったのは、本文の iOS セクションにある改善でした。タッチしてから画面が反応するまでの遅延が縮み、「告知が控えめすぎる」という声が出たほどです。
この記事では、iOS のタッチ遅延がなぜ起きていたのか、Android のリリースビルドで何が動かなくなるのか、既存アプリで確認すべき移行作業は何かを整理します。
Flutter 3.50 の主な変更点
公式ブログで挙げられている変更のうち、実務に影響が大きいものは次のとおりです。
| 分野 | 変更 |
|---|---|
| iOS | タッチ後のフレーム生成スケジュールを改修。入力遅延が 60Hz 端末で 16ms、120Hz 端末で 8ms 短縮 |
| Android | リリースビルドで、外部から渡された Intent extras の route や dart_entrypoint などを検証し、通らなければ無視 |
| ネイティブ連携 | Objective-C 向け FFIgen と Java/Kotlin 向け JNIgen が stable。Pigeon の新しいネイティブ連携モードはプレビュー |
| デザイン | package:flutter/material.dart と cupertino.dart を正式に非推奨化。新規プロジェクトは package:material_ui を使う |
| Web | Chrome / Edge 137 以降は既定で Wasm。Safari 26.2 以降と Firefox 147 以降も flutter_bootstrap.js の設定で Wasm を有効にできる。dart:html などの旧 JS 連携を非推奨化 |
| ツール | CocoaPods の trunk が2026年12月に読み取り専用になるため、Swift Package Manager を無効にすると毎回警告が出る |
同時に出た Dart 3.14 には新しい言語構文はありません。代わりに、SDK 制約を1マイナーずつ上げながら dart fix を当てる dart migrate コマンドが追加されました。pub は ETag によるキャッシュに対応し、依存が多いプロジェクトでは pub get の通信量が減ります。
iOS のタッチ遅延 — 「1 vsync 待ち」をやめた
何が遅かったのか
Flutter が iOS でネイティブより1フレーム遅れて反応する問題は、2022年8月に #110431「Flutter adds additional one frame touch latency compared to native」として報告されていました。ネイティブアプリと並べると、スクロールやドラッグで指に対する追従がわずかに遅れて見える現象です。
原因は、タッチイベントを次の vsync(画面更新の区切り)まで待たせる仕組みにありました。2026年8月に立った #191199 では、iPhone 6s から iPhone 17 Pro まで実機で計測し、約99%のタッチが1 vsync 遅れて処理されていたことが示されています。遅らせていたのは SmoothPointerDataDispatcher などの、タッチの間隔を均すための仕組みです。均すこと自体には意味がありましたが、その代わりに必ず1フレーム分の遅延が乗っていました。
どう直したのか
3.50 では、Matej Knopp 氏によりタッチ後のフレーム生成スケジュールが作り直されました。公式ブログによると、タッチイベントを次の vsync まで待たせずにすぐフレームワークへ渡し、同じ画面更新の中でフレームを組み立てるようになっています。#191199 は PR #191444「Cleanup VSync infrastructure and improve iOS touch to present latency」で完了しました。
短縮幅は1フレーム分で、60Hz なら約16ms、ProMotion の 120Hz なら約8ms です。数字は小さく見えますが、指で直接触る操作では1フレームの差がはっきり体感に出ます。60fps と 120fps ほど違うという Reddit の感想も、1フレーム遅れがなくなったことと合っています。なお、公式ブログは今後のリリースで入力遅延をさらに縮める作業が進んでいると書いており、#110431 自体はこの記事の執筆時点でまだ open のままです。
Android — リリースビルドで Intent extras が無視される
何を防ぐのか
こちらは既存アプリが動かなくなる可能性がある変更です。Flutter の FlutterActivity と FlutterFragmentActivity は、Intent extras に入った次の値を読んで起動方法を変えられました。
route(初期ルート)dart_entrypoint/dart_entrypoint_args(実行する Dart の関数と引数)cached_engine_id/cached_engine_group_id(キャッシュ済みエンジンの再利用)
公式ブログは、これまでの Android アプリが「端末にインストールされた任意のアプリから」これらの設定を受け付けていたことを脆弱性とし、3.50 のリリースビルドで塞いだと説明しています。筆者の補足として具体的に考えると、ログイン後にしか見せない画面へ外部から直接遷移させる、意図しないエントリポイントを実行させる、認証済みのままメモリに残っているエンジンを再利用させる、といった悪用が考えられます。
3.50 のリリースビルドでは、送信元を検証してから extras を読みます。非公開の Activity(android:exported="false")への起動は信頼されます。Android 14 以降は起動元の UID がアプリ自身と一致するかを確かめ、Android 13 以前は呼び出し元のパッケージ名を確かめます(startActivityForResult() か startActivityIfNeeded() で起動したときだけ取得できる)。ACTION_VIEW のディープリンクは、マニフェストの <intent-filter> に一致する必要があります。検証に通らなければ extras は無視され、マニフェストの設定か既定値(ルートは /、エントリポイントは main)で起動します。デバッグ・プロファイルビルドでは検証が省略され、検証に失敗する場合は警告ログが出ます。
あわせて、--dart-flags などのエンジンフラグも、リリースビルドでは Intent 経由で受け付けなくなりました(警告ログを出して破棄)。flutter run --release --use-application-binary にフラグを付けた場合は CLI がエラーで止まります。どちらの変更にも、リリースビルドで無効にするオプトアウトは用意されていません。
影響を受けるケースと対応
影響を受けるのは、ネイティブ側から extras でルートを渡して Flutter 画面を開いているアプリです。ネイティブアプリに Flutter を部分的に組み込んでいる add-to-app 構成で、よく使われてきた書き方です。対応は公式ドキュメントに沿って次のいずれかを選びます。
- 外部から開く必要がない Activity は
android:exported="false"にする(ランチャー Activity は exported のまま) - 外部からの遷移は extras ではなく、
<intent-filter>を宣言したディープリンクにする - 固定のルートやエントリポイントはマニフェストの
io.flutter.InitialRoute/io.flutter.Entrypointに書く - 動的に決めたい場合は Activity をサブクラス化し、
getDartEntrypointFunctionName()やgetDartEntrypointArgs()をオーバーライドする - Android 13 以前で同じアプリ内から起動する場合は、
startActivity()ではなくstartActivityForResult()を使う(呼び出し元パッケージを取得できるようにするため)
ドキュメントには明記されていませんが、検証の規則から考えると、FlutterActivity.withNewEngine().initialRoute(...) で作った Intent も対象になります。このビルダーはルートを route extra に入れるためです。同じアプリ内からの起動でも、対象 Activity が exported で、Android 13 以前の端末で startActivity() を使っていると検証に通らず、ルートが / に戻ります。Android 14 以降や、非公開の Activity なら影響はありません。
注意したいのは、デバッグビルドでは検証が省略される点です。開発中は問題なく動き、リリースビルドで初めて「初期画面が / になる」という形で発覚します。3.50 に上げたら、リリースビルドで Flutter 画面への遷移を一通り確認しておくと安全です。CI でビルド済みのリリース APK にフラグを渡して計測していた場合も、プロファイルビルドに切り替える必要があります。
エンジニアへの影響 — 移行の優先順位
既存プロジェクトを 3.50 に上げるときは、次の順で確認すると手戻りが少なくなります。
- Android の Intent 検証: リリースビルドでだけ挙動が変わり、開発中に気づけないので最初に確認する。ネイティブ側で
EXTRA_INITIAL_ROUTEやwithNewEngine().initialRouteを使っている箇所を洗い出し、対象 Activity のexported設定と、サポートする Android の最低バージョンをあわせて確認する - iOS のビルド環境: CocoaPods から Swift Package Manager への移行が済んでいないなら、12月の trunk 読み取り専用化の前に着手する。Intel Mac でビルドしている場合も、Flutter はすでに Intel Mac でのテストをやめており、将来 Intel Mac のサポートが外れた時点で iOS / macOS / Android のビルドに Apple Silicon が必須になると書かれている
- Material の非推奨化: 3.47 で
material_ui1.0 が出た流れの続きで、今回は警告が出るだけ。dart fix --apply --code=migrate_design_widgetsで import を一括で書き換えられる - ネイティブ連携: プラットフォームチャネルで書いた既存コードはそのまま動く。FFIgen / JNIgen を使うと、プラットフォームチャネルのメッセージ受け渡しを経由せずにネイティブ API を直接呼べる。公式ブログによると、同期呼び出しやバックグラウンド isolate からの呼び出しもできる。新しく書く連携から検討するとよい
iOS のタッチ遅延の改善は、アップグレードするだけで得られます。ネイティブアプリを Flutter に置き換えるプロジェクトでは、「触ったときの感触がネイティブと違う」という指摘が出やすいため、3.50 に上げる理由として説明しやすい改善です。
一方、メジャー相当の変更が多いリリースなので、r/FlutterDev でも「x.x.1 のパッチ版を待ってから上げる」という意見が出ています。本番アプリは Android のリリースビルドの確認を済ませ、最初のパッチリリースを待ってから移行するのが堅実です。
まとめ
- Flutter 3.50 と Dart 3.14 が2026年11月11日にリリースされた
- iOS では、タッチを次の vsync まで待たせる仕組みをやめ、入力遅延が1フレーム分(60Hz で16ms、120Hz で8ms)縮んだ
- Android のリリースビルドでは、外部から渡された
routeやdart_entrypointなどの Intent extras が検証され、通らなければ無視される。デバッグビルドでは気づけないため、リリースビルドで確認が必要 - FFIgen(Objective-C)と JNIgen が stable になり、Material / Cupertino の旧ライブラリは正式に非推奨になった
公式ブログはネイティブ連携の専用記事を予告しています。Pigeon の新モードはまだプレビューなので、既存のプラットフォームチャネルをどこまで置き換えられるかは、その記事と今後のリリースで確かめたいところです。
ソース
- What’s new in Flutter 3.50 (Flutter Blog)
- Announcing Dart 3.14 (Dart Blog)
- Stricter Android Intent verification for entrypoints (Flutter Docs)
- Restrict Android engine flags in release mode (Flutter Docs)
- flutter/flutter #191199: iOS: Delete SmoothPointerDataDispatcher and _touchRateCorrectionVSyncClient
- flutter/flutter #110431: Flutter adds additional one frame touch latency compared to native
- r/FlutterDev のスレッド(タッチ遅延修正への反応、アップグレード時期の議論)は本文を取得できなかったため、デイリーダイジェストの要約を参照した