Flutter实时通信插件netcore_signalr的使用

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

Flutter实时通信插件netcore_signalr的使用

简介

signalr_netcore 是一个用于 Flutter 应用程序的 ASP.NET Core SignalR 客户端库。ASP.NET Core SignalR 是一个开源库,它简化了向应用程序添加实时Web功能的过程。实时Web功能使服务器端代码能够即时推送内容到客户端。

本库经过测试,支持 ASP.NET Core 3.1 和 ASP.NET Core 6。该客户端能够调用服务器端的Hub函数(包括流式函数)并接收由服务器发起的方法调用。它还支持自动重连功能。

该客户端支持以下传输协议:

  • WebSocket
  • Service Side Events
  • Long Polling

该客户端支持以下Hub协议:

  • Json
  • MessagePack

示例

聊天客户端/服务器

开始使用

pubspec.yaml 文件中添加 signalr_netcore 依赖项:

dependencies:
  flutter:
    sdk: flutter

  signalr_netcore:

重要提示:如果你遇到问题(例如未接收到消息回调),请尝试使用旧版本,如 signalr_netcore: 0.1.7+2-nullsafety.3,但请注意,该版本不支持自动重连功能,需要手动处理。

使用方法

以下是一些基本用法的示例:

1. 创建Hub连接

// 导入库
import 'package:signalr_netcore/signalr_client.dart';

// 服务器地址
final serverUrl = "192.168.10.50:51001";

// 创建连接
final hubConnection = HubConnectionBuilder().withUrl(serverUrl).build();

// 连接关闭时打印消息
hubConnection.onclose((error) => print("Connection Closed"));

日志记录可以通过 logging 包进行配置:

// 导入库
import 'package:logging/logging.dart';
import 'package:signalr_netcore/signalr_client.dart';

// 配置日志
Logger.root.level = Level.ALL;
Logger.root.onRecord.listen((LogRecord rec) {
  print('${rec.level.name}: ${rec.time}: ${rec.message}');
});

// 日志记录级别为Hub协议
final hubProtLogger = Logger("SignalR - hub");

// 日志记录级别为传输
final transportProtLogger = Logger("SignalR - transport");

// 创建带有日志记录选项的连接
final httpOptions = HttpConnectionOptions(logger: transportProtLogger);
final hubConnection = HubConnectionBuilder().withUrl(serverUrl, options: httpOptions).configureLogging(hubProtLogger).build();

// 连接关闭时打印消息
hubConnection.onclose((error) => print("Connection Closed"));

2. 连接到Hub

调用以下方法开始握手并连接客户端到SignalR服务器:

await hubConnection.start();

3. 调用Hub函数

假设有一个Hub函数:

public string MethodOneSimpleParameterSimpleReturnValue(string p1)
{
  Console.WriteLine($"'MethodOneSimpleParameterSimpleReturnValue' invoked. Parameter value: '{p1}");
  return p1;
}

客户端可以调用此函数:

final result = await hubConnection.invoke("MethodOneSimpleParameterSimpleReturnValue", args: <Object>["ParameterValue"]);
logger.log(LogLevel.Information, "Result: '$result'");

4. 调用客户端函数

假设服务器调用名为 “aClientProvidedFunction” 的函数:

await Clients.Caller.SendAsync("aClientProvidedFunction", null);

客户端可以这样实现:

hubConnection.on("aClientProvidedFunction", _handleAClientProvidedFunction);

// 取消注册函数
// a) 取消注册特定实现
// hubConnection.off("aClientProvidedFunction", method: _handleServerInvokeMethodNoParametersNoReturnValue);
// b) 取消注册所有实现
// hubConnection.off("aClientProvidedFunction");

void _handleAClientProvidedFunction(List<Object> parameters) {
  logger.log(LogLevel.Information, "Server invoked the method");
}

5. 使用Msgpack进行序列化

如果需要使用Msgpack协议进行序列化,需要在客户端和服务器上都进行配置。

客户端

import 'package:signalr_netcore/msgpack_hub_protocol.dart';

_hubConnection = HubConnectionBuilder()
          .withUrl(_serverUrl, options: httpOptions)
          /* 配置Hub使用Msgpack协议 */
          .withHubProtocol(MessagePackHubProtocol())
          .withAutomaticReconnect()
          .configureLogging(logger)
          .build();

服务器

在ASP.NET Core项目中添加以下包:

Microsoft.AspNetCore.SignalR.Protocols.MessagePack

然后在 ConfigureServices 方法中配置Hub使用Msgpack协议:

public void ConfigureServices(IServiceCollection services)
{
    // 配置Hub使用Msgpack协议
    services.AddSignalR().AddMessagePackProtocol();
}

参数类型注意事项

