Flutter实时通信插件pusher_client_socket的使用

发布于 1周前 作者 wuwangju 来自 Flutter

Flutter 实时通信插件 pusher_client_socket 的使用

简介

pusher_client_socket 是一个用于通过 WebSocket 连接到 Pusher 服务器的 Dart 库。它提供了一个易于使用的 API 来订阅频道、绑定事件监听器以及向服务器发送事件。

特性

  • 使用 WebSocket 连接到 Pusher 服务器。
  • 支持所有平台(Android, iOS, MacOS, WindowsOS, LinuxOS, Web)。
  • 订阅公共、私有、加密私有和存在频道。
  • 绑定事件监听器以处理自定义和 Pusher 特定事件。
  • 自动重连逻辑以处理连接中断。
  • 活动检查机制以确保连接保持活动状态。

安装

pubspec.yaml 文件中添加以下依赖:

dependencies:
  pusher_client_socket: ^0.0.2+6

然后运行:

flutter pub get

或者使用 pub add

flutter pub add pusher_client_socket

使用示例

1. 导入库

/// 导入 pusher client
import 'package:pusher_client_socket/pusher_client_socket.dart';

/// 导入频道
import 'package:pusher_client_socket/channels/channel.dart';
import 'package:pusher_client_socket/channels/private_channel.dart';
import 'package:pusher_client_socket/channels/private_encrypted_channel.dart';
import 'package:pusher_client_socket/channels/presence_channel.dart';

2. 初始化连接选项

使用默认 Pusher 服务器

final options = PusherOptions(
  key: 'PUSHER-KEY',
  cluster: 'mt1',
  wsPort: 80,
  wssPort: 443,
  authOptions: PusherAuthOptions(
    endpoint: 'http://localhost/broadcasting/auth',
    headers: {
      'Accept': 'application/json',
      'Authorization': 'Bearer AUTH-TOKEN'
    }
  ),
  autoConnect: false,
);

指定服务器(例如 Laravel/Reverb)

final options = PusherOptions(
  key: 'REVERB_APP_KEY',
  host: 'localhost', // REVERB_HOST
  wsPort: 6001, // REVERB_PORT
  encrypted: false, // (注意:如果你使用 wss 连接,请启用此项)
  authOptions: PusherAuthOptions(
    endpoint: 'http://localhost/broadcasting/auth',
    headers: {
      'Accept': 'application/json',
      'Authorization': 'Bearer AUTH-TOKEN'
    }
  ),
  autoConnect: false,
);

3. 初始化客户端并连接

final pusherClient = PusherClient(options);

pusherClient.onConnectionEstablished((data) {
  print("Connection established - socket-id: ${pusherClient.socketId}");
});

pusherClient.onConnectionError((error) {
  print("Connection error - $error");
});

pusherClient.onError((error) {
  print("Error - $error");
});

pusherClient.onDisconnected((data) {
  print("Disconnected - $data");
});

pusherClient.connect();

4. 订阅频道

/// 订阅公共频道
final publicChannel = pusherClient.channel('channel-1');

/// 订阅私有频道
final privateChannel = pusherClient.channel('private-channel-2');
// 或者
final privateChannel = pusherClient.private('channel-2');

/// 订阅加密私有频道
final privateEncryptedChannel = pusherClient.channel('private-encrypted-channel-3');
// 或者
final privateEncryptedChannel = pusherClient.privateEncrypted('channel-3');

/// 订阅存在频道
final presenceChannel = pusherClient.channel("presence-channel-4");
// 或者
final presenceChannel = pusherClient.presence("channel-4");

5. 监听事件

channel.bind('EventName', (data) {
  print('event received - EventName - $data');
});

6. 在私有或存在频道上触发事件

privateChannel.trigger('client-EventName', data);
// 或者
privateChannel.trigger('EventName', data);
// 或者
presenceChannel.trigger('client-EventName', data);
// 或者
presenceChannel.trigger('EventName', data);

7. 取消订阅频道

channel.unsubscribe();

完整示例 Demo

以下是一个完整的 Flutter 示例应用,展示了如何使用 pusher_client_socket 插件进行实时通信。

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:pusher_client_socket/pusher_client_socket.dart';

