Flutter ile MQTT kullanmak için mqtt_client paketini ekleyin; Android, iOS ve masaüstü için bir MqttServerClient, Flutter web için bir MqttBrowserClient oluşturun, bağlanın, abone olun ve updates stream'ini dinleyin. En çok kafa karıştıran nokta, iki istemcinin farklı taşıma katmanları kullanmasıdır: server istemcisi TCP veya TLS konuşur, browser istemcisi ise yalnızca WebSocket kullanabilir.
Bu rehberde Flutter için küçük, yeniden kullanılabilir bir MQTT servisi kuruyor, broker.connectmq.com üzerinde TCP, TLS ve güvenli WebSocket yapılandırmalarını gösteriyor ve tüm akışı tarayıcıdan hızlıca test etmenin yolunu anlatıyoruz.
mqtt_client kurulumu
mqtt_client saf bir Dart paketidir; bu yüzden native plugin gerektirmeden tüm Flutter platformlarında çalışır:
flutter pub add mqtt_clientPaket, iki ayrı kütüphanede iki istemci sınıfı içerir. Hangisini import ettiğiniz, hangi taşıma katmanını kullanacağınızı belirler:
| Sınıf | Import | Platformlar | Taşıma |
|---|---|---|---|
MqttServerClient | package:mqtt_client/mqtt_server_client.dart | Android, iOS, macOS, Windows, Linux | TCP, TLS, WebSocket, güvenli WebSocket |
MqttBrowserClient | package:mqtt_client/mqtt_browser_client.dart | Flutter web | Yalnızca WebSocket ve güvenli WebSocket |
mqtt_server_client.dart, tarayıcıda bulunmayan dart:io'yu import eder; bu nedenle web build'de import edildiğinde derleme hata verir. Bunu aşağıda koşullu import ile çözeceğiz. Uygulama yerine saf Dart ile bir komut satırı aracı yazıyorsanız aynı API geçerlidir: Dart ile MQTT yazısına bakın.
TCP üzerinden ilk bağlantı
En basit kurulumla başlayın: 1883 portunda şifresiz TCP. Her istemcinin benzersiz bir client ID'ye ihtiyacı vardır; iki cihaz aynı ID'yi paylaşırsa, biri her bağlandığında broker eski oturumu düşürür. Format seçmek için client ID oluşturucu işinize yarar.
import 'dart:math';
import 'package:mqtt_client/mqtt_client.dart';
import 'package:mqtt_client/mqtt_server_client.dart';
Future<MqttServerClient> connectMqtt() async {
final clientId = 'flutter-${Random().nextInt(0xFFFFFF).toRadixString(16)}';
final client = MqttServerClient.withPort('broker.connectmq.com', clientId, 1883);
client.logging(on: false);
client.setProtocolV311();
client.keepAlivePeriod = 30;
client.connectTimeoutPeriod = 5000; // milisaniye
client.onConnected = () => print('bağlandı');
client.onDisconnected = () => print('bağlantı kesildi');
client.connectionMessage = MqttConnectMessage()
.withClientIdentifier(clientId)
.startClean()
.withWillTopic('testmqtt/flutter-demo/$clientId/status')
.withWillMessage('offline')
.withWillQos(MqttQos.atLeastOnce);
try {
await client.connect(); // veya client.connect('username', 'password')
} on Exception catch (e) {
print('bağlantı başarısız: $e');
client.disconnect();
rethrow;
}
final state = client.connectionStatus?.state;
if (state != MqttConnectionState.connected) {
throw Exception('broker bağlantıyı reddetti: ${client.connectionStatus}');
}
return client;
}connect(), broker CONNECT'i reddettiğinde (yanlış kimlik bilgileri, engellenmiş client ID) NoConnectionException, host veya porta ulaşılamadığında ise SocketException fırlatır. client.connectionStatus çıktısı size dönüş kodunu verir; bu kodu MQTT reason code tablosunda arayabilirsiniz.
Abone olma ve mesaj alma
Gelen mesajlar bir Dart stream'i olan client.updates üzerinden gelir. Önce abone olun, sonra bir kez dinleyin; her abonelik için ayrı ayrı değil:
const topic = 'testmqtt/flutter-demo/sensors/#';
void listen(MqttServerClient client) {
client.subscribe(topic, MqttQos.atLeastOnce);
client.updates!.listen((messages) {
for (final m in messages) {
final publish = m.payload as MqttPublishMessage;
final text = MqttPublishPayload.bytesToStringAsString(publish.payload.message);
print('${m.topic}: $text');
}
});
}bytesToStringAsString byte'ları metin olarak çözer. JSON için sonucu jsonDecode'a verin; binary payload'lar (CBOR, Protobuf) için doğrudan tipli bir byte buffer olan publish.payload.message'ı kullanın.
Bir widget içinde listen'in döndürdüğü StreamSubscription'ı saklayın ve dispose() içinde iptal edin ya da stream'i state management çözümünüz (Provider, Riverpod, Bloc) üzerinden sunun. Böylece her widget kendi bağlantısını açmak yerine tek bir doğruluk kaynağından yeniden çizilir.
Publish
Payload'lar MqttClientPayloadBuilder ile oluşturulur:
import 'dart:convert';
void publishReading(MqttServerClient client, double celsius) {
final builder = MqttClientPayloadBuilder()
..addUTF8String(jsonEncode({'celsius': celsius, 'ts': DateTime.now().toIso8601String()}));
client.publishMessage(
'testmqtt/flutter-demo/sensors/kitchen',
MqttQos.atLeastOnce,
builder.payload!,
retain: false,
);
}Metin ASCII dışı karakter içerebiliyorsa addString yerine addUTF8String kullanın; addString her UTF-16 kod birimi için tek byte yazar ve ç, ğ, ş gibi harfleri ya da emojileri bozabilir.
8883 portunda TLS
Production için server istemcisini TLS'e geçirin. broker.connectmq.com gibi genel bir CA'dan sertifikası olan broker'lar işletim sisteminin güven deposuyla doğrulanır; ek dosya gerekmez:
import 'dart:io';
final client = MqttServerClient.withPort('broker.connectmq.com', clientId, 8883)
..secure = true
..securityContext = SecurityContext.defaultContext;
await client.connect('username', 'password');Self-signed sertifikalı veya özel CA kullanan bir broker için SecurityContext(withTrustedRoots: false) oluşturun ve asset'lerinizden yüklediğiniz CA sertifikasıyla setTrustedCertificatesBytes() çağırın. onBadCertificate: (_) => true ifadesini hızlı bir yerel deneme dışında kullanmayın: her sertifikayı kabul eder ve TLS'i sessizce etkisiz kılar. Handshake başarısız olursa, terminalden TLS bağlantısını test etmek sorunun broker'da mı yoksa uygulamada mı olduğunu gösterir.
Flutter web: WSS üzerinden MqttBrowserClient
Tarayıcıda MQTT, WebSocket üzerinden çalışır. HTTPS ile sunulan sayfalar yalnızca wss:// bağlantısı açabilir; bu yüzden güvenli WebSocket portunu kullanın ve path'i ekleyin:
import 'package:mqtt_client/mqtt_client.dart';
import 'package:mqtt_client/mqtt_browser_client.dart';
MqttClient createClient(String clientId) {
final client = MqttBrowserClient('wss://broker.connectmq.com/mqtt', clientId)
..port = 8084
..keepAlivePeriod = 30
..websocketProtocols = MqttClientConstants.protocolsSingleDefault;
return client;
}Portun URL içinde değil, property olarak ayarlandığına dikkat edin. websocketProtocols satırı, çoğu broker'ın beklediği mqtt subprotocol başlığını gönderir. Yanlış path genellikle upgrade'den hemen sonra WebSocket'in kapanmasıyla kendini gösterir; handshake'in ayrıntıları WebSocket üzerinden MQTT yazısında.
Tüm platformlar için tek kod tabanı
Bir MqttServerClient döndüren (örneğin 8883'te TLS ile) karşılık gelen bir lib/mqtt_server.dart oluşturun ve doğru dosyayı derleme zamanında seçin:
export 'mqtt_server.dart'
if (dart.library.js_interop) 'mqtt_browser.dart';Uygulamanın geri kalanı yalnızca mqtt_factory.dart ve package:mqtt_client/mqtt_client.dart'ı import eder ve ortak MqttClient taban sınıfıyla çalışır. Connect, subscribe, publish ve updates stream'i iki tarafta da aynı davranır.
Yeniden bağlanma ve uygulama yaşam döngüsü
Mobil ağlar bağlantıyı sürekli koparır: Wi-Fi'dan hücresel ağa geçiş, tüneller, işletim sisteminin uygulamanızı askıya alması. mqtt_client yerleşik bir otomatik yeniden bağlanma özelliğine sahiptir:
client
..autoReconnect = true
..resubscribeOnAutoReconnect = true
..onAutoReconnect = () => print('bağlantı koptu, yeniden bağlanılıyor...')
..onAutoReconnected = () => print('yeniden bağlandı');resubscribeOnAutoReconnect (varsayılanı true) ile istemci yeniden bağlandıktan sonra aboneliklerinizi tekrar gönderir. Bu önemlidir, çünkü clean session broker tarafında abonelikleri unutur. Clean session'da broker, bağlantı kopukken yayınlanan mesajları saklamaz; uygulama veri kaçırmamalıysa kalıcı oturumla bağlanın (startClean() kullanmayın, sabit bir client ID tutun) ve QoS 1 ile abone olun. Bunu kendi özel broker instance'ınızda test edin: paylaşılan test endpoint'i çevrimdışı oturumları saklamaz.
iOS ve Android'in arka plandaki uygulamaları askıya aldığını ve bunun keep-alive'dan bağımsız olarak soketi kapattığını unutmayın. Yaşam döngüsünü WidgetsBindingObserver ile izleyin, paused durumunda düzgünce bağlantıyı kesin, resumed durumunda yeniden bağlanın. Arka planda teslim için doğru araç push bildirimleridir; Android'de arka plan bağlantı kopmaları ve iOS arka plan sınırları yazılarına bakın.
Platform kontrol listesi
- Android:
android/app/src/main/AndroidManifest.xmldosyasına<uses-permission android:name="android.permission.INTERNET"/>ekleyin. Debug build'ler bunu otomatik içerir; "debug'da çalışıyor, release'de çalışmıyor" durumunun bu kadar yaygın olmasının sebebi budur. - macOS:
DebugProfile.entitlementsveRelease.entitlementsdosyalarının ikisine detruedeğeriylecom.apple.security.network.clientekleyin; aksi halde sandbox giden soketleri engeller. - iOS: TLS için ek bir şey gerekmez. App Transport Security URL yükleme API'leri için geçerlidir, ham TCP veya bir hostname'e
ws://için değil; yine de production'da TLS kullanın. - Web:
MqttBrowserClient,wss://, doğru port ve path kullanın. Tarayıcı mixed content'i (birhttps://sayfasındanws://broker'a bağlantı) engeller.
Uçtan uca test
Uygulamayı çalıştırın, tarayıcıda online MQTT istemcisini açın, güvenli WebSocket ile broker.connectmq.com'a bağlanın ve testmqtt/flutter-demo/# topic'ine abone olun. Uygulamanızın yayınladığı ölçümleri görmeniz gerekir; tarayıcıdan testmqtt/flutter-demo/sensors/test topic'ine yayınladığınız her şey de Flutter debug konsolunda görünmelidir.
Flutter uygulamanızın mesajlarını tarayıcıda izleyin
Hiçbir şey gelmiyorsa şu sırayla kontrol edin: connect() sonrasındaki bağlantı durumu, abonelik topic'inin publish topic'iyle eşleşip eşleşmediği (wildcard'lar için topic matcher yardımcı olur) ve client.logging(on: true) sonrasındaki debug çıktısı. En sık görülen exception'lar ve çözümleri Flutter MQTT hataları yazısında toplanmıştır.
Tek bir factory dosyası, tek bir mesaj stream'i ve açık otomatik yeniden bağlanma ile aynı Flutter kodu telefondan, masaüstünden ve bir tarayıcı sekmesinden broker'la konuşur. Paylaşılan endpoint ile başlayın, kimlik bilgileriyle TLS ve güvenli WebSocket'e geçin ve geliştirme sırasında tarayıcı istemcisini açık tutarak uygulamanızın gönderdiği her mesajı görün.
Sıkça sorulan sorular
Flutter MQTT uygulamam neden Android'de çalışıyor da web'de çalışmıyor?
Tarayıcılar ham TCP soketi açamaz, bu yüzden MqttServerClient Flutter web'de çalışmaz. wss:// adresiyle, broker'ın WebSocket portuyla (örneğin 8084) ve /mqtt gibi doğru path ile MqttBrowserClient kullanın.
mqtt_client MQTT 5'i destekliyor mu?
Hayır. mqtt_client MQTT 3.1 ve 3.1.1'i uygular. Reason code, user property veya session expiry gibi MQTT 5 özelliklerine ihtiyacınız varsa aynı yazarın, API'si çok benzer olan mqtt5_client paketini kullanın.
Flutter'da MQTT için özel izin gerekir mi?
Android'de release build'ler AndroidManifest.xml içinde INTERNET iznine ihtiyaç duyar (debug build'ler bunu otomatik ekler). macOS'ta giden bağlantı entitlement'ını (com.apple.security.network.client) açın. iOS ve web için ek bir şey gerekmez.


