Flutter 3.29 は2025年2月12日に出た安定版で、Dart 3.7 を同梱しています。パッチは 3.29.3(2025年4月14日)が最終で、次の 3.32.0 は2025年5月20日に出ました。この版の変更でいちばん影響が大きいのは、Android と iOS で Dart コードがプラットフォームのメインスレッドで動くようになった点です。
この記事では、公式ブログ「What’s new in Flutter 3.29」、破壊的変更の一覧、flutter/flutter のタグ 3.29.3 の CHANGELOG とエンジンのソースを根拠に、3.29 で変わったことと、3.29.0〜3.29.3 のパッチ内容を整理します。掲載したコードは Flutter 3.29.3(Dart 3.7.2)で flutter analyze にかけ、ウィジェットテストで動作を確かめました。analyze が出す警告は、本文で触れている非推奨の指摘だけです。最新版の Flutter で変わった点はFlutter 3.47とは?material_ui分離とIntel Mac終息で決まる移行判断【2026年8月時点】で扱っています。
まとめ:Flutter 3.29 で押さえる変更点
- 3.29.0 は2025年2月12日公開・Dart 3.7.0 同梱。最終パッチの 3.29.3 は Dart 3.7.2 で、2025年4月14日に出ました。
- Android と iOS で、Dart コードは独立した UI スレッドではなくアプリのメインスレッドで実行されます。3.29〜3.35 は設定で元に戻せましたが、3.38.0 以降はその設定を書くと起動時にエラーになります。
- iOS からは Skia が削除され、
FLTEnableImpellerで Impeller を切る方法は効かなくなりました。Android は Vulkan が使えない端末で Impeller の OpenGLES に切り替わります。ただし、3.29.2 以降は Android 9(API 28)以前の端末で Skia を使います。 - Flutter Web の HTML レンダラーは 3.29 で削除されました。Wasm ビルドは特別な HTTP ヘッダーが無くても単一スレッドで動くようになりました。
- 新しい API は
BackdropGroup/BackdropFilter.grouped、showCupertinoSheet、CupertinoNavigationBarのbottom、SelectionListener、FadeForwardsPageTransitionsBuilderなど。 - 移行作業が要るのは、Flutter Gradle プラグインの命令的な apply(3.16 より前に作ったプロジェクト)、v1 Android embedding、2025年4月30日で開発終了となった公式パッケージ6本です。
以下、パッチ履歴、スレッドとレンダラーの変更、新しい API、移行作業の順に説明します。
Flutter 3.29.0〜3.29.3 のリリース日と Dart バージョン
リリース日と同梱 Dart は、Flutter の配布情報(releases_macos.json。一覧はSDK アーカイブのページでも見られます)から取りました。日付は UTC です。
| バージョン | 公開日(UTC) | Dart | 主な内容 |
|---|---|---|---|
| 3.29.0 | 2025-02-12 | 3.7.0 | 初回の安定版 |
| 3.29.1 | 2025-03-06 | 3.7.0 | Vulkan の不良ドライバー除外、文字の揺れ修正 |
| 3.29.2 | 2025-03-13 | 3.7.2 | API 29 未満の OpenGLES クラッシュ修正 |
| 3.29.3 | 2025-04-14 | 3.7.2 | エミュレーターのぼかしクラッシュ修正 |
| 3.32.0(次版) | 2025-05-20 | 3.8.0 | 3.29 系の後継 |
Dart が 3.7.2 に上がったのは 3.29.2 からです。pubspec.yaml で sdk: ^3.7.2 のように patch まで指定しているパッケージは、3.29.0 と 3.29.1 では解決できません。
3.29.1〜3.29.3 で直った不具合
CHANGELOG を見ると、パッチの修正は Impeller と Android の描画に集中しています。3.29.0 の Impeller で問題が出ていたなら、3.29.3 まで上げれば直っている可能性があります。
- 3.29.1:不具合が既知の Exynos・Xclipse GPU ドライバーで Vulkan を無効化。一部の GLES ドライバーで
BackdropFilterを使うと落ちる問題、バックグラウンドから戻ったときの文字化け、グリフの揺れを修正。アイコン付きボタンがforegroundColorを無視する問題も直りました。 - 3.29.2:API 29 未満の Android で Impeller OpenGLES を使ったときのクラッシュを修正。MediaTek の SoC では Vulkan をやめて OpenGL を使います。ちょうど180度回転した文字が裏返る問題や、Android・iOS でグリフが欠ける問題も直りました。
- 3.29.3:Android エミュレーターで背景ぼかしのある画面へ遷移すると落ちる問題と、48倍を超えて拡大した文字の描画崩れを修正。デバッガーで「Pause on Unhandled Exceptions」を有効にしたまま
computeやIsolate.runを呼ぶと、ホットリスタートが止まる問題も直りました。
なお Flutter の CHANGELOG には「hotfix は最新版にしか出さない」と明記されています。3.29 系に新しい修正が入ることはもうありません。
3.29.3 の SDK を入手する方法
既存プロジェクトの再ビルドなどで 3.29.3 を使い続けるなら、プロジェクト単位で版を固定できる FVM が手軽です。
# FVM でプロジェクトを 3.29.3 に固定する
fvm install 3.29.3
fvm use 3.29.3
# FVM を使わない場合は配布アーカイブを直接取得する(Intel Mac 用の例)
curl -LO https://storage.googleapis.com/flutter_infra_release/releases/stable/macos/flutter_macos_3.29.3-stable.zip
アーカイブのファイル名は CPU で分かれていて、Apple Silicon の Mac 用は flutter_macos_arm64_3.29.3-stable.zip です。Intel Mac で arm64 版を展開すると、同梱の Dart が「Bad CPU type in executable」で起動しません。FVM の設定やチームでの版の揃え方はFVMとは?Flutter SDKをプロジェクト単位で固定する運用とCI設定【2026年8月時点】で解説しています。
Dart コードがメインスレッドで動く変更と 3.38 での固定
3.27 までの Flutter は、Dart コードを専用の UI スレッドで実行し、プラットフォームのメインスレッドとはメッセージで通信していました。3.29 から Android と iOS では UI スレッドが無くなり、Dart コードはアプリのメインスレッドで動きます。公式ブログはこれを「プラットフォームとの相互運用を改善する一連の変更の第一弾」と位置付けていて、シリアライズとメッセージ送受信を挟まない同期呼び出しを可能にするのが狙いです。
開発者側で気をつけたいのは、Dart 側の重い同期処理とネイティブ側の処理が同じスレッドを取り合う点です。以前は別スレッドだったので、Dart 側の長いループがネイティブ UI の応答を直接止めることはありませんでした。3.29 以降は、メインスレッドを長く握る処理が Android の ANR(アプリ応答なし)判定にもつながります。JSON の大きなデコードや画像処理は Isolate.run や compute に逃がしてください。
オプトアウトの設定と使える版
3.29.3 のエンジンのソースでは、Android は AndroidManifest.xml のメタデータ、iOS は Info.plist のキーで、スレッド統合を無効にできます。
<!-- android/app/src/main/AndroidManifest.xml の <application> 内 -->
<meta-data
android:name="io.flutter.embedding.android.DisableMergedPlatformUIThread"
android:value="true" />
<!-- ios/Runner/Info.plist の <dict> 内 -->
<key>FLTEnableMergedPlatformUIThread</key>
<false/>
ただし、この逃げ道が使えるのは 3.35 までです。各版のタグのソースを確かめたところ、3.38.0 からは Android で IllegalArgumentException(「is no longer allowed」)が投げられ、iOS でも FLTEnableMergedPlatformUIThread=false is no longer allowed. で停止します。
| 版 | Android の無効化キー | iOS の無効化キー |
|---|---|---|
| 3.29〜3.35 | 有効(UIスレッドに戻る) | 有効 |
| 3.38.0 以降 | 例外で起動失敗 | エラーで停止 |
3.29 で統合スレッドの不具合を避けるためにこの設定を入れたプロジェクトは、3.38 以降へ上げる前に設定を消し、原因になった処理を直す必要があります。上げたとたんに起動しなくなるので、アップグレード時に最初に確認したい項目です。
Impeller の変更:iOS は Skia 削除、Android は OpenGLES へ
iOS のバックエンドからは Skia が削除されました。Info.plist の FLTEnableImpeller で Impeller を切って Skia に戻す方法は効きません。公式ブログは、今後の版で Skia の部品を iOS ビルドから外し、バイナリサイズをさらに減らすとしています。
Android は、Vulkan ドライバーが正常に動かない端末で、Skia ではなく Impeller の OpenGLES バックエンドに切り替わるようになりました。3.29.0 の発表時点では、この切り替えは設定不要で、対応する Android 端末全体で Impeller が使えると説明されていました。ただし、3.29.2 からは Android 9(API 28)以下の端末は Skia を使うように変わりました。3.29.2 のエンジンのソースに API レベル29未満を Skia に振り分ける判定が入り、同じパッチの CHANGELOG には API 29 未満で Impeller OpenGLES を使ったときのクラッシュ修正が載っています。あわせて、黒画面やクラッシュの報告が多かった MediaTek・PowerVR の SoC では Vulkan を無効にし、Android エミュレーターも Impeller の GLES バックエンドを使います。
Android で Impeller そのものを切る io.flutter.embedding.android.EnableImpeller のメタデータは、3.29.3 のソースにも残っています。false を指定すると --enable-impeller=false がエンジンに渡ります。iOS と違って Android では、3.29 時点ではまだ Skia に戻せるということです。
描画結果に影響する破壊的変更もあります。ImageFilter.blur の既定のタイルモードが自動選択になったので、ぼかしの端の見え方が変わることがあります。移行ガイドによると、以前はタイルモードを指定しなければ TileMode.clamp でしたが、3.29 からは背景フィルターでは mirror、セーブレイヤーと図形描画では decal、drawImage では clamp が自動で選ばれます。影響を受けるのはタイルモードを明示していないぼかしだけです。ゴールデンテストで差分が出たら、意図した描画かを確認してから画像を更新してください。従来の端処理を残したい場合は TileMode.clamp を明示します。
Flutter Web:HTML レンダラーの削除と Wasm の要件緩和
3.29 は、Flutter Web から HTML レンダラーが削除された最初の版です。3.29.3 で flutter build web --web-renderer html を実行すると、Could not find an option named "--web-renderer". で止まります。CI のビルドコマンドにこのオプションが残っていたら削除してください。描画は CanvasKit になり、--wasm を付けると Wasm(skwasm)でビルドします。
Wasm ビルドは、2024年5月の登場時は特別な HTTP レスポンスヘッダーを付けて配信する必要がありました。3.29 からはヘッダーなしでも動きます。ただし、ヘッダーなしではマルチスレッドにならず、単一スレッドで動きます。
画像まわりでは、CORS エラー時に <img> 要素へ切り替えるかどうかを webHtmlElementStrategy で選べるようになりました。3.28 ベータでは自動で切り替わっていて、挙動が一定しないのが問題でした。CanvasKit と Wasm の違いや Web 版を採用する条件は、Flutter Webとは?CanvasKitとWasmの描画差・SEO制約・採用条件【2026年8月時点】で比べています。
BackdropGroup と BackdropFilter.grouped によるぼかしの共有
同じ画面に背景ぼかしを複数配置すると、個別のフィルター処理が負荷になります。以下の共有方式は、ぼかす領域が互いに重ならない配置で使います。重なる領域に同じキーを使うと、フィルターが1回だけ適用されたように見えることがあります。3.29 で入った BackdropGroup の下で BackdropFilter.grouped を使うと、同じグループのフィルターが背景の取得を共有します。公式ブログは、Skia バックエンドで可能だった水準を超える性能改善だとしています。
import 'dart:ui' show ImageFilter;
import 'package:flutter/material.dart';
class BlurredToolbar extends StatelessWidget {
const BlurredToolbar({super.key});
@override
Widget build(BuildContext context) {
return BackdropGroup(
child: Column(
children: [
for (final label in ['検索', '通知', '設定'])
ClipRect(
child: BackdropFilter.grouped(
filter: ImageFilter.blur(sigmaX: 8, sigmaY: 8),
child: SizedBox(height: 48, child: Center(child: Text(label))),
),
),
],
),
);
}
}
BackdropFilter.grouped は、描画オブジェクトを作るときに祖先の BackdropGroup を探し、そのキーを使います。3.29.3 のウィジェットテストでは、ウィジェット側の backdropGroupKey は null のままで、3つの描画オブジェクトがすべて同じキーを持っていました。キーを自分で作って渡す必要はありません。逆に BackdropGroup の外に置くとキーが null になり、エラーは出ないまま通常の BackdropFilter として動きます。共有されていないことに気づきにくいので、グループの置き場所は確認してください。
同じく Impeller 前提の機能として、子ウィジェットに独自のシェーダーをかける ImageFilter.shader も追加されました。package:flutter_shaders の AnimatedSampler に近い機能ですが、背景フィルターにも使える点が違います。
Cupertino の追加:ナビゲーションバーの bottom とシート
CupertinoNavigationBar と CupertinoSliverNavigationBar に bottom が追加され、検索欄やセグメントコントロールをバーの下に置けるようになりました。スライバー版では bottomMode で、スクロール時に縮めて隠すか常に表示するかを選べます。下にドラッグして閉じる iOS 風のモーダルシートは、CupertinoSheetRoute と、ネスト用ナビゲーションまで設定済みで開く showCupertinoSheet で作れます。
import 'package:flutter/cupertino.dart';
class SheetDemo extends StatelessWidget {
const SheetDemo({super.key});
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: Text('一覧'),
bottom: PreferredSize(
preferredSize: Size.fromHeight(44),
child: CupertinoSearchTextField(),
),
),
child: Center(
child: CupertinoButton(
child: const Text('シートを開く'),
onPressed: () => showCupertinoSheet<void>(
context: context,
pageBuilder: (context) => const CupertinoPageScaffold(
child: Center(child: Text('下にドラッグで閉じる')),
),
),
),
),
);
}
}
3.29.3 のウィジェットテストでは、ボタンを押すとシートが開き、テキストを下へ500ピクセルドラッグするとシートが閉じて画面から消えることを確認しました。ほかに、大きなタイトルを表示する CupertinoNavigationBar.large コンストラクタ、スライバー版の途中スクロール時のスナップ、ダークモードの CupertinoAlertDialog の見た目の改善も入っています。iOS 26 以降の Liquid Glass への対応状況はFlutterのLiquid Glass対応はどこまで来たか|cupertino_ui 1.0でも入らない現状と代替手段【2026年8月時点】を参照してください。
SelectionListener による選択範囲と状態の取得
SelectionArea や SelectableRegion の中で、ユーザーが選んだ範囲を受け取れるようになりました。SelectionListener で対象の子を包み、SelectionListenerNotifier を購読すると、SelectionDetails から選択の状態と開始・終了オフセットが取れます。選択した語に応じてツールバーやボタンを出し分けたいときに使います。
import 'package:flutter/material.dart';
class SelectionDemo extends StatefulWidget {
const SelectionDemo({super.key});
@override
State<SelectionDemo> createState() => _SelectionDemoState();
}
class _SelectionDemoState extends State<SelectionDemo> {
final _notifier = SelectionListenerNotifier();
String _status = '未選択';
@override
void initState() {
super.initState();
_notifier.addListener(() {
final d = _notifier.selection;
setState(() {
_status = '${d.status.name} ${d.range?.startOffset}-${d.range?.endOffset}';
});
});
}
@override
void dispose() {
_notifier.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
SelectionArea(
child: SelectionListener(
selectionNotifier: _notifier,
child: const Text('Flutter 3.29 adds SelectionListener'),
),
),
Text(_status),
],
);
}
}
3.29.3 でマウスのドラッグを模したテストを実行すると、表示は「未選択」から「uncollapsed 0-4」(選択済み・オフセット0〜4)に変わりました。選択の確定前か確定後かを知りたいときは、祖先の SelectionArea の状態を返す SelectableRegionSelectionStatusScope を使います。
Material の変更:遷移アニメーションと 2024年版 M3 デザイン
FadeForwardsPageTransitionsBuilder が Material 3 の新しいページ遷移として追加されました。最近の Android の遷移に合わせたもので、入ってくるページが右から左へスライドしながらフェードインします。
Slider と CircularProgressIndicator/LinearProgressIndicator は2024年版の Material Design 3 の見た目が入りましたが、3.29.3 の既定は従来の見た目のままです。新しいデザインにするには year2023 を false にします。テーマで一括指定する場合は次のとおりです。
import 'package:flutter/material.dart';
final theme = ThemeData(
pageTransitionsTheme: const PageTransitionsTheme(
builders: {
TargetPlatform.android: FadeForwardsPageTransitionsBuilder(),
},
),
// 2024年版のM3デザインに切り替える(既定は true=従来の見た目)
sliderTheme: const SliderThemeData(year2023: false),
progressIndicatorTheme: const ProgressIndicatorThemeData(year2023: false),
// ThemeData.dialogBackgroundColor は 3.29 で非推奨
dialogTheme: const DialogThemeData(backgroundColor: Colors.white),
);
このコードを 3.29.3 で flutter analyze にかけると、year2023 自体にも deprecated_member_use が出ます。新旧デザインを切り替えるための移行用フラグで、将来は削除される前提です。新デザインを使うなら false にしたうえで、警告は残ることを了解しておきます。
テーマの正規化の一環として ThemeData.dialogBackgroundColor は非推奨になり、DialogThemeData.backgroundColor へ移ります。3.29.3 で旧プロパティを使うと、flutter analyze が deprecated_member_use を出しました。置き換えは dart fix --apply で自動化できます。ボタンの ButtonStyleButton.iconAlignment も、ButtonStyle 側に移ったため非推奨です。Material 3 全体の仕様と各実装の対応状況はMaterial Design 3(Material 3)とは?Expressiveの変更点と各実装の対応状況にまとめています。
Dart 3.7:ワイルドカード変数と新しいフォーマッタ
3.29 に同梱される Dart 3.7 では、ワイルドカード変数と、型境界を使った型推論が入りました。どちらも pubspec.yaml の SDK 制約の下限を 3.7 以上(sdk: ^3.7.0)にしたパッケージでだけ有効です。
ワイルドカード変数 _ の書き方
ローカル変数と引数の _ は束縛されない名前になり、同じスコープで何度宣言しても衝突しません。その代わり、値を読むことはできなくなります。トップレベル変数やクラスのメンバーの _ は従来どおりです。
// Dart 3.7 以降(sdk: ^3.7.0)でだけ通るコード
int countPairs(Map<String, int> m) {
var n = 0;
m.forEach((_, _) => n++); // 同じスコープで _ を2回宣言できる
return n;
}
void main() {
var _ = 1;
var _ = 2; // 再宣言しても衝突しない
print(countPairs({'a': 1, 'b': 2}));
}
このコードは sdk: ^3.7.0 のプロジェクトでは解析も実行も通り、2 を出力しました。SDK 制約の下限を 3.6 にすると、dart analyze が2か所の _ の二重宣言を duplicate_definition エラーとして報告します。3.6 以前のコードで _ を読んでいた箇所は、下限を 3.7 に上げた時点でエラーになるので、書き換えが必要です。
tall style フォーマッタと page_width の設定
dart format は、末尾カンマを付けたときに近い縦長のスタイル(tall style)に変わり、カンマの追加と削除もフォーマッタが行います。新旧どちらのスタイルになるかはファイルの言語バージョンで決まり、3.6 以下なら従来のスタイル、3.7 以上なら tall style です。つまり SDK 制約を 3.7 に上げると、フォーマットの差分がまとめて出ます。
言語バージョンは package_config.json から判定されるため、dart pub get を実行する前に整形すると正しく判定されません。CI でフォーマットを検査しているなら、検査の前に dart pub get を入れてください。1行の幅は analysis_options.yaml でプロジェクト単位に指定できるようになりました。
# analysis_options.yaml(Dart 3.7 から読まれる)
formatter:
page_width: 100
3.29 で必要になる移行作業
破壊的変更の一覧(Released in Flutter 3.29)に載っている項目のうち、ビルドが通らなくなるものから順に確認します。
Flutter Gradle プラグインの命令的な apply の削除
3.19 から非推奨だった、スクリプトで Flutter Gradle プラグインを適用する方式(apply from:)が削除されました。3.16 より前に作って移行していない Android プロジェクトが対象です。以前の版で「You are applying Flutter’s main Gradle plugin imperatively」という警告が出ていたプロジェクトは、3.29 では警告で済まず、flutter.gradle が GradleException を投げてビルドが失敗します。宣言的な plugins {} ブロックへの移行が必要です。同じく、v1 Android embedding の Java API も削除されました。
2025年4月30日で開発終了した公式パッケージ
公式ブログは、次の6パッケージのサポートを2025年4月30日に終了すると予告していました。pub.dev の API で確かめると、2026年10月時点で6本とも discontinued になっており、最終版の published はすべて2025年5月6日です。
| パッケージ | 最終版 | pub.dev の後継指定 |
|---|---|---|
| flutter_markdown | 0.7.7+1 | flutter_markdown_plus |
| flutter_adaptive_scaffold | 0.3.3+1 | なし |
| palette_generator | 0.3.3+7 | なし |
| flutter_image | 4.1.13 | なし |
| ios_platform_images | 0.2.4+4 | なし |
| css_colors | 1.1.7 | なし |
後継が指定されているのは flutter_markdown だけです。ほかの5本は、コミュニティのフォークを探すか、機能を自前で持つかを決める必要があります。
WebGoldenComparator の非推奨化と描画差分の確認
Web のゴールデンテストで使う WebGoldenComparator は非推奨になりました。前述の ImageFilter.blur のタイルモード、Slider と進捗インジケーターの M3 更新も、破壊的変更の一覧に含まれています。見た目の差分がゴールデンテストで出たら、まずこの3つを疑ってください。
3.29 に留まるか上げるかの判断
3.29 系は hotfix の対象から外れていて、今後セキュリティ修正や不具合修正は入りません。2026年10月時点の安定版は 3.47.5(2026年9月18日公開・Dart 3.13.4)で、3.29 から数えて6回後の安定版系列です。新しい機能が要らなくても、次のどれかに当てはまるなら上げる計画を立てたほうがよいと判断します。
- Xcode 27 でビルドする必要がある:iOS 27 SDK でビルドした UIScene 未対応のアプリは、iOS 27 以降で起動できません。Flutter 側の UIScene 対応は 3.38 からです(Flutter UIScene移行手順|SceneDelegate対応と自動移行が効かない条件【3.38〜3.47・Xcode 27】)。
- 使っているパッケージの新しい版が、Flutter の下限を上げている:たとえば flutter_riverpod 3.4.1 は Dart ^3.12.0 を要求するため、安定版の Flutter では Dart 3.12 を同梱する 3.44 系以降が必要です。
- スレッド統合のオプトアウトを入れている:3.38 以降では起動しなくなるので、先に原因を直す必要があります。
途中の版で何が変わったかは、版ごとの記事で追えます。Flutter 3.41が2026年2月安定版で示した開発者体験の改善ポイント、Flutter 3.44とは?SPM既定化とHCPPで変わる移行判断【2026年7月時点】、そして最新の 3.47 です。一度に6系列分上げるより、3.35 まで上げてテストし、スレッドの設定を外してから 3.38 以降へ進むと、どの変更で壊れたかを切り分けやすくなります。
よくある質問
Flutter 3.29.3 の Dart のバージョンは?
Dart 3.7.2 です。3.29.0 と 3.29.1 は Dart 3.7.0 で、3.29.2 から 3.7.2 になりました。
Flutter 3.29 はいつリリースされましたか?
3.29.0 は2025年2月12日(UTC)に安定版として公開されました。最終パッチの 3.29.3 は2025年4月14日です。
Flutter 3.29 で iOS を Skia に戻せますか?
戻せません。3.29 で iOS のバックエンドから Skia が削除され、FLTEnableImpeller の指定は効かなくなりました。Android は 3.29 時点でも EnableImpeller のメタデータで Skia を選べます。
Dart をメインスレッドで動かす変更は無効にできますか?
3.29〜3.35 では、Android の DisableMergedPlatformUIThread、iOS の FLTEnableMergedPlatformUIThread で無効にできます。3.38.0 では、Android の前者を true、iOS の後者を false にしてスレッド統合を無効化しようとすると、起動時にエラーになります。
Flutter 3.29 の次のバージョンは?
3.32.0 です。2025年5月20日に公開され、Dart 3.8.0 を同梱しています。