void main() {
  runApp(const MyApp());
}

const String TOKEN = "AUTH_TOKEN";
const String KEY = "PUSHER_KEY";

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Pusher Client Socket',
      theme: ThemeData(
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late PusherClient client;

  final tokenController = TextEditingController(text: TOKEN);

  bool connected = false;
  bool connecting = false;
  String? connectError;
  String? socketId;

  final channelController = TextEditingController(text: "Chat.1");
  PrivateChannel? channel;
  bool subscribed = false;
  bool subscribing = false;

  final messageController = TextEditingController();

  String messages = '';

  void connect() {
    if (tokenController.text.isEmpty) {
      return;
    }

    setState(() {
      connecting = true;
    });
    client = PusherClient(
      options: PusherOptions(
        host: "localhost",
        wsPort: 6001,
        encrypted: false,
        authOptions: PusherAuthOptions(
          "http://localhost/api/broadcasting/auth",
          headers: {
            "Accept": "application/json",
            "Authorization": "Bearer ${tokenController.text}",
          },
        ),
        key: KEY,
        enableLogging: true,
        autoConnect: false,
      ),
    );

    client.onConnectionEstablished((data) => setState(() {
          connected = true;
          socketId = client.socketId;
          connecting = false;
          client
              .subscribe("private-encrypted-User.1")
              .bind("UserUpdatedEvent", (data) => print("UserUpdatedEvent - $data"));
        }));

    client.onDisconnected((reason) => setState(() {
          connected = false;
          socketId = client.socketId;
          connecting = false;
        }));

    client.onConnectionError((error) => setState(() {
          connectError = "$error";
          connecting = false;
        }));

    client.onError((error) => setState(() {
          connectError = "$error";
          connecting = false;
        }));

    client.connect();
  }

  void disconnect() {
    setState(() {
      connecting = true;
    });

    client.disconnect();
  }

  void subscribe() {
    setState(() {
      subscribed = false;
      subscribing = true;
    });

    channel = client.presence(channelController.text);
    channel!.onSubscriptionSuccess((data) => setState(() {
          print("Subscribe success $data");
          subscribed = true;
          subscribing = false;
        }));
    channel!.bind("client-whisper", (data) {
      print("test event - $data");
      setState(() {
        messages += "client: ${data["message"]}\n";
      });
    });
    channel!.subscribe();
  }

  void unSubscribe() {
    channel!.unsubscribe();
    setState(() => subscribed = false);
  }

  void sendMessage() {
    channel!.trigger("whisper", {"message": messageController.text});
    setState(() {
      messages += "you: ${messageController.text}\n";
    });
    messageController.clear();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Pusher Client Socket'),
      ),
      body: SizedBox.expand(
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 20),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              if (connecting)
                const CircularProgressIndicator()
              else ...[
                if (!connected)
                  TextField(
                    controller: tokenController,
                    decoration: const InputDecoration(
                      border: OutlineInputBorder(),
                      labelText: 'Token',
                    ),
                  ),
                ElevatedButton(
                  onPressed: connected ? disconnect : connect,
                  child: Text(
                    connected ? 'Disconnect' : 'Connect',
                    style: TextStyle(
                      color: connected ? Colors.red : Colors.green,
                    ),
                  ),
                ),
                if (connectError != null)
                  Text(
                    connectError!.substring(0, min(400, connectError!.length)),
                    style: const TextStyle(
                      color: Colors.red,
                      fontSize: 20,
                    ),
                  ),
              ],
              if (connected) ...[
                Text(
                  'Socket-ID: $socketId',
                  style: const TextStyle(
                    fontWeight: FontWeight.bold,
                    fontSize: 18,
                  ),
                ),
                const Divider(),
                if (!subscribed)
                  Row(
                    children: [
                      const Text(
                        "Channel: ",
                        style: TextStyle(fontSize: 18),
                      ),
                      Flexible(
                        child: TextField(
                          controller: channelController,
                          decoration: const InputDecoration(
                            border: OutlineInputBorder(),
                          ),
                        ),
                      ),
                    ],
                  ),
                if (subscribing)
                  const CircularProgressIndicator()
                else ...[
                  ElevatedButton(
                    onPressed: subscribed ? unSubscribe : subscribe,
                    child: Text(
                      subscribed ? 'unsubscribe' : 'subscribe',
                      style: TextStyle(
                        color: subscribed ? Colors.red : Colors.green,
                      ),
                    ),
                  ),
                  if (subscribed) ...[
                    const Divider(),
                    Row(
                      children: [
                        Flexible(
                          child: TextField(
                            controller: messageController,
                            decoration: const InputDecoration(
                              border: OutlineInputBorder(),
                            ),
                          ),
                        ),
                        ElevatedButton(
                          onPressed: sendMessage,
                          child: const Text('Send'),
                        ),
                        SizedBox(
                          height: 200,
                          child: SingleChildScrollView(
                            child: Text(messages),
                          ),
                        ),
                      ],
                    ),
                  ],
                ],
              ],
            ],
          ),
        ),
      ),
    );
  }
}

