sdk

What does it do?

The Dart SDK includes the Dart VM (virtual machine), JavaScript and Wasm (WebAssembly) compilers, analysis, and core libraries. [1] For devices, Dart Native includes a Dart VM with JIT (just-in-time) compilation and an AOT (ahead-of-time) compiler that produces machine code. [2] For the web, Dart Web includes a development compiler and a production compiler, and Dart code can be compiled to JavaScript or WebAssembly. [3a][3b]

Activity, over time

Daily observations from the public event archive.

Attention

Daily stars & forks

Loading attention chart

Star accumulation

Cumulative stars

Loading star accumulation chart

Pull requests

Daily opens & merges

Loading pull requests chart

Conversations

Daily issues & comments

Loading conversations chart

Community

Daily accounts & reviews

Loading community chart

Releases

Daily releases

Loading releases chart

Mentions

17posts · 30d
Nov 40 posts
  1. X · · @Anipy1

    @1440000bytes @cakewallet Btw cake's Android/Windows/Linux build is vulnerable & affected by TLS MitM github.com/dart-lang/sdk/security/advisories/GHSA…

    1 like · 156 views
  2. Flutter 3.47.8 fixes a TLS flaw on Android and Windows Compromised eMudhra CA certificates could let attackers intercept HTTPS traffic from Flutter/Dart apps. Upgrade, rebuild and redeploy. Source: Dart SDK advisory github.com/dart-lang/sdk/security/advisories/GHSA… #Flutter

    1 like · 19 views
  3. Flutter 3.47.8 tambal celah TLS di Android & Windows Sertifikat CA eMudhra yang bocor bisa dipakai untuk menyadap koneksi HTTPS aplikasi Flutter/Dart. Upgrade, build ulang, lalu rilis ulang aplikasinya. Sumber: Dart SDK advisory github.com/dart-lang/sdk/security/advisories/GHSA… #Flutter

    1 like · 25 views
  4. Reddit · · r/FlutterDev · u/chonli

    TLS MitM vulnerability on Android, Windows, and Linux due to compromised eMudhra intermediate CA certificates Hi A security vulnerability affects Dart and Flutter applications that establish TLS/HTTPS connections on Android, Windows, and certain Linux environments. Compromised eMudhra intermediate certificate authorities could allow an attacker intercepting network traffic to generate fake certificates for legitimate domains. Versions earlier than Dart 3.13.7 and Flutter 3.47.8 are affected, including certain beta versions. Web, iOS, and macOS applications are not affected according to the published advisory. It is recommended to update the SDK, recompile the applications, and redeploy the affected binaries. the full security advisory

    6 points · 3 comments
  5. Zenn · · @koji_1009

    dart:ioと端末のネットワーク設定 はじめに 2026年10月、eMudhraが発行した中間CA証明書が、鍵生成時の乱数の弱さによって侵害されていたことが公表されました。Dart SDKにも、この件のセキュリティアドバイザリが出ています。 github.com/dart-lang/sdk/security/advisories/GHSA… アドバイザリによると、AndroidとWindowsの dart:io は、SDKに組み込まれたBoringSSLで証明書チェーンを検証しており、OSが管理する中間証明書のブロックリストを読みません。そのため対処には、修正済みのSDK(Dart 3.13.7 / Flutter 3.47.8)でアプリを再ビルドし、配布し直す必要があります。一方で、iOSとmacOSは、AppleのSecurity.frameworkで検証しているため影響を受けません。Android端末には、Google Play Services経由で同等の更新が配信されていますが、dart:io で通信するアプリはその更新を使えません。 設計がそうなっているから、といえばそうなのですが、直感に反します。AndroidでもiOSのように、OSで管理される証明書を利用できないのでしょうか。 一部で知られているように、端末のproxy設定が反映されない問題があります。気づくタイミングが切羽詰まっている状況になることも多く、知っている方は若干辛い記憶なのではないでしょうか? flutter#26359 これも不思議です。Android端末上から通信をしているのに、その端末に設定されたproxyが反映されません。AndroidのNative SDKを使って開発していた頃には、全く意識する必要がなかったのに、です。 そして、結構厄介です。開発者の手元だと問題が起きないが、QAメンバーからの問い合わせで発覚したり。ユーザーから、特定環境で利用できない報告で発覚したりします。どうして。 なにが原因なのか dart:ioにおける、以下の特徴が原因です。 socketからTLSまで、ネットワーク処理をDart SDKの中に自前で実装している dart:io の実装からはJNIを呼べないため、AndroidのJava API(proxyの設定や TrustManager)に手が届かない proxyは、http_proxy などの環境変数しか見ず、OSの設定画面で指定したproxyを読まない Androidでは、ルート証明書を端末のディレクトリから直接読み、証明書の検証もSDK内蔵のBoringSSLで行う つまりAndroidでは、自前の実装がOSの仕組みを素通りするので、OSのネットワーク設定が効きません。それなら、まあ、しょうがないか…。 proxy、ルート証明書、証明書の検証 Security advisoriesにもある通り、今回の問題はAndroidとWindowsで発生し、iOS・macOSでは発生していません。これはiOS・macOSの dart:io が、証明書の検証をOSのSecurity.frameworkに任せていることに起因しています。 以下、よくわかっていなかったのでOpusにコードを読ませながら確認してみました。 proxy: 環境変数しか見ない (AndroidとiOS) HttpClient には、接続先のURLを受け取って、使うproxyを文字列で返す findProxy という関数を設定できます。 api.flutter.dev 返すのは、"PROXY host:port"(proxyを使う)か "DIRECT"(直接つなぐ)です。 この関数のデフォルトの findProxyFromEnvironment が見るのは、http_proxy・https_proxy・no_proxy という環境変数だけです。ターミナルで export http_proxy=... と設定する、あの環境変数です。この処理は、AndroidとiOSで共通です。 github.com/dart-lang/sdk/blob/3.13.7/sdk/lib/_htt… 本来、AndroidのWi-Fi設定やiOSの設定アプリで指定したproxyは、環境変数としては渡されません。このため、OSのAPIを経由して取得する必要があります。結果、dart:io においては、proxyの検知が働かないようです。 http#1414 sdk#41376 自前で実装しようとしても、ちょっとした壁があります。findProxy は同期関数です。AIに調べてもらったのですが、AndroidはPAC(Proxy Auto-Config)を同期処理で実装できそうです。しかし、iOS・macOSでPACを評価するAPIは、非同期になっています。結果、両OSをサポートする実装が難しくなっています。1 ルート証明書: ディレクトリを直接読む (Android) Android向けのTLS処理は、Linuxと同じ security_context_linux.cc の中にあります。証明書は、端末のディレクトリから直接読みます。2 github.com/dart-lang/sdk/blob/3.13.7/runtime/bin/… OSの設定を通らないので、こんな問題が出ています。 dart-lang/sdk#48056: 設定で無効にしたCA証明書を信頼し続ける dart-lang/sdk#50435: ユーザーが入れたCA証明書を信頼しない Android 14からはルート証明書が、Google Play system updatesで更新されるConscryptのAPEXモジュールに移りました。Dart 3.13.7から /apex/com.android.conscrypt/cacerts を読むようになるそうなので、この問題は徐々に解消していくと思われます。3 証明書の検証: OSのTrustManagerを通らない (Android) 冒頭のeMudhraに関する諸問題の、根本がここです。検証をSDKに内蔵するBoringSSLが行なっているため、Androidの TrustManager を利用しません。 結果、OSが配る中間証明書のブロックリストが効かない、という事態になったようです。Flutter 3.47.8(Dart 3.13.7)での修正は、次の2つです。 dart/568000: Dartに内蔵するBoringSSLを更新し、侵害されたeMudhraの中間CA証明書をブロックする dart/64696: Android 14以降で、更新可能なConscrypt APEXのルート証明書ストアを使う 中間証明書のブロックリストは、アプリに組み込まれたBoringSSLの中にあります。ルート証明書はOSの更新に追従するようになりましたが、中間証明書は追従しません。もちろん中間証明書のブロックリストが頻繁に更新されるなんてことはない、はずです。ただ、この違いは把握しておく必要があると思われます。 一方で、cronet_httpを使っていた場合は、証明書の検証をAndroidの TrustManager が行います(後述の補足を参照)。Android端末にはGoogle Play Services経由で同等の更新が配信されているので、Cronetで通信していたアプリは、SDKの更新やアプリの再ビルドを待たずに守られていたことになります。ただし、Google Play Servicesがない端末など、OSの更新を受け取れない端末は対象外です。 proxyの深掘り 証明書については、改善された点がある一方で、一層の覚悟も求められることになりました。では、proxyはどうでしょうか? sdk#50434 proxyの問題は、P3のIssueで追跡されています。issueのコメントを確認すると、AndroidではJNIを呼ぶしかない、という点が問題のようです。 We could also solve this issue in HttpClient. This would actually be fairly easy on iOS but harder on Android (AFAIK, the only way would be to make JNI calls to get the proxy configuration). sdk#50434 There is currently not a good way to make JNI calls from the dart:io implementation. flutter#20376 Android OSがJavaやKotlin向けに提供しているAPIなので、FFIではなくJNIが必要になり難しい、ということと筆者は理解しています。これはffigenとjnigenの安定度の違いを見たことがある方なら、まあそうだろうなって印象になると思います。 というわけで、何かしらの回避策が必要です。 かつての回避策: system_proxy かつて、Flutterのアプリを手探りで実装していた頃には、system_proxy などでOSのproxy設定を取ってくるのが典型的な対応でした。main() でなんか書いたことがあるな? って方は、多分これです。 github.com/kaivean/system_proxy/blob/0ad8536e39e3… ただ、このパッケージがやるのはproxyの取得だけで、使い方はアプリ任せです。 proxyを通すと、今度はTLSが問題になります。CharlesやTLSインスペクションのように、proxyがHTTPSを中継する環境では、proxyの証明書を信頼しないと通信できません。でも dart:io は、ユーザーが入れた証明書を信頼しません。そこで、こういうコードが書かれがちです。 HttpClient() ..findProxy = (uri) => 'PROXY $host:$port' ..badCertificateCallback = (cert, host, port) => true; badCertificateCallback が true を返すと、信頼できない証明書でも接続します。つまり、どんな証明書でも通るので、中間者攻撃に無防備になります。もちろん、適切に実装をすれば問題はありません。4 ただ、本来OSが適切に管理するべき通信が、アプリ実装者の手に委ねられてしまうのは危険です。2026年も終わろうとしている現在、そして、あれこれセキュリティに注目が集まる現在では推奨されないと感じています。 cronet_httpとcupertino_http OSが管理するproxyや証明書を使うのであれば、多くのAndroidやiOSのネイティブアプリと同じ通信経路を辿ればOKです。と書くとMethodChannelでリクエストを送ることをイメージするかもしれません。大丈夫です。Dartチームが用意しています。 パッケージ プラットフォーム 中身 cronet_http Android Cronet(Chromiumのネットワークスタック) cupertino_http iOS / macOS Foundation URL Loading System(URLSession) どちらのREADMEも、dart:io に対する利点の1つ目にproxy対応を挙げています。 cronet_http: "It automatically supports Android platform features such as HTTP proxies." cupertino_http: "It automatically supports iOS/macOS platform features such as VPNs and HTTP proxies." Charlesに通信が出ないという flutter/flutter#20376 も、iOSでは cupertino_http が使えるよ、というコメントでcloseされています。また、特にAndroidであれば、 cronet_http を使うことで証明書の問題も回避することができます。OkHttp版の開発も進んでいるので、この機会にぜひ検討してみてください。 補足 Opusに調べてもらった、それぞれのツールでproxyと証明書がどう扱われるかになります。本題からズレるので、気になる方はどうぞ。 Cronet(cronet_http)は、Androidのproxyと証明書をどう扱っているか proxy Cronetは初期化のときに、CreateProxyConfigService でproxyの設定の取得元を作ります。ここで呼ぶ CreateSystemProxyConfigService は、Androidでは ProxyConfigServiceAndroid を返します。 github.com/chromium/chromium/blob/55adf20e5753fc9… ProxyConfigServiceAndroid は、JNIでJavaの System.getProperty を呼び、次のシステムプロパティからproxyの設定を組み立てます(proxy_config_service_android.cc#L71-L173)。コード中のコメントによると、Javaの標準の ProxySelector とほぼ同じ読み方です。 http.proxyHost / http.proxyPort、https.proxyHost / https.proxyPort(なければ proxyHost / proxyPort) socksProxyHost / socksProxyPort http.nonProxyHosts など(proxyを使わないホストの一覧) 設定の変更は、Java側の ProxyChangeListener で受け取ります。PACが設定されている場合、CronetはPACのURLを使わず(set_exclude_pac_url(true))、Androidが用意するローカルのHTTP proxyに任せます(crbug.com/432539)。そのため、PACを評価する仕組み(proxy resolver)自体を持ちません(CreateWithoutProxyResolver)。 証明書の検証 Android向けのChromiumは、Chrome Root Storeを使う独自の検証器と、OSの検証器を選べます。ただし、Cronetのビルドでは chrome_root_store_optional = is_android && !is_cronet_build となり、この選択肢がありません。 github.com/chromium/chromium/blob/5691202e214341a… そのため CreateSystemVerifyProc が使われ(cert_verifier.cc#L30-L64)、Androidでは CertVerifyProcAndroid になります(cert_verify_proc.cc#L378-L379)。CertVerifyProcAndroid はJNIでJavaの AndroidNetworkLibrary.verifyServerCertificates を呼び(cert_verify_proc_android.cc#L100、AndroidNetworkLibrary.java#L120-L127)、最後は X509Util が、OSの TrustManagerFactory のデフォルトのトラストマネージャーで checkServerTrusted を呼びます。 github.com/chromium/chromium/blob/195962358a83d3d… ルート証明書の選び方も、チェーンの検証も、Androidの仕組みに任されているわけです。 なお、ここで読んでいるのはChromiumのソース(Cronetを同梱する場合のもの)です。Google Play Servicesが提供するCronetも同じ作りだと考えられますが、そのソースは公開されていません。 URLSession(cupertino_http)は、iOSのproxyと証明書をどう扱っているか proxy URLSessionConfiguration の connectionProxyDictionary は、デフォルトが NULL で、その場合はシステムの設定が使われます。 The default value is NULL, which means that tasks use the default system settings. developer.apple.com cupertino_httpは、connectionProxyDictionary を設定する公開APIを持たず、内部でも設定していません。そのため、defaultSessionConfiguration() などから作った CupertinoClient は、システムのproxy設定に従います。 証明書の検証 cupertino_httpは、認証チャレンジを受け取るdelegate(URLSession:task:didReceiveChallenge:completionHandler:)を実装していません。この場合、URLSessionはデフォルトの処理を行います(NSURLSession.h のコメント)。サーバー証明書の検証に、アプリ側の判定は入りません。 httpパッケージとdioでの差し替え 筆者がネイティブのHTTPクライアント推しなので、簡単ではありますが、置き換え方法を紹介します。 httpパッケージ package:http の Client() は、Web以外では IOClient、つまり dart:io の HttpClient を使います。何もしなければ、同じ問題を抱えたままです。 github.com/dart-lang/http/blob/http-v1.5.0/pkgs/h… READMEの "Choosing an implementation" のとおり、プラットフォームごとに Client を差し替えます。 import 'package:cronet_http/cronet_http.dart'; import 'package:cupertino_http/cupertino_http.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; import 'package:http/io_client.dart'; Client createHttpClient() { switch (defaultTargetPlatform) { case TargetPlatform.android: final engine = CronetEngine.build(); return CronetClient.fromCronetEngine(engine, closeEngine: true); case TargetPlatform.iOS || TargetPlatform.macOS: final config = URLSessionConfiguration.defaultSessionConfiguration(); return CupertinoClient.fromSessionConfiguration(config); case TargetPlatform.fuchsia || TargetPlatform.linux || TargetPlatform.windows: return IOClient(); } } あとは Client をRiverpodのProviderで配布する、などすればOKです。もしも http.get() や Client() を直接呼んでいるところがあり、置き換えが難しいならば、runWithClient で包みます。ただし、Flutterではコールバックが同じZoneで実行される保証がないため、包んだ範囲でも IOClient に戻ることがあります。 pub.dev dio dioのデフォルトも、dart:io を使う IOHttpClientAdapter です。native_dio_adapter を使うと、cronet_http と cupertino_http に切り替えることができます。 final dio = Dio()..httpClientAdapter = NativeAdapter(); Androidでは CronetAdapter、iOS・macOSでは CupertinoAdapter、それ以外では従来どおり dart:io を使います。5 注意点 見逃しがちな点がいくつかあります。 観点 何が変わるか 見直すこと 画像の読み込み Image.network は dart:io のまま Client を渡せるパッケージに置き換える User-Agent クライアントごとにデフォルトの値が違う すべてのクライアントで明示的に指定する 例外 SocketException で捕まえられなくなる。dioではエラーの種類が変わる ClientException で捕まえる。DioException.type で分けている処理を見直す 画像の読み込み Flutter frameworkは任意のパッケージに依存しないので、Image.network は dart:io の HttpClient を直接使います。差し替える口はありません。6 画像も、Client を渡せるパッケージに置き換える必要があります。以下のようなパッケージが候補です。 パッケージ Client の差し替え ディスクキャッシュ http_image_provider できる なし extended_image できない(内部で dart:io の HttpClient を持つ) あり cached_network_image できる(flutter_cache_managerの HttpFileService) あり taro できる(TaroHttpClient) あり http_image_providerは、httpパッケージのREADMEが紹介している Flutter HTTP example application で使われています。一応、公式が提案しているパッケージです。 また cached_network_image は、ウィジェットごとに cacheManager: を渡すと渡し忘れが出るので、defaultCacheManager ごと差し替えるのが確実です。7 CachedNetworkImageProvider.defaultCacheManager = CacheManager( Config( 'networkImages', fileService: HttpFileService(httpClient: createHttpClient()), ), ); ちなみに、筆者は「画像だけ dart:io に戻る」状態をなんとかするだけなら、もっと軽量で行けるだろうと taro を作ってメンテナンスしています。デフォルトは dart:io ですが、TaroHttpClient を実装すれば Client に差し替えられます。サンプルも書いてあるので、よければご利用ください。 User-Agent 何も指定しないと、User-Agentはこうなります。 クライアント デフォルトのUser-Agent dart:io Dart/3.x (dart:io) Cronet <パッケージ名>/<versionCode> (Linux; U; Android 15; ja_JP; <端末名>; Build/<ID>; Cronet/<バージョン>) URLSession <アプリ名>/<ビルド番号> CFNetwork/<バージョン> Darwin/<バージョン> 「APIはCronet、画像は dart:io」のように混ざると、同じアプリから2種類のUser-Agentが飛びます。揃えたいなら、クライアントごとに指定します。 // Android CronetEngine.build(userAgent: userAgent); // iOS / macOS URLSessionConfiguration.defaultSessionConfiguration() ..httpAdditionalHeaders = {'User-Agent': userAgent}; // それ以外(dart:io) HttpClient()..userAgent = userAgent; native_dio_adapterなら、createCronetEngine と createCupertinoConfiguration に同じ設定を渡します。 例外 失敗したときの例外の型も変わります。 IOClient CronetClient CupertinoClient ClientException(SocketException も実装) CronetException とそのサブクラス NSErrorClientException IOClient の例外は、互換性のために SocketException も実装しています。なので on SocketException catch で捕まえているコードは、差し替えると素通りします。3つに共通するのは ClientException です。 dioでは、タイムアウトは常に receiveTimeout、通信の失敗は unknown になり、connectionTimeout や connectionError は返ってきません。 その他 cronet_httpとcupertino_httpが対応しているのは、Android・iOS・macOSだけです。WindowsのWinHTTP対応の要望(dart-lang/http#1837)には、Dartチームが取り組む可能性は低い、という回答でした。 おわりに package:http、というより dart:io には、あまり語られないものの把握しておくべきクセがあります。proxyや証明書のことを考えると、ネイティブのHTTPクライアントを利用するのが安牌なのではないかなと思っています。 🤏知ってることをまとめようと思い、AIに下調べと裏どりをさせてみたところ、自分も知らない話がたくさん出てきました。アプリ作るの、難しくない…? 脚注 dart-lang/sdk#44971 ↩︎ コード中のコメントによると、証明書をバイナリに組み込まないのは、バイナリのサイズを約240KB減らすためです。 ↩︎ それまでは /system/etc/security/cacerts を読んでいたそうです ↩︎ 環境ごとに適用を切り替えたり、証明書を限定したりすればOKのはず。 ↩︎ dio#2456 を入れたので、一応timeoutも効きます。 ↩︎ debugNetworkImageHttpClientProvider という差し替え口はありますが、デバッグビルド専用です。 ↩︎ flutter_cache_managerへの直接の依存が必要です。ディスクに保存するときの縮小(maxWidthDiskCache)も使う場合は、ImageCacheManager をmixinしたクラスにします。 ↩︎

  6. X · · @kevmoo

    How was YOUR Friday? github.com/dart-lang/sdk/security/advisories/GHSA… (I did a tiny part of this, honestly. Random to have your name on such things.) If you haven't heard, google for `ecc "the number 4"`. 😲🤦🤷

    1 like · 346 views
  7. Flutterの修正版が来たら即アプデ推奨🙏 sdk#64644

    3 likes · 203 views
  8. Can you migrate to material_ui yet? What changed, and why For years, package:flutter/material.dart came with the SDK. You installed Flutter, and Material came with it, same version, same release schedule, no decision to make. That is changing. Since Flutter 3.47, Material and Cupertino also exist as two packages on pub.dev,material_ui and [cupertino_ui] (pub.dev), published by flutter.dev and versioned on their own. The SDK still ships its own copy for now, but that copy is frozen. The three architectural layers are untouched. What moved is the top of the framework layer. !Flutter architecture before the split: Material and Cupertino sit inside the framework layer, above Widgets !Flutter architecture after the split: material_ui and cupertino_ui are packages above the framework, whose top layer is now Widgets Material and Cupertino used to sit inside the framework, on top of widgets. You can now use them above it, as ordinary packages you add to pubspec.yaml. Why now Three reasons, all from the announcement by Craig Labenz on 9 September 2026. 1. Upgrading Flutter meant redoing your UI Material shipped inside the SDK. So a Flutter upgrade, even one you wanted only for a security patch, brought Material changes with it. You could not take one without the other. The team is blunt about what that cost: > *a major source of developer friction that kept many teams on older Flutter > releases* and > *the task could consume multiple weeks of developer effort and bottleneck > entire repositories* Teams stayed on old Flutter versions on purpose, because moving up meant weeks of fixing screens. Staying behind also meant missing the security patches they wanted in the first place. 2. A fix could wait sixteen weeks Flutter ships a stable release every three months, and Material shipped with it. So a Material fix had to catch the release cutoff. The post gives the worst case: > *landing code one minute after the stable release cutoff can introduce a 16 > week delay until that change sees the light of a stable release* One minute late meant sixteen weeks of waiting. As separate packages, material_ui and cupertino_ui are planned to release weekly. And the post says work is already underway on official implementations of Liquid Glass and Material 3 Expressive, Apple's and Google's current design languages. 3. Material was keeping the useful parts to itself This reason is less obvious than the other two, but its effect lasts the longest. Flutter's core is the widgets library. Material is built on top of it. When the Material team needed something the core did not have, they added it to Material. That was faster, and it worked. But only Material got it. > *it proved too tempting to build foundational functionality in those design > libraries* Other design systems exist. The post names seven: macos_ui, fluent_ui,yaru, arna, chicago, VSP, shadcn. They needed some of the same pieces, and could not reuse Material's. Now that Material is a package like the others, the missing pieces have to go into the core instead. The official migration guide puts it this way: > *Decoupling lays the groundwork for a style-neutral Flutter core widget > catalog, making it easier to build and maintain custom design systems.* In plain terms: make the core work for any design system, not just Material and Cupertino. The team's own description of the old arrangement is the clearest line in the post. Material and Cupertino had started to feel: > more soldered-on than just included And for years, improving this system was *"a top request from Flutter developers"*. --- What you actually get Version 1.0.0 of material_ui was a copy of what was already in the SDK. The announcement says so directly: > *released exact replicas on pub.dev as the 1.0.0 versions of > pkg:material_ui and pkg:cupertino_ui* It had the same widgets, with the same names and the same behaviour. Migrating is not meant to change how your app looks. Here is how the team describes the move: > *Our expectation is that this will be a drop-in maneuver, but please file an > issue if you encounter any trouble.* Note the word "expectation". We will come back to it. What changes in your code One line per file: // before import 'package:flutter/material.dart'; // after import 'package:material_ui/material_ui.dart'; For most files, that is the whole change. Scaffold, AppBar, TextField, ThemeData all keep their names. Are they really shipping weekly? Speed was the reason for the split. So it is worth checking whether the speed arrived. Counting from pub.dev on 8 October 2026: | Package | Latest | Releases after 1.0.0 | One every | |---|---|---|---| | material_ui | 1.6.0 | 7, over 55 days | 8 days | | cupertino_ui | 1.1.2 | 4, over 55 days | 14 days | material_ui is shipping close to the weekly pace it promised, and a long way from a three-month cycle. cupertino_ui moves more slowly. So on paper, migrating is one import line and nothing else. The rest of this article is what happened when I ran it. --- The migration, step by step The app under test A small app with no third-party UI package. If something breaks, the migration is the only suspect. It contains the pieces the migration touches: Material and Cupertino widgets, translations generated from .arb files, a language switcher, a barrel file that exports both design libraries, and two widgets that take a ColorScheme or a CupertinoThemeData as a constructor argument. Ten widget tests cover it. All ten pass before we start. The code is in the repository, with a tag for each state: first-app-without-migration, after-dart-fix and after-localizations-fix. Every command output quoted below is saved in its measurements/ folder. Step 1: ask before you apply dart fix --dry-run --code=migrate_design_widgets 17 proposed fixes in 14 files. --dry-run changes nothing. It only lists what the tool plans to do. Sixteen fixes come from the migration rule. One comes from a second rule, missing_dependency, which targets pubspec.yaml. Step 2: apply dart fix --apply --code=migrate_design_widgets 17 fixes made in 14 files. The same seventeen. Every change in the Dart files is an import line, like this one: -import 'package:flutter/material.dart'; +import 'package:material_ui/material_ui.dart'; No widget, no constructor, no type was touched. The pubspec.yaml was updated too, with any as the version: + cupertino_ui: any + material_ui: any any accepts every version, including a future one that breaks your app. I replaced it with real constraints: cupertino_ui: ^1.1.2 material_ui: ^1.6.0 What the tool did not touch export directives. The barrel file is not in the diff: // lib/core/ui.dart, unchanged after the migration export 'package:flutter/cupertino.dart' hide RefreshCallback; export 'package:flutter/material.dart'; The tool rewrites import lines, not export lines. This was reported in dart-lang/sdk#63968. The issue is marked as closed, but with Dart 3.13.5 the exports were still left as they were. The next part, Where it stops working, shows what this costs. The localization import. lib/app/app.dart had two SDK imports: material.dart and flutter_localizations.dart. Only the first one was rewritten. That is where the only error comes from. The only error This is the top of app.dart after the tool: import 'package:material_ui/material_ui.dart'; // rewritten import 'package:flutter_localizations/flutter_localizations.dart'; // not touched Both libraries define a class called GlobalMaterialLocalizations. flutter_localizations still has the old one, and material_ui brought its own copy of the Material translations. The file imports both, so Dart cannot tell which one you mean: error - lib/app/app.dart:66:9 - The name 'GlobalMaterialLocalizations' is defined in the libraries 'package:flutter_localizations/src/material_localizations.dart (via ...)' and 'package:material_ui/src/global_material_localizations.dart (via ...)' - ambiguous_import A second error follows on the same line, non_constant_list_element. It disappears with the first one. The fix, in two steps. 1. Remove the flutter_localizations import from app.dart. 2. Replace the three old delegates with the list from material_ui: // before localizationsDelegates: const <LocalizationsDelegate<dynamic>>[ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], // after localizationsDelegates: <LocalizationsDelegate<dynamic>>[ AppLocalizations.delegate, ...GlobalMaterialLocalizations.delegates, ], GlobalMaterialLocalizations.delegates, with an s, is a list. The migration guide says it contains the Material, Cupertino and Widgets delegates, so the three old lines become one. The ... spreads that list into yours. The app's French tests confirm it: Material and Cupertino texts are translated. AppLocalizations.delegate stays first. It carries your own app's texts, generated from your .arb files. The guide's example does not show this line, because its example app has no texts of its own. If yours does, keep it. One more point if you use .arb files: keep flutter_localizations in your pubspec.yaml. Your own code no longer imports it, but the file that gen-l10n generates still does. Without the line, the app still builds, because material_ui brings the package along. But your project would then use a package it never asked for, and the lint that would warn you is switched off in generated files. So keep it declared in pubspec.yaml, and never import it again in your own files. The import is what caused the error, not the declaration. Did anything break? Analyzing material_ui_migration... No issues found! 00:00 +10: All tests passed! I also ran the same ten tests on the code from before the migration, in a separate git worktree, with the test imports switched back. Ten green there as well. So: ten tests green before, ten green after. Seventeen automatic fixes, and one manual fix to make it compile. For an app without third-party UI packages, the documented path works. The second pass The guide says to run dart fix a second time to sort the imports. They do need it, because the migration breaks the alphabetical order: import 'package:material_ui/material_ui.dart'; import 'package:flutter_test/flutter_test.dart'; But the second pass returned Nothing to fix!. Import order is checked by the lint rule directives_ordering, which is not part of flutter_lints. Without that rule, dart fix does not sort your imports. Your dependencies stay the same flutter pub outdated prints the same list before and after the migration. For example, material_color_utilities stays at 0.13.0 when 0.13.1 exists. In Flutter 3.47 the old Material is still inside the SDK, and the SDK holds this version. Migrating does not change that. --- That is the good news. Here are the three places where it goes wrong: a file left on the old import, an export the tool skipped, and the translation list that gen-l10n generates for you. --- Where it stops working The migration guide has a tool for apps that cannot migrate everything at once: the compatibility bridge. You add it in MaterialApp.builder: builder: (BuildContext context, Widget? child) { return MaterialUiCompatibilityBridge(child: child!); }, dart fix does not add it for you. The guide describes what it does: > *This allows unmigrated child widgets and dependencies that read design state > from context (such as Theme.of(context) or MaterialLocalizations.of(context)) to continue functioning properly.* and what it cannot do: > *the compatibility bridge cannot resolve type mismatches when a dependency > exposes, accepts, or returns in-framework SDK types in its public API > signatures (such as passing a FloatingActionButtonLocation, ColorScheme, > or TextTheme as a parameter or callback return value).* One thing the guide does not say: in material_ui 1.6.0, the bridge is already marked @Deprecated, as "a temporary migration utility" that "will be removed in a future release". The changelog does not mention it either. Only the analyzer warns you, when you add it. So whatever it fixes below, it fixes for now. I broke the migrated app in three ways, on purpose, and checked whether the bridge helps. 1. A file left on the old import This happens when one file stays on the old import, and with packages that have not migrated yet. To reproduce it, I put one file back on its old import: git checkout first-app-without-migration -- lib/features/legacy/legacy_summary.dart That file reads the theme and passes its ColorScheme to StatCard, a widget that is now migrated: The argument type 'ColorScheme (where ColorScheme is defined in .../flutter/lib/src/material/color_scheme.dart)' can't be assigned to the parameter type 'ColorScheme (where ColorScheme is defined in .../material_ui-1.6.0/lib/src/color_scheme.dart)'. "ColorScheme can't be assigned to ColorScheme." Same name, two classes. The compiler has to show the file paths, because the name no longer tells them apart. The bridge cannot help here, and the guide says so: it works through the context, and this value travels as a constructor argument. The only fix is to migrate the file. At least the compiler tells you. 2. An export the tool skipped After the migration, the app's theme belongs to material_ui. But the barrel file, lib/core/ui.dart, still exports the old Material from the SDK. And one widget, Section, imports that barrel. So when Section asks for the theme with Theme.of(context), it asks the old Material. The old Material cannot see the app's theme, because that theme now belongs to material_ui. Instead of failing, it gives back its own default theme. No error, no warning, and all ten tests still pass. A test measured the colors: | | Primary color | Title color | |---|---|---| | the app's theme | #465D91, my blue | #1A1B20 | | what Section gets | #6750A4, the default purple | #1D1B20 | The test also checked the color on screen: Section painted its title with the default one, #1D1B20. In this app you cannot see the difference: Section only uses the title color, and the two are almost identical. But any widget behind the barrel that uses colorScheme.primary would show the default purple instead of your blue. With the bridge: it works. The old Material now gets the app's colors, #465D91 and #1A1B20. But it only fixes part of the theme. Its source (lib/src/migration_utility.dart) builds the old ThemeData from four values only: platform, visualDensity, colorScheme and textTheme. Everything else keeps the old Material's defaults. Component themes, like inputDecorationTheme, and theme extensions are not passed on. The fix: migrate the two export lines by hand. export 'package:cupertino_ui/cupertino_ui.dart' hide RefreshCallback; export 'package:material_ui/material_ui.dart'; After that, dart analyze is clean and Section paints its title with the app's color, #1A1B20. No bridge needed. After running dart fix, search your project for export 'package:flutter/: the tool will not do it for you. 3. The translation list gen-l10n writes for you gen-l10n generates a ready-made list of delegates in lib/l10n/app_localizations.dart. After the migration, it still writes the old ones: import 'package:flutter_localizations/flutter_localizations.dart'; static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = <LocalizationsDelegate<dynamic>>[ delegate, GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ]; Those three come from flutter_localizations, the SDK. Passing this list straight to MaterialApp is a common shortcut: Zulip and kitchenowl both used it. So I did the same: localizationsDelegates: AppLocalizations.localizationsDelegates, It compiles. Eight tests pass, three fail, and the three that fail are the three that run in French. The app registers French texts for the SDK's Material widgets, but its widgets now come from material_ui, and they look for material_ui's texts. In English the app falls back on built-in English texts. In French, there is nothing to fall back on. The messages point the wrong way: - A MaterialLocalizations delegate that supports the fr locale was not found. There is one. It is the SDK's. No MaterialLocalizations found. To introduce a MaterialLocalizations, either use a MaterialApp at the root of your application... There is a MaterialApp. Neither message can say what is wrong, which is that two classes are called MaterialLocalizations. It breaks in the TextField on the first screen, the same widget as in the kitchenowl report. My tests run in debug mode, where an assertion catches it. The kitchenowl report says that release builds only showed a generic null-check crash. I did not measure release mode. With the bridge: no change. The same three French tests fail, with the same messages. The bridge registers the old flutter_localizations delegates, for widgets that still use the old Material. The migrated widgets need the new ones. > Does your app speak more than one language? > > 1. Search your code: grep -rn "localizationsDelegates" lib/. If you see > AppLocalizations.localizationsDelegates, you are affected. > 2. Run the app with locale: const Locale('fr') (or any language other than > English) in your MaterialApp. An English-only run will not show the bug. > 3. Replace the generated list with: > [AppLocalizations.delegate, ...GlobalMaterialLocalizations.delegates]. If that > file still imports flutter_localizations, remove the import. > 4. Never fix the generated file by hand. It is rewritten every time you add a > text to your .arb files. > 5. The compatibility bridge does not fix this one. --- So, can you migrate yet? For an app like the one tested here, with no third-party UI package: yes. Remember the word "expectation": the team expected "a drop-in maneuver", and for this app it almost is. Seventeen automatic fixes, one manual fix to make it compile, and the same ten tests green before and after. Almost, because of the three things below. But dart fix does not finish the job. After running it, check three things yourself: 1. Your export lines. The tool skips them. A forgotten one gives no error and brings back the default theme without any warning. 2. Your translation list, if your app speaks more than English. The list that gen-l10n generates still points to the old Material, and it breaks every other language. 3. Your pubspec.yaml. Replace any with real version constraints. The compatibility bridge will not do this for you. It fixes the theme read through Theme.of(context), but not types passed as arguments, and not the generated translations. And it is already deprecated. Should you migrate now, or wait? The SDK copy of Material is frozen. The package is not: it has released a new version about every week since August, with fixes the SDK copy will not get, like the showAboutDialog crash on the web (changelog). And the Flutter 3.47 announcement schedules the old libraries for deprecation in the November stable release. If you wait, you will migrate anyway, only closer to that deadline. Which leaves the real question for most apps: can you migrate if your app depends on packages that have not migrated yet? The first case above shows what such a package looks like from your side. If it passes a ColorScheme or a ThemeData through its API, the compiler refuses, and the bridge cannot help. The guide asks package authors to treat the migration as a major version bump. In one real app, only one of the eighteen dependencies that import Material had migrated when its team started (flutter_server_box#1591). That is the next article. I will add real packages to this app and sort them: the ones that migrate on their own, the ones the bridge saves, and the ones that break.

    3 comments
  9. Reddit · · r/dartlang · u/julemand101

    [Breaking Change] dart:mirrors is deprecated in Dart 3.14 and scheduled for removal in Dart 4.0 >The Dart core library `dart:mirrors` is formally deprecated starting in the November 2026 stable release (Dart 3.14), with complete removal planned for Dart 4.0. As of Dart SDK commit 2d4ba07 (dart-review.googlesource.com), `dart:mirrors` is annotated with `@deprecated` on `main`. Timeline: - Dart 3.14 (November 2026): Importing `dart:mirrors` emits deprecation warnings, while continuing to execute on the standalone Dart VM throughout Dart 3.x. - Dart 4.0: `dart:mirrors` will be removed from the Dart SDK. Recommended Alternatives & Common Migrations: - Resolving Package or Script Paths: Replace `currentMirrorSystem().findLibrary(...)` or `ClosureMirror.function.location` file lookups with `Isolate.resolvePackageUriSync(Uri.parse('package:foo/foo.dart'))` (`dart:isolate`) or `Platform.script` (`dart:io`). - Static Code Inspection (Tests & Tooling): Replace `reflectClass` / `LibraryMirror` declaration checks in tests and linters with `package:analyzer` (`parseString` from `package:analyzer/dart/analysis/utilities.dart` for fast single-file AST inspection, or `AnalysisContextCollection` when resolved element types are needed). - Enums, Dispatch & Test Runners: Replace reflective enum iteration and string-based method dispatch (`InstanceMirror.invoke`) with built-in `Enum.values` / `.byName()`, exhaustive `switch` expressions, and standard `package:test` `group()` / `test()` blocks. - Code Generation: Use `package:build`, `package:build_runner`, and `package:source_gen` (or `json_serializable`, `built_value`, `freezed`) for serialization, dependency injection, and boilerplate generation. - Ahead-of-Time Reflection: For workloads requiring reflection-like runtime capabilities, use pre-generated reflection via `package:reflectable` and `package:reflectable_builder`. Full details and discussion: sdk#44489

    25 points · 5 comments

Latest stargazers

The last 10 distinct accounts we observed this year.

Most active participants

PR, issue, comment & review events in the past year.

Packages

Scan pending.

README badges

Embed a badge in your README or website.

Live mentions · last 30 days
dart-lang/sdk mentions in the last 30 days