Flutter实时聊天插件stream_chat的使用

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

Flutter实时聊天插件stream_chat的使用

概述

stream_chat 是由 Stream 提供的官方 Dart 客户端,用于构建聊天应用程序。这个库可以在任何 Dart 项目中使用,并且适用于Flutter移动和Web应用。

快速开始

添加依赖

pubspec.yaml 文件中添加 stream_chat 依赖:

dependencies:
  stream_chat: ^latest-version

然后运行 flutter packages get

示例项目

example 文件夹中有一个详细的 Flutter 示例项目,可以直接运行并尝试。

设置API客户端

首先需要实例化一个聊天客户端。聊天客户端将管理 API 调用、事件处理并管理与 Stream Chat 服务器的 WebSocket 连接。你应该只创建一次客户端并在整个应用程序中重用它。

final client = StreamChatClient("stream-chat-api-key");

日志记录

默认情况下,聊天客户端会将所有级别为 Warn 或 Error 的消息写入 stdout

更改日志级别

在开发过程中,你可能希望启用更多的日志信息:

final client = StreamChatClient("stream-chat-api-key", logLevel: Level.INFO);

自定义日志记录器

你可以直接处理日志消息而不是将其写入 stdout

myLogHandlerFunction = (LogRecord record) {
  // do something with the record (ie. send it to Sentry or Fabric)
}

final client = StreamChatClient("stream-chat-api-key", logHandlerFunction: myLogHandlerFunction);

离线存储

为了添加数据持久性,可以扩展 ChatPersistenceClient 类并传递实例给 StreamChatClient。我们提供了一个官方的持久化客户端在 stream_chat_persistence 包中。

import 'package:stream_chat_persistence/stream_chat_persistence.dart';

final chatPersistentClient = StreamChatPersistenceClient(
  logLevel: Level.INFO,
  connectionMode: ConnectionMode.background,
);

final client = StreamChatClient(
  apiKey ?? kDefaultStreamApiKey,
  logLevel: Level.INFO,
)..chatPersistenceClient = chatPersistentClient;

示例代码

以下是一个完整的示例,展示了如何使用 stream_chat 创建一个简单的聊天界面。

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

Future<void> main() async {
  final client = StreamChatClient(
    'b67pax5b2wdq',
    logLevel: Level.INFO,
  );

  await client.connectUser(
    User(
      id: 'cool-shadow-7',
      name: 'Cool Shadow',
      image: 'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow',
    ),
    '''eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiY29vbC1zaGFkb3ctNyJ9.gkOlCRb1qgy4joHPaxFwPOdXcGvSPvp6QY0S4mpRkVo''',
  );

  final channel = client.channel('messaging', id: 'godevs');
  await channel.watch();

  runApp(
    StreamExample(
      client: client,
      channel: channel,
    ),
  );
}

class StreamExample extends StatelessWidget {
  const StreamExample({
    super.key,
    required this.client,
    required this.channel,
  });

  final StreamChatClient client;
  final Channel channel;

  @override
  Widget build(BuildContext context) => MaterialApp(
        title: 'Stream Chat Dart Example',
        home: HomeScreen(channel: channel),
      );
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({
    super.key,
    required this.channel,
  });

  final Channel channel;

  @override
  Widget build(BuildContext context) {
    final messages = channel.state!.messagesStream;
    return Scaffold(
      appBar: AppBar(
        title: Text('Channel: ${channel.id}'),
      ),
      body: SafeArea(
        child: StreamBuilder<List<Message>?>(
          stream: messages,
          builder: (
            BuildContext context,
            AsyncSnapshot<List<Message>?> snapshot,
          ) {
            if (snapshot.hasData && snapshot.data != null) {
              return MessageView(
                messages: snapshot.data!.reversed.toList(),
                channel: channel,
              );
            } else if (snapshot.hasError) {
              return const Center(
                child: Text(
                  'There was an error loading messages. Please see logs.',
                ),
              );
            }
            return const Center(
              child: SizedBox(
                width: 100,
                height: 100,
                child: CircularProgressIndicator(),
              ),
            );
          },
        ),
      ),
    );
  }
}

class MessageView extends StatefulWidget {
  const MessageView({
    super.key,
    required this.messages,
    required this.channel,
  });

  final List<Message> messages;
  final Channel channel;

  @override
  _MessageViewState createState() => _MessageViewState();
}

class _MessageViewState extends State<MessageView> {
  late final TextEditingController _controller;
  late final ScrollController _scrollController;

  List<Message> get _messages => widget.messages;

  @override
  void initState() {
    super.initState();
    _controller = TextEditingController();
    _scrollController = ScrollController();
  }

  @override
  void dispose() {
    _controller.dispose();
    _scrollController.dispose();
    super.dispose();
  }

  void _updateList() {
    _scrollController.animateTo(
      0,
      duration: const Duration(milliseconds: 200),
      curve: Curves.easeOut,
    );
  }

