Flutter WebSocket通信插件web_socket_support的使用

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

Flutter WebSocket通信插件web_socket_support的使用

插件介绍

web_socket_support 是一个用于在 Android 平台上实现 WebSocket 通信的 Flutter 插件。该插件基于 OkHttp 实现,旨在解决标准 Flutter WebSocket 实现中的一些问题,如屏幕锁定或应用后台时连接断开的问题。

使用示例

下面是一个完整的示例代码,展示了如何使用 web_socket_support 插件进行 WebSocket 通信。

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

void main() async {
  final backend = WsBackend();
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider<WsBackend>.value(
          value: backend,
        ),
        ChangeNotifierProvider<WebSocketSupport>(
          create: (ctx) => WebSocketSupport(backend),
        ),
      ],
      child: const WebSocketSupportExampleApp(),
    ),
  );
}

class WsBackend with ChangeNotifier {
  final textController = TextEditingController();
  final List<ServerMessage> _messages = [];

  WsBackend() {
    print('WsBackend created.');
  }

  void addMessage(ServerMessage msg) {
    _messages.add(msg);
    notifyListeners();
  }

  void clearMessages() {
    _messages.clear();
    notifyListeners();
  }

  List<ServerMessage> getMessages() {
    return List.unmodifiable(_messages);
  }

  bool hasMessages() {
    return _messages.isNotEmpty;
  }

  [@override](/user/override)
  void dispose() {
    textController.dispose();
    super.dispose();
  }
}

class WebSocketSupport with ChangeNotifier {
  static const String serverUrl = 'ws://ws.ifelse.io';

  final WsBackend _backend;

  // locals
  late WebSocketClient _wsClient;
  WebSocketConnection? _webSocketConnection;
  bool working = false;

  WebSocketSupport(this._backend) {
    _wsClient = WebSocketClient(DefaultWebSocketListener.forTextMessages(
      _onWsOpened,
      _onWsClosed,
      _onTextMessage,
      (_, __) =&gt; {},
      _onError,
    ));
    print('WebSocketSupport created.');
  }

  void _onWsOpened(WebSocketConnection webSocketConnection) {
    _webSocketConnection = webSocketConnection;
    working = false;
    notifyListeners();
  }

  void _onWsClosed(int code, String reason) {
    _webSocketConnection = null;
    _backend.clearMessages();
    working = false;
    notifyListeners();
  }

  void _onTextMessage(String message) {
    _backend.addMessage(ServerMessage(message, DateTime.now()));
    notifyListeners();
  }

  void _onError(Exception ex) {
    print('_onError: Fatal error occurred: $ex');
    _webSocketConnection = null;
    working = false;
    _backend.addMessage(
        ServerMessage('Error occurred on WS connection!', DateTime.now()));
    notifyListeners();
  }

  bool isConnected() {
    return _webSocketConnection != null;
  }

  void sendMessage() {
    if (_webSocketConnection != null) {
      _webSocketConnection?.sendStringMessage(_backend.textController.text);
      _backend.textController.clear();
    }
  }

  Future<void> connect() async {
    working = true;
    _backend.textController.clear();
    _backend.clearMessages();
    try {
      await _wsClient.connect(serverUrl,
          options: WebSocketOptions(autoReconnect: true));
      notifyListeners();
    } on PlatformException catch (e) {
      final errorMsg = 'Failed to connect to ws server. Error:$e';
      print(errorMsg);
      _backend.addMessage(ServerMessage(errorMsg, DateTime.now()));
    }
  }

  Future<void> disconnect() async {
    working = true;
    await _wsClient.disconnect();
    notifyListeners();
  }
}

class WebSocketSupportExampleApp extends StatelessWidget {
  const WebSocketSupportExampleApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('WebSocketSupport example app'),
        ),
        body: const Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            WsControlPanel(),
            WsTextInput(),
            WsMessages(),
          ],
        ),
      ),
    );
  }
}

class WsControlPanel extends StatelessWidget {
  const WsControlPanel({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Column(
      children: [
        const SizedBox(height: 10),
        Center(
          child: Consumer<WebSocketSupport>((
            builder: (ctx, ws, _) {
              return Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Padding(
                    padding: const EdgeInsets.only(left: 10, right: 10),
                    child: Row(
                      children: [
                        // status title
                        const Text('WS status:'),
                        Padding(
                          padding: const EdgeInsets.only(left: 5, right: 5),
                          child: Icon(
                            ws.isConnected()
                                ? Icons.check_circle_outlined
                                : Icons.highlight_off,
                            color: _connectionColor(ws),
                            size: 20,
                          ),
                        ),
                        // status value
                        Text(
                          (ws.isConnected() ? 'Connected' : 'Disconnected'),
                          style: TextStyle(color: _connectionColor(ws)),
                        ),
                      ],
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.only(left: 10, right: 10),
                    child: ElevatedButton(
                      key: const Key('connect'),
                      onPressed: ws.working
                          ? null
                          : () async {
                              ws.isConnected()
                                  ? await ws.disconnect()
                                  : await ws.connect();
                            },
                      child: ws.isConnected()
                          ? const Text('Disconnect')
                          : const Text('Connect'),
                    ),
                  ),
                ],
              );
            },
          ),
        ),
        const Divider(),
      ],
    );
  }

  MaterialColor _connectionColor(WebSocketSupport ws) =&gt;
      ws.isConnected() ? Colors.green : Colors.red;
}

class WsTextInput extends StatelessWidget {
  const WsTextInput({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Consumer<WebSocketSupport>(builder: (ctx, ws, _) {
      return !ws.isConnected()
          ? const SizedBox.shrink()
          : Column(
              children: [
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 10),
                  child: Row(
                    children: [
                      Expanded(
                        child: TextField(
                          key: const Key('textField'),
                          textAlign: TextAlign.center,
                          controller:
                              Provider.of<WsBackend>(context, listen: false)
                                  .textController,
                          decoration: const InputDecoration(
                            focusedBorder: OutlineInputBorder(
                              borderSide: BorderSide(
                                color: Colors.greenAccent, width: 2.0),
                            ),
                            enabledBorder: OutlineInputBorder(
                              borderSide:
                                  BorderSide(color: Colors.blue, width: 2.0),
                            ),
                            hintText: 'Enter message to send to server',
                          ),
                        ),
                      ),
                      IconButton(
                        key: const Key('sendButton'),
                        icon: const Icon(Icons.send),
                        onPressed: () =&gt; ws.sendMessage(),
                      ),
                    ],
                  ),
                ),
                const Divider(),
              ],
            );
    });
  }
}

