Flutter trên iOS, Android và web
Một client Dart: kênh riêng tư, tự kết nối lại, và push khi ứng dụng đã đóng.
Flutter dựng một ứng dụng cho iOS, Android, web và desktop, và mã thời gian thực cũng nên là một. Plugin Pusher Flutter chính thức luôn kết nối tới máy chủ của pusher.com, nên hãy dùng dart_pusher_channels: một client giao thức Pusher viết hoàn toàn bằng Dart, cho phép đặt host và chạy ở mọi nơi Flutter chạy.
Người dùng nhận được gì
- Màn hình đơn hàng, chat và tỉ số cập nhật tại chỗ, không cần kéo để tải lại.
- Kết nối tự quay lại sau khi đi qua đường hầm, vào thang máy hoặc chuyển từ Wi-Fi sang dữ liệu di động.
- Hoạt động giống nhau trên điện thoại và trong trình duyệt.
Dùng những gì
- dart_pusher_channels, một client cho cả ứng dụng.
- Kênh riêng tư (
private-), được backend của bạn cấp quyền bằng token của người dùng đã đăng nhập. - Client event trên kênh riêng tư và presence, cho chỉ báo đang nhập và các tín hiệu nhỏ khác.
- Hibira Push cho những lúc ứng dụng ở chế độ nền hoặc đã đóng.
Bước 1: cài đặt
flutter pub add dart_pusher_channelsBước 2: một client cho cả ứng dụng
// lib/realtime.dart
import 'package:dart_pusher_channels/dart_pusher_channels.dart';
final realtime = PusherChannelsClient.websocket(
options: PusherChannelsOptions.fromHost(
scheme: 'wss',
host: 'ws.hibira.io',
port: 443,
key: const String.fromEnvironment('HIBIRA_KEY'),
),
connectionErrorHandler: (error, trace, refresh) => refresh(),
);Truyền key khi build: flutter run --dart-define=HIBIRA_KEY=YOUR_APP_KEY. App secret không bao giờ nằm trong ứng dụng; kênh riêng tư do backend của bạn ký.
Bước 3: theo dõi một đơn hàng trên màn hình
// lib/order_screen.dart
import 'dart:async';
import 'package:dart_pusher_channels/dart_pusher_channels.dart';
import 'package:flutter/material.dart';
import 'realtime.dart';
class OrderScreen extends StatefulWidget {
const OrderScreen({super.key, required this.orderId, required this.token});
final String orderId;
final String token;
State<OrderScreen> createState() => _OrderScreenState();
}
class _OrderScreenState extends State<OrderScreen> {
late final PrivateChannel channel;
final subs = <StreamSubscription>[];
String status = '…';
void initState() {
super.initState();
channel = realtime.privateChannel(
'private-order-${widget.orderId}',
authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel(
authorizationEndpoint: Uri.parse('https://api.example.com/pusher/auth'),
headers: {'Authorization': 'Bearer ${widget.token}'},
),
);
subs.add(channel.bind('status').listen((event) {
setState(() => status = event.tryGetDataAsMap()?['status'] ?? status);
}));
subs.add(realtime.onConnectionEstablished.listen((_) => channel.subscribeIfNotUnsubscribed()));
channel.subscribeIfNotUnsubscribed();
}
void dispose() {
for (final s in subs) {
s.cancel();
}
channel.unsubscribe();
super.dispose();
}
Widget build(BuildContext context) => Text(status);
}Đăng ký lại khi có onConnectionEstablished sẽ đưa kênh trở lại sau mỗi lần kết nối lại. Endpoint cấp quyền của backend nhận socket_id và channel_name, kiểm tra token, rồi trả về chữ ký từ bất kỳ thư viện máy chủ tương thích Pusher nào.
Bước 4: chỉ kết nối khi ứng dụng đang mở
class _AppState extends State<App> with WidgetsBindingObserver {
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
realtime.connect();
}
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.paused) realtime.disconnect();
if (state == AppLifecycleState.resumed) realtime.connect();
}
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
Widget build(BuildContext context) => const MaterialApp(home: HomeScreen());
}iOS và Android vốn đã tạm dừng mạng của ứng dụng chạy nền, nên hãy ngắt kết nối khi paused và kết nối lại khi resumed. Những gì người dùng cần biết khi ứng dụng đã đóng nên được gửi bằng thông báo đẩy: xem thông báo đẩy kéo người dùng quay lại và hướng dẫn push, nơi giới thiệu SDK Android và iOS mà ứng dụng host của Flutter có thể gọi.
Mẹo
- Tải những gì màn hình cần từ API trước, rồi để event cập nhật; với trạng thái phải có ngay khi mở, hãy phát lên kênh
cache-. - Client event (
channel.trigger(eventName: 'client-typing', data: {...})) dùng được trên kênh riêng tư và presence khi bật Allow client events trong cài đặt ứng dụng. - Sau khi đăng nhập, hướng dẫn Flutter có sẵn cài đặt client với giá trị của ứng dụng bạn.