所有函数参数和返回值都通过 dart:convert 包(json.encode/json.decode)进行序列化/反序列化。确保你:

  • 只使用简单参数类型
  • 或者使用实现了 toJson() 方法的对象,因为该方法被 dart:convert 包用来序列化对象。

如何暴露MessageHeaders对象以便客户端发送默认头

final defaultHeaders = MessageHeaders();
defaultHeaders.setHeaderValue("HEADER_MOCK_1", "HEADER_VALUE_1");
defaultHeaders.setHeaderValue("HEADER_MOCK_2", "HEADER_VALUE_2");

final httpConnectionOptions = HttpConnectionOptions(
          httpClient: WebSupportingHttpClient(logger, httpClientCreateCallback: _httpClientCreateCallback),
          accessTokenFactory: () => Future.value('JWT_TOKEN'),
          logger: logger,
          logMessageContent: true,
          headers: defaultHeaders);

final _hubConnection = HubConnectionBuilder()
          .withUrl(_serverUrl, options: httpConnectionOptions)
          .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000, null])
          .configureLogging(logger)
          .build();

HTTP请求日志:

I/flutter ( 5248): Starting connection with transfer format 'TransferFormat.Text'.
I/flutter ( 5248): Sending negotiation request: https://localhost:5000/negotiate?negotiateVersion=1
I/flutter ( 5248): HTTP send: url 'https://localhost:5000/negotiate?negotiateVersion=1', method: 'POST' content: '' content length = '0' 
headers: '{ content-type: text/plain;charset=UTF-8 }, { HEADER_MOCK_1: HEADER_VALUE_1 }, { X-Requested-With: FlutterHttpClient }, { HEADER_MOCK_2: HEADER_VALUE_2 }, { Authorization: Bearer JWT_TOKEN }'

示例代码

聊天客户端/服务器

import 'package:flutter/material.dart';

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

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

1 回复

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


当然,以下是一个使用Flutter和netcore_signalr插件实现实时通信的示例代码。这个示例假设你已经有一个ASP.NET Core SignalR服务器在运行,并且你希望从Flutter客户端连接到该服务器并接收实时消息。

1. 设置Flutter项目

首先,确保你已经创建了一个Flutter项目。如果还没有,可以使用以下命令创建:

flutter create signalr_flutter_app
cd signalr_flutter_app

2. 添加netcore_signalr依赖

在你的pubspec.yaml文件中添加netcore_signalr依赖:

dependencies:
  flutter:
    sdk: flutter
  netcore_signalr: ^最新版本号  # 请替换为实际的最新版本号

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

3. 配置SignalR客户端

在你的lib目录下,打开main.dart文件,并进行如下修改:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter SignalR Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SignalRScreen(),
    );
  }
}

class SignalRScreen extends StatefulWidget {
  @override
  _SignalRScreenState createState() => _SignalRScreenState();
}

class _SignalRScreenState extends State<SignalRScreen> {
  late SignalRHubConnection _connection;
  final TextEditingController _messageController = TextEditingController();
  final List<String> _messages = [];

  @override
  void initState() {
    super.initState();
    _initSignalRConnection();
  }

  void _initSignalRConnection() {
    // 配置SignalR连接
    _connection = SignalRHubConnection(
      url: 'https://你的signalr服务器地址/你的hub路径', // 替换为你的SignalR服务器URL
    );

    // 监听接收到的消息
    _connection.on('ReceiveMessage', (arguments) {
      setState(() {
        _messages.add(arguments['message']);
      });
    });

    // 尝试连接SignalR服务器
    _connection.start().then((_) {
      print('Connected to SignalR server');
    }).catchError((error) {
      print('Failed to connect to SignalR server: $error');
    });
  }

  void _sendMessage() {
    final message = _messageController.text;
    if (message.isNotEmpty) {
      // 发送消息到SignalR服务器
      _connection.invoke('SendMessage', {'message': message}).then((_) {
        setState(() {
          _messageController.clear();
          _messages.add('You: $message');
        });
      }).catchError((error) {
        print('Failed to send message: $error');
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter SignalR Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Expanded(
              child: ListView.builder(
                itemCount: _messages.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    title: Text(_messages[index]),
                  );
                },
              ),
            ),
            TextField(
              controller: _messageController,
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Message',
                suffixIcon: IconButton(
                  icon: Icon(Icons.send),
                  onPressed: _sendMessage,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    // 关闭SignalR连接
    _connection.stop();
    super.dispose();
  }
}

4. 运行Flutter应用

确保你的SignalR服务器正在运行,并且URL和Hub路径配置正确。然后,你可以通过运行以下命令来启动Flutter应用:

flutter run

这个示例展示了如何使用netcore_signalr插件在Flutter应用中实现实时通信。你可以根据需要扩展这个示例,比如处理更多类型的消息、增加错误处理等。

回到顶部