Flutter实时通信插件x_action_cable的使用

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

Flutter实时通信插件x_action_cable的使用

ActionCable 是 Rails 默认的实时 WebSocket 框架和协议。

这个库是 ActionCable 的 Dart 端口,适用于 Web、DartVM 和 Flutter。它与其他库的主要区别在于它使用的某些模式。例如,服务器的响应需要符合我们期望的格式,并且会根据最新的 Dart 特性来改进代码(我知道我们仍然有一些代码需要改进)。更多细节见下文。

使用方法

连接到 WebSocket

final cable = ActionCable.connect(
  'ws://127.0.0.1:3000/cable',
  headers: {
    'Authorization': 'jwt-token',
  },
  onConnected: () {
    print('connected');
  }, 
  onConnectionLost: () {
    print('connection lost');
  }, 
  onCannotConnect: () {
    print('cannot connect');
  },
);

订阅频道

void receiveMessage(Map payload) => print(payload);
final actionCallback = ActionCallback(name: 'on_receive_message', callback: receiveMessage);

ActionChannel channel = cable.subscribe(
  'Chat', // 可以是 'Chat' 或 'ChatChannel'
  channelParams: { 'room': 'private' },
  onSubscribed: () {}, // 收到 'confirm_subscription' 后调用
  onDisconnected: () {}, // 收到 'disconnect' 后调用
  callbacks: [actionCallback], // 服务器可以调用的所有回调列表
);

当服务器发送带有键 ‘on_receive_message’ 的数据时,库将能够识别并正确调用回调。

例如,服务器需要发送的数据如下:

ActionCable.server.broadcast("notifications_#{current_user}", {method: "on_receive_message", data: { anyData: [1, 2, 3] }})

上面的第二个参数是键 ‘method’,这是库在客户端侧调用回调所需的所有信息。

通过这个 ActionChannel,你还可以从通道对象执行操作。更多信息见下文。

取消订阅频道

首先,让我们看看如何取消订阅频道。记住你创建的 ActionChannel 对象,你将使用相同的对象来取消订阅。

channel.unsubscribe();

就这样,不需要更多的步骤。现在让我们看看如何从客户端向服务器发起操作。

在你的 ActionCable 服务器上执行操作

再次,记住你之前创建的对象?就是通道对象。我们将使用它来执行一个操作。

channel.performAction(
  action: 'send_message',
  actionParams: { 'message': 'Hello private peeps! 😜' }
);

这里有一些其他参数。

  • action: 你要调用的服务器端方法的名称。
  • actionParams: 传递给服务器的参数。

下面是一个 Ruby on Rails 方法的例子:

def send_message(data)
  puts("message: #{data}")
end

断开与 ActionCable 服务器的连接

最后,断开连接时,你需要使用主对象(ActionCable)来断开 WebSocket。

cable.disconnect();

ActionCable 协议

Anycable 在该主题上有非常好的文档。

贡献者 ✨

该项目遵循 all-contributors 规范。欢迎任何形式的贡献!


示例代码

下面是完整的示例代码:

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

void main() => runApp(const MyApp());

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Example',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const HomeScreen(),
    );
  }
}

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

  [@override](/user/override)
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  late final ActionCable cable;
  late final ActionChannel channel;

  [@override](/user/override)
  void initState() {
    super.initState();
    // 连接到 WebSocket
    cable = ActionCable.connect(
      'ws://chat.example.com/cable',
      headers: {'Authorization': 'Some Token'},
      onConnected: onConnected,
      onConnectionLost: onConnectionLost,
      onCannotConnect: onCannotConnect,
    );

    // 订阅频道以接收服务器消息
    // 参数 callbacks 是所有服务器可以在前端应用中调用的方法
    // 首先你需要定义一个 ActionCallback
    // 参数 name 是服务器将调用的名称
    // 参数 callback 是基于名称调用的方法
    // 如果服务器发送带有参数 "method": "on_receive_message" 的消息,
    // 库将为你调用 onReceiveMessage。
    // 库期望服务器发送的数据格式为:{"method": "on_receive_message", "data": "任何消息"}
    final onMessageCallback = ActionCallback(
      name: 'on_receive_message',
      callback: onReceiveMessage,
    );

    channel = cable.subscribe(
      'Chat',
      onSubscribed: onChannelSubscribed,
      callbacks: [onMessageCallback],
    );
  }

  void onConnected() => debugPrint('connected');
  void onConnectionLost() => debugPrint('connection lost');
  void onCannotConnect(dynamic reason) => debugPrint(reason.toString());

  void onChannelSubscribed() {
    debugPrint('Subscribed to the ChatChannel');
    // 订阅频道后,你可以开始向其发送动作
    // 第一个参数是要调用的服务器端方法的名称
    // 参数 [params] 是要发送给服务器的数据
    channel.performAction(
      'send_message',
      params: {'message': 'Hello World'},
    );
  }

  void onReceiveMessage(ActionResponse response) {
    final message = response.data ?? response.error;
    debugPrint('$message');
  }

  [@override](/user/override)
  void dispose() {
    // 最后,你可以断开所有通道
    channel.unsubscribe();

    // 当你断开 WebSocket 连接时,cable 会自动断开连接
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: Text(
          'Example showing how the lib works!\nCurrently we don\'t have any server to supply the example. Be patient',
        ),
      ),
    );
  }
}

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

