iOS、Android 和网页上的 Flutter
一个 Dart 客户端:私有频道、自动重连,App 关闭时改用推送。
Flutter 用一份代码构建 iOS、Android、网页和桌面应用,实时功能的代码也应该是一份。官方的 Pusher Flutter 插件总是连接 pusher.com 的主机,所以请改用 dart_pusher_channels:一个纯 Dart 的 Pusher 协议客户端,可以设置 host,而且 Flutter 能运行的地方它都能运行。
用户得到什么
- 订单、聊天和比分界面原地更新,无需下拉刷新。
- 经过隧道、乘电梯,或从 Wi-Fi 切换到移动网络后,连接会自动恢复。
- 手机上和浏览器里的表现一致。
用到的功能
- dart_pusher_channels,整个 App 共用一个客户端。
- 私有频道(
private-),由你的后端用已登录用户的 token 授权。 - 私有和 presence 频道上的客户端事件,用于正在输入提示和其他小信号。
- App 在后台或已关闭时,改用 Hibira Push。
步骤 1:安装
flutter pub add dart_pusher_channels步骤 2:整个 App 共用一个客户端
// 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(),
);构建时传入 key:flutter run --dart-define=HIBIRA_KEY=YOUR_APP_KEY。App secret 绝不放进 App;私有频道由你的后端签名。
步骤 3:在界面上跟踪一个订单
// 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);
}在 onConnectionEstablished 时重新订阅,每次重连后频道都会恢复。你的后端授权端点会收到 socket_id 和 channel_name,检查 token 后,用任何兼容 Pusher 的服务器库返回签名。
步骤 4:App 打开时才连接
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 和 Android 本来就会暂停后台 App 的网络,所以在 paused 时断开,resumed 时重新连接。App 关闭时用户必须知道的事,请用推送通知发送:请看把用户带回来的推送通知和推送指南,其中介绍了你的 Flutter 宿主 App 可以调用的 Android 和 iOS SDK。
小提醒
- 先从你的 API 加载界面需要的数据,再让事件更新它;打开时就必须存在的状态,请发布到
cache-频道。 - 在应用设置中开启 Allow client events 后,客户端事件(
channel.trigger(eventName: 'client-typing', data: {...}))就能在私有和 presence 频道上使用。 - 登录后,Flutter 指南会用你的应用数值填好客户端设置。