这个示例展示了如何初始化 Pusher 客户端、连接到服务器、订阅频道、监听事件以及发送消息。你可以根据需要修改和扩展此示例。


更多关于Flutter实时通信插件pusher_client_socket的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter实时通信插件pusher_client_socket的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用pusher_client_socket插件进行实时通信的代码示例。这个示例将展示如何连接到Pusher服务器,订阅一个频道,并监听事件。

首先,确保你已经在pubspec.yaml文件中添加了pusher_client_socket依赖:

dependencies:
  flutter:
    sdk: flutter
  pusher_client_socket: ^x.y.z  # 替换为最新版本号

然后,运行flutter pub get来安装依赖。

接下来,在你的Flutter项目中创建一个新的Dart文件(例如pusher_service.dart),并编写以下代码:

import 'package:flutter/material.dart';
import 'package:pusher_client_socket/pusher_client_socket.dart';

class PusherService {
  late PusherClient _pusherClient;
  late Channel _channel;

  PusherService({required String key, required String cluster}) {
    _pusherClient = PusherClient(
      key: key,
      cluster: cluster,
      enableLogging: true,
    );

    _pusherClient.connect().then((value) {
      print("Connected to Pusher!");
      _subscribeToChannel();
    }).catchError((error) {
      print("Error connecting to Pusher: $error");
    });
  }

  void _subscribeToChannel() {
    _channel = _pusherClient.subscribe('my-channel');

    _channel.bind('my-event', (data) {
      print("Received event: $data");
      // 在这里处理接收到的事件数据
    });
  }

  void disconnect() {
    _pusherClient.disconnect();
  }
}

在上面的代码中,我们创建了一个PusherService类,它负责处理与Pusher的连接、频道订阅和事件监听。你需要替换keycluster参数为你的Pusher应用密钥和集群信息。

现在,在你的主应用程序文件(例如main.dart)中,使用这个服务:

import 'package:flutter/material.dart';
import 'pusher_service.dart';

void main() {
  // 初始化Pusher服务
  final pusherService = PusherService(
    key: 'YOUR_PUSHER_KEY', // 替换为你的Pusher应用密钥
    cluster: 'YOUR_PUSHER_CLUSTER', // 替换为你的Pusher集群(例如 'ap2' 或 'eu')
  );

  runApp(MyApp(pusherService: pusherService));
}

class MyApp extends StatelessWidget {
  final PusherService pusherService;

  MyApp({required this.pusherService});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Pusher Demo'),
        ),
        body: Center(
          child: Text('Listening for events...'),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            // 断开连接(可选)
            pusherService.disconnect();
          },
          tooltip: 'Disconnect',
          child: Icon(Icons.disconnect),
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用程序,它在启动时初始化PusherService并连接到Pusher。应用程序会显示一个文本和一个浮动操作按钮,点击按钮将断开与Pusher的连接(虽然在实际应用中,你可能会有更复杂的逻辑来处理连接和断开连接)。

请注意,为了完整性和实际使用,你需要确保你的Pusher应用已经配置好,并且你正在监听的频道和事件是存在的。此外,你可能还需要处理更多的错误情况和连接状态变化。

希望这个示例能帮助你开始在Flutter项目中使用pusher_client_socket插件进行实时通信!

回到顶部