1 回复

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


当然,以下是如何在Flutter应用中使用x_action_cable插件来实现实时通信的一个基本示例。x_action_cable插件通常用于与Rails的Action Cable进行集成,以实现WebSocket通信。

首先,确保你已经在你的Flutter项目中添加了x_action_cable依赖。你可以在你的pubspec.yaml文件中添加以下依赖项:

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

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

配置Action Cable服务器

假设你已经在Rails中配置好了Action Cable,并且有一个名为ChatChannel的通道,你可以发送和接收消息。

Flutter 客户端代码

以下是一个简单的Flutter应用,展示如何使用x_action_cable插件连接到Action Cable服务器,并发送和接收消息。

  1. 创建一个新的Flutter项目(如果你还没有的话):

    flutter create my_flutter_app
    cd my_flutter_app
    
  2. 修改pubspec.yaml(如上所述)。

  3. 编写Flutter代码

    // main.dart
    import 'package:flutter/material.dart';
    import 'package:x_action_cable/x_action_cable.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Action Cable Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: ChatScreen(),
        );
      }
    }
    
    class ChatScreen extends StatefulWidget {
      @override
      _ChatScreenState createState() => _ChatScreenState();
    }
    
    class _ChatScreenState extends State<ChatScreen> {
      final TextEditingController _messageController = TextEditingController();
      final List<String> _messages = [];
      ActionCableClient? _cableClient;
    
      @override
      void initState() {
        super.initState();
        connectToActionCable();
      }
    
      void connectToActionCable() async {
        // 替换为你的Action Cable服务器URL和通道名称
        String url = 'wss://your-rails-app-url/cable';
        String channel = 'ChatChannel';
    
        _cableClient = await ActionCableClient.connect(url);
        _cableClient!.subscribe(
          channel,
          params: {'room': 'general'}, // 传递任何需要的参数
          onReceived: (data) {
            // 处理接收到的消息
            setState(() {
              _messages.add(data['message']);
            });
          },
          onConnected: () {
            print('Connected to Action Cable');
          },
          onDisconnected: () {
            print('Disconnected from Action Cable');
          },
        );
      }
    
      void sendMessage() {
        if (_messageController.text.isNotEmpty) {
          _cableClient?.perform(
            channel: 'ChatChannel',
            action: 'speak',
            data: {'message': _messageController.text},
          );
          setState(() {
            _messages.add('You: $_messageController.text');
            _messageController.clear();
          });
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Flutter Action Cable Chat'),
          ),
          body: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              children: <Widget>[
                Expanded(
                  child: ListView.builder(
                    itemCount: _messages.length,
                    itemBuilder: (context, index) {
                      return ListTile(
                        title: Text(_messages[index]),
                      );
                    },
                  ),
                ),
                TextField(
                  controller: _messageController,
                  onSubmitted: sendMessage,
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                    labelText: 'Message',
                    suffixIcon: IconButton(
                      icon: Icon(Icons.send),
                      onPressed: sendMessage,
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    
      @override
      void dispose() {
        _cableClient?.disconnect();
        _messageController.dispose();
        super.dispose();
      }
    }
    

解释

  • 连接Action Cable

    • 使用ActionCableClient.connect(url)连接到Action Cable服务器。
    • 使用_cableClient!.subscribe订阅通道,并处理接收到的消息。
  • 发送消息

    • 使用_cableClient?.perform发送消息到服务器。
  • UI

    • 使用ListView.builder显示聊天记录。
    • 使用TextFieldIconButton发送消息。

确保你的Rails服务器正在运行,并且Action Cable配置正确。运行Flutter应用,你应该能够连接到服务器,发送和接收消息。

回到顶部