
- Published on
- ·9 min read
Flutter × BLE:跟藍牙硬體對話的各種路線
- Authors

- Name
- Bert / DOTUNE
- Developer
Flutter 寫 UI 很強,但跟硬體溝通——藍牙、USB、嵌入式板子——就不是簡單的事了。不過反過來看,正因為 Flutter 一套 code 跨 iOS、Android、Desktop,它反而是嵌入式廠商最理想的夥伴。想像一個智慧家電 App,手機設定、電腦監控、平板操作——除了 Flutter 沒幾個方案能同時覆蓋這些場景。
但 Flutter 怎麼跟硬體對話?不是找到一個 BLE package、scan()、connect() 就完事了——你要根據場景,在兩個關鍵環節各做選擇,然後拼成一條路線。這篇整理我實際走過的三種組合。
先搞清楚有兩層
在講路線之前,先拆開來看。Flutter 跟 BLE 硬體溝通,涉及兩個獨立的決策:
橋接層——Flutter 怎麼接到 native 世界
- Platform Channel(走原生 Kotlin/Swift)
- FFI(直接 call C/Rust library)
通訊層——藍牙由誰來管
- flutter_blue_plus(Dart package,內部走 Platform Channel)
- 廠商 SDK(封裝好的 AAR / framework,黑箱處理藍牙)
- Rust btleplug(Desktop 上直接用 Rust 管藍牙)
橋接層 2 選 × 通訊層 3 選,可以排出好幾種組合。但實務上大部分場景會落在下面這三條路線裡面——這篇整理的是最常見的三種,不是全部。
方案一:廠商給 SDK + Platform Channel
最常見的情況——廠商不公開通訊協定,只給你封裝好的 SDK。Android 一個 AAR、iOS 一個 framework,裡面黑箱處理了藍牙、配對、加密、韌體更新。你只能透過 SDK 提供的 API 跟裝置對話。
這時候走 Platform Channel:原生端(Kotlin/Swift)接 SDK 的 API,結果透過 Method Channel 傳回 Flutter。
理論上廠商也可以直接寫一套 Flutter SDK 給你——省掉 Platform Channel,import 就能用。但現實是大部分廠商不會這麼做,你還是得自己封裝。
好處是省事——連線穩定性和安全性廠商都幫你處理完了。但代價也有:
- 兩套原生 code。 Kotlin 一套、Swift 一套,即使邏輯一樣,API 形狀和語言不同,沒辦法複製貼上。AI 可以幫你寫,但維護期兩邊各改各的,還是會多一份心力
- Platform Channel 的序列化成本。 資料量小的時候無感,但如果 SDK 每秒噴幾百筆 event,Method Channel 來回序列化會變成瓶頸。這種情況可以考慮用 FFI 走 binary channel,但那是更進階的事了
- 自由度低。 SDK 是黑箱——裡面的編解碼邏輯你改不了、優化不了。廠商的實作品質不一定差,但你沒有自己寫的空間,效能瓶頸在哪也看不到
什麼時候用這條路:
- 廠商鎖定 SDK,沒有公開協定文件
- 裝置功能複雜(OTA 韌體更新、安全認證),自己逆向不值得
什麼時候不適合:
- 你有選擇權——如果廠商同時給了協定文件和 SDK,走方案二自己解碼,自由度大很多
方案二:廠商給標準 + flutter_blue_plus + 自己解碼
跟方案一相反——廠商給你編解碼的標準,但不給你封裝好的 code。
很多硬體廠商會公開他們的通訊協定文件——例如「byte 0-3 是溫度(float32)、byte 4-7 是濕度、byte 8 是電量」。你知道 BLE 的 GATT service UUID 和 characteristic UUID,知道資料格式,但怎麼把 raw bytes 轉成可讀的數值——你要自己寫。
通訊層用 flutter_blue_plus。它內部已經走 Platform Channel 接好了 iOS 的 CoreBluetooth 和 Android 的 BluetoothAdapter,掃描、連線、GATT 讀寫、Notify 全部封裝好。你寫 Dart 就能從 BLE characteristic 讀到 raw bytes,不用自己處理藍牙底層。
解碼的部分看資料量。一般感測器幾秒一筆的溫濕度資料,Dart 直接解就行。但碰到高頻資料——例如心電圖波形、音訊串流、慣性感測器的 raw data——每秒幾百甚至幾千筆,這時候可以把 raw bytes 透過 FFI 丟給 Rust 或 C++ 處理,不用擔心 Dart GC 在關鍵時刻卡一下。
跟方案三的共通點是:解碼層都可能用 Rust/C++ 來寫。 差別在於藍牙誰管——方案二的藍牙通訊是 flutter_blue_plus 處理的(它內部走 Platform Channel),方案三則是 Rust 直接管藍牙。換句話說,方案二的 Rust 只做「解碼」,方案三的 Rust 做「藍牙通訊 + 解碼」。
什麼時候用這條路:
- 廠商有公開協定文件,但沒有封裝好的 SDK(或 SDK 只有 C/C++ 版本)
- 裝置是標準 BLE,手機端為主
- 你想自己控制解碼邏輯,不依賴廠商 code
什麼時候不適合:
- 桌面端(Windows/Linux/macOS)——
flutter_blue_plus只支援手機,桌面要改用universal_ble_fork或layrz_ble - 廠商沒公開協定——你根本不知道那些 bytes 是什麼
方案三:btleplug + FFI(實驗性方案)
這條路的概念是:不用 flutter_blue_plus,也不用平台原生的藍牙 API——直接用 Rust 的 btleplug 跟藍牙晶片對話,然後透過 FFI 接給 Flutter。Rust 同時管藍牙通訊和解碼,Flutter 只處理 UI。
btleplug 2026 年已經支援 Windows、macOS、Linux,核心功能(掃描、連線、GATT 讀寫、Notify)在所有平台都是齊的。pub.dev 上也已經有 bluetooth_flutter 這個 package 嘗試封裝這條路(2026 年 6 月發布 v0.0.1)。
但目前還在非常早期的階段。如果你是做 Desktop App 而且有 Rust 經驗,可以關注這條路的發展——未來一兩年可能會成熟到生產可用。但如果你現在就要上線,這條路還需要大量的自行測試和補坑。手機端更是如此——iOS/Android 不讓你繞過系統藍牙 API,btleplug 在手機上底層還是走 CoreBluetooth/BluetoothAdapter,沒有真正「繞過」,走方案一或方案二更實際。
方向是對的,但目前可能還不是時候。
總結——三條路線對照
| 方案一:廠商給 SDK | 方案二:廠商給標準 + 自己解碼 | 方案三:btleplug + FFI | |
|---|---|---|---|
| 廠商給你什麼 | 封裝好的 SDK(黑箱) | 協定文件(開放標準) | 不需要(你用 Rust stack) |
| 平台 | iOS / Android | iOS / Android | Desktop(Win/Mac/Linux) |
| 藍牙誰管 | 廠商 SDK | flutter_blue_plus | Rust btleplug |
| 橋接層 | 手寫 Platform Channel | 不需要(package 內建) | FFI + flutter_rust_bridge |
| 解碼層 | 廠商 SDK 處理 | 你自己寫(Dart 或 Rust/C++) | Rust |
| 成熟度 | 看廠商 SDK 品質 | 高,生產可用 | 實驗性,發展中 |
| 原生 code 量 | 兩套(Kotlin + Swift) | 幾乎沒有 | 沒有(都 Rust) |
| 適合 | 廠商封閉 SDK、沒公開協定 | 有協定文件、想自己控制解碼 | 未來可期,現在先觀望 |
三條路線沒有誰是絕對最好的。關鍵是你手上的硬體是什麼、廠商給了你什麼、目標平台是什麼——然後照這個表,走對的那條路。
BLE 處理的是近距離低功耗通訊。如果你的 IoT 裝置走 WiFi——或 BLE 配對完就切 WiFi——那又是另一條路,門檻比 BLE 低很多。細節寫在 WiFi 篇。