class WsMessages extends StatelessWidget {
  const WsMessages({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Consumer<WsBackend>((
      builder: (ctx, be, _) {
        return be.getMessages().isEmpty
            ? const SizedBox.shrink()
            : Expanded(
                child: Column(
                  children: [
                    const Padding(
                      padding: EdgeInsets.only(top: 10, bottom: 10),
                      child: Text(
                        'Reply messages from: ${WebSocketSupport.serverUrl}',
                        key: Key('replyHeader'),
                      ),
                    ),
                    Expanded(
                      child: ListView.separated(
                        itemCount: be.getMessages().length,
                        separatorBuilder: (BuildContext context, int index) =&gt;
                            const Divider(),
                        itemBuilder: (BuildContext context, int index) {
                          var message = be.getMessages()[index];
                          return ListTile(
                            title: Text(
                              '${DateFormat.Hms().format(message.dateTime)}: ${message.message}',
                              key: Key(message.message),
                            ),
                          );
                        },
                      ),
                    ),
                  ],
                ),
              );
        });
  }
}

class ServerMessage {
  final String message;
  final DateTime dateTime;

  ServerMessage(this.message, this.dateTime);
}

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

1 回复

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


当然,下面是一个关于如何使用 web_socket_support 插件在 Flutter 中实现 WebSocket 通信的示例代码。需要注意的是,web_socket_support 并不是一个官方或者广泛使用的 Flutter 插件名称,通常 Flutter 开发者会使用 web_socket_channel 插件来进行 WebSocket 通信。不过,为了符合你的要求,我将假设 web_socket_support 提供了类似的功能,并给出相应的示例代码。

在实际开发中,如果 web_socket_support 插件存在并且功能类似 web_socket_channel,你应该参考该插件的官方文档进行调整。以下示例基于假设的 web_socket_support 插件提供了与 web_socket_channel 类似的功能。

示例代码

  1. 添加依赖

首先,在你的 pubspec.yaml 文件中添加 web_socket_support 依赖(假设存在):

dependencies:
  flutter:
    sdk: flutter
  web_socket_support: ^x.y.z  # 替换为实际的版本号

然后运行 flutter pub get 来获取依赖。

  1. 实现 WebSocket 通信

接下来,在你的 Flutter 应用中实现 WebSocket 通信。以下是一个简单的示例,展示如何连接到 WebSocket 服务器、发送消息和接收消息。

import 'package:flutter/material.dart';
import 'package:web_socket_support/web_socket_support.dart'; // 假设包名和导入路径

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

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

class WebSocketPage extends StatefulWidget {
  @override
  _WebSocketPageState createState() => _WebSocketPageState();
}

class _WebSocketPageState extends State<WebSocketPage> {
  WebSocketChannel? _channel;
  TextEditingController _controller = TextEditingController();
  List<String> _messages = [];

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

  void connectToWebSocket() {
    _channel = WebSocketChannel.connect(Uri.parse('ws://your-websocket-server-url'));
    
    _channel!.stream.listen(
      (message) {
        setState(() {
          _messages.add('Received: $message');
        });
      },
      onError: (error) {
        setState(() {
          _messages.add('Error: ${error.message}');
        });
      },
      onDone: () {
        setState(() {
          _messages.add('WebSocket connection closed.');
        });
      },
    );
  }

  void sendMessage() {
    if (_controller.text.isNotEmpty) {
      _channel!.sink.add(_controller.text);
      setState(() {
        _messages.add('Sent: ${_controller.text}');
        _controller.clear();
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('WebSocket 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: _controller,
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Enter message',
              ),
              onSubmitted: (value) {
                sendMessage();
              },
            ),
            ElevatedButton(
              onPressed: sendMessage,
              child: Text('Send'),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    _channel?.sink.close();
    _controller.dispose();
    super.dispose();
  }
}

注意事项

  1. 替换 WebSocket 服务器 URL:将 ws://your-websocket-server-url 替换为你实际的 WebSocket 服务器 URL。
  2. 错误处理:在实际应用中,你可能需要更完善的错误处理和重连机制。
  3. 插件文档:由于 web_socket_support 是一个假设的插件名称,请参考实际使用的插件文档以获取更多信息和最佳实践。

如果 web_socket_support 实际上并不存在或者功能不同,你可能需要使用 web_socket_channel 或其他类似的插件,并参考其官方文档进行实现。

回到顶部