  @override
  Widget build(BuildContext context) => Column(
        children: [
          Expanded(
            child: ListView.builder(
              controller: _scrollController,
              itemCount: _messages.length,
              reverse: true,
              itemBuilder: (BuildContext context, int index) {
                final item = _messages[index];
                if (item.user?.id == widget.channel.client.uid) {
                  return Align(
                    alignment: Alignment.centerRight,
                    child: Padding(
                      padding: const EdgeInsets.all(8),
                      child: Text(item.text ?? ''),
                    ),
                  );
                } else {
                  return Align(
                    alignment: Alignment.centerLeft,
                    child: Padding(
                      padding: const EdgeInsets.all(8),
                      child: Text(item.text ?? ''),
                    ),
                  );
                }
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _controller,
                    decoration: const InputDecoration(
                      hintText: 'Enter your message',
                    ),
                  ),
                ),
                Material(
                  type: MaterialType.circle,
                  color: Colors.blue,
                  clipBehavior: Clip.hardEdge,
                  child: InkWell(
                    onTap: () async {
                      if (_controller.value.text.isNotEmpty) {
                        await widget.channel.sendMessage(
                          Message(text: _controller.value.text),
                        );
                        _controller.clear();
                        _updateList();
                      }
                    },
                    child: const Padding(
                      padding: EdgeInsets.all(8),
                      child: Center(
                        child: Icon(
                          Icons.send,
                          color: Colors.white,
                        ),
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      );
}

extension on StreamChatClient {
  String get uid => state.currentUser!.id;
}

通过上述代码,您可以快速搭建一个基于 Stream Chat 的实时聊天应用。更多高级功能和自定义选项请参考官方文档。


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

1 回复

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


当然,以下是一个关于如何在Flutter项目中使用stream_chat插件来实现实时聊天功能的代码示例。这个示例将展示如何设置Stream Chat客户端、连接到聊天服务器、以及显示和发送消息。

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

dependencies:
  flutter:
    sdk: flutter
  stream_chat: ^latest_version  # 请替换为最新版本号
  stream_chat_flutter: ^latest_version  # 请替换为最新版本号

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

接下来,按照以下步骤在你的Flutter应用中实现实时聊天功能:

  1. 初始化Stream Chat客户端

在你的应用的主文件(例如main.dart)中,初始化Stream Chat客户端。

import 'package:flutter/material.dart';
import 'package:stream_chat/stream_chat_dart.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';

void main() {
  // 配置Stream Chat客户端
  final client = StreamChatClient(
    apiKey: 'your_api_key', // 替换为你的Stream API密钥
    appId: 'your_app_id',   // 替换为你的Stream应用ID
  );

  // 使用Provider管理Stream Chat客户端状态
  runApp(
    MultiProvider(
      providers: [
        Provider<StreamChatClient>.value(value: client),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Stream Chat Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ChatScreen(),
    );
  }
}
  1. 创建聊天屏幕

创建一个新的Dart文件(例如chat_screen.dart)来定义聊天屏幕。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:stream_chat/stream_chat_dart.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';

class ChatScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final client = Provider.of<StreamChatClient>(context);
    final user = client.currentUser!; // 假设当前用户已经登录

    // 创建聊天频道
    final channel = client.channel(
      'messaging',
      id: 'general', // 频道ID,可以根据需要修改
      type: ChannelType.messaging,
    );

    return Scaffold(
      appBar: AppBar(
        title: Text('Chat Screen'),
      ),
      body: StreamChat(
        client: client,
        channel: channel,
        builder: (context, state) {
          if (state is ChatBlocLoadingState) {
            return Center(child: CircularProgressIndicator());
          } else if (state is ChatBlocErrorState) {
            return Center(child: Text('Error: ${state.error.message}'));
          } else if (state is ChatBlocReadyState) {
            return Chat(
              messages: state.messages,
              user: user,
              onSendMessage: (message) async {
                try {
                  await channel.sendMessage(Message(
                    text: message,
                    user: user,
                  ));
                } catch (e) {
                  // 处理发送消息时的错误
                }
              },
            );
          }
          return Container();
        },
      ),
    );
  }
}
  1. 处理用户登录(可选,但通常是必需的):

在实际应用中,你可能需要处理用户的登录。这可以通过Stream Chat的认证系统来完成,或者通过你自己的后端服务。以下是一个简单的用户登录示例:

// 假设你有一个函数`loginUser`来处理用户登录
Future<void> loginUser(StreamChatClient client) async {
  // 这里应该是你的登录逻辑
  // 例如,调用你的后端API获取用户令牌,并使用该令牌登录到Stream Chat
  final token = 'user_auth_token'; // 替换为用户认证令牌
  await client.connectUser(
    User(
      id: 'user_id', // 替换为用户ID
      name: 'User Name', // 替换为用户名
    ),
    token: token,
  );
}

你可以在应用启动时调用loginUser函数来登录用户。

请注意,以上代码示例是一个简化的版本,用于展示如何使用stream_chat插件在Flutter中实现基本的实时聊天功能。在实际应用中,你可能需要处理更多的边缘情况、错误处理、用户身份验证等。此外,请确保遵循Stream Chat的最佳实践和API文档来构建你的应用。

回到顶部