Flutter即时通讯插件im_flutter_sdk的使用

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

Flutter即时通讯插件im_flutter_sdk的使用

通过本文可以实现一个集成聊天 SDK 的简单 app。

实现原理

发送和接收单聊消息的步骤如下:

  1. 客户端向你的应用服务器请求 Token,你的应用服务器返回 Token。
  2. 客户端 A 和客户端 B 使用获得的 Token 登录环信即时通讯系统。
  3. 客户端 A 发送消息到环信即时通讯服务器。
  4. 环信即时通讯服务器将消息发送到客户端 B,客户端 B 接收消息。

前提条件

  • Xcode 12.4 或以上版本(iOS)
  • iOS 10 或以上版本(iOS)
  • Android SDK API 等级 21 或以上版本(Android)
  • Android Studio 4.0 或以上版本,包括 JDK 1.8 或以上版本(Android)
  • CocoaPods 包管理工具(iOS)
  • Flutter 2.10 或以上版本
  • Dart 2.16 或以上版本
  • 有效的环信即时通讯 IM 开发者账号和 App Key

项目设置

使用命令创建项目

flutter create quick_start

设置 Android

打开文件 quick_start/android/app/build.gradle 在文件最后添加:

android {
    defaultConfig {
        minSdkVersion 21
    }
}

quick_start/android/app/proguard-rules.pro 中设置免混淆规则:

-keep class com.hyphenate.** {*;}
-dontwarn  com.hyphenate.**

设置 iOS

打开文件 quick_start/ios/Runner.xcodeproj,然后:

  • 找到 TARGETS > RunnerGeneralDeployment Info 中修改最低版本为 iOS 10.0

集成 SDK

在终端命令行,输入命令添加依赖:

cd quick_start
flutter pub add im_flutter_sdk
flutter pub get

添加示例代码

打开 quick_start/lib/main.dart 文件,引入头文件:

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

修改 _MyHomePageState 代码:

class _MyHomePageState extends State<MyHomePage> {
  ScrollController scrollController = ScrollController();
  String _username = "";
  String _password = "";
  String _messageContent = "";
  String _chatId = "";
  final List<String> _logText = [];

  @override
  void initState() {
    super.initState();
    _initSDK();
    _addChatListener();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Container(
        padding: const EdgeInsets.only(left: 10, right: 10),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          mainAxisSize: MainAxisSize.max,
          children: [
            TextField(
              decoration: const InputDecoration(hintText: "Enter username"),
              onChanged: (username) => _username = username,
            ),
            TextField(
              decoration: const InputDecoration(hintText: "Enter password"),
              onChanged: (password) => _password = password,
            ),
            const SizedBox(height: 10),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                Expanded(
                  flex: 1,
                  child: TextButton(
                    onPressed: _signIn,
                    child: const Text("SIGN IN"),
                    style: ButtonStyle(
                      foregroundColor: MaterialStateProperty.all(Colors.white),
                      backgroundColor:
                          MaterialStateProperty.all(Colors.lightBlue),
                    ),
                  ),
                ),
                const SizedBox(width: 10),
                Expanded(
                  child: TextButton(
                    onPressed: _signOut,
                    child: const Text("SIGN OUT"),
                    style: ButtonStyle(
                      foregroundColor: MaterialStateProperty.all(Colors.white),
                      backgroundColor:
                          MaterialStateProperty.all(Colors.lightBlue),
                    ),
                  ),
                ),
                const SizedBox(width: 10),
                Expanded(
                  child: TextButton(
                    onPressed: _signUp,
                    child: const Text("SIGN UP"),
                    style: ButtonStyle(
                      foregroundColor: MaterialStateProperty.all(Colors.white),
                      backgroundColor:
                          MaterialStateProperty.all(Colors.lightBlue),
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 10),
            TextField(
              decoration: const InputDecoration(
                  hintText: "Enter recipient's user name"),
              onChanged: (chatId) => _chatId = chatId,
            ),
            TextField(
              decoration: const InputDecoration(hintText: "Enter message"),
              onChanged: (msg) => _messageContent = msg,
            ),
            const SizedBox(height: 10),
            TextButton(
              onPressed: _sendMessage,
              child: const Text("SEND TEXT"),
              style: ButtonStyle(
                foregroundColor: MaterialStateProperty.all(Colors.white),
                backgroundColor: MaterialStateProperty.all(Colors.lightBlue),
              ),
            ),
            Flexible(
              child: ListView.builder(
                controller: scrollController,
                itemBuilder: (_, index) {
                  return Text(_logText[index]);
                },
                itemCount: _logText.length,
              ),
            ),
          ],
        ),
      ),
    );
  }

  void _initSDK() async {
    EMOptions options = EMOptions(
      appKey: "<#Your AppKey#>",
      autoLogin: false,
    );
    await EMClient.getInstance.init(options);
    await EMClient.getInstance.startCallback();
  }

  void _addChatListener() {
    EMClient.getInstance.chatManager.addMessageEvent(
        "UNIQUE_HANDLER_ID",
        ChatMessageEvent(
          onSuccess: (msgId, msg) {
            _addLogToConsole("send message succeed");
          },
          onProgress: (msgId, progress) {
            _addLogToConsole("send message succeed");
          },
          onError: (msgId, msg, error) {
            _addLogToConsole(
              "send message failed, code: ${error.code}, desc: ${error.description}",
            );
          },
        ));

    EMClient.getInstance.chatManager.addEventHandler(
      "UNIQUE_HANDLER_ID",
      EMChatEventHandler(
        onMessagesReceived: (messages) {
          for (var msg in messages) {
            switch (msg.body.type) {
              case MessageType.TXT:
                {
                  EMTextMessageBody body = msg.body as EMTextMessageBody;
                  _addLogToConsole(
                    "receive text message: ${body.content}, from: ${msg.from}",
                  );
                }
                break;
              // 其他类型的消息处理...
            }
          }
        },
      ),
    );
  }

  void _signIn() async {
    if (_username.isEmpty || _password.isEmpty) {
      _addLogToConsole("username or password is null");
      return;
    }

    try {
      await EMClient.getInstance.login(_username, _password);
      _addLogToConsole("sign in succeed, username: $_username");
    } on EMError catch (e) {
      _addLogToConsole("sign in failed, e: ${e.code} , ${e.description}");
    }
  }

  void _signOut() async {
    try {
      await EMClient.getInstance.logout(true);
      _addLogToConsole("sign out succeed");
    } on EMError catch (e) {
      _addLogToConsole(
          "sign out failed, code: ${e.code}, desc: ${e.description}");
    }
  }

  void _signUp() async {
    if (_username.isEmpty || _password.isEmpty) {
      _addLogToConsole("username or password is null");
      return;
    }

    try {
      await EMClient.getInstance.createAccount(_username, _password);
      _addLogToConsole("create account succeed, username: $_username");
    } on EMError catch (e) {
      _addLogToConsole(
          "create account failed, code: ${e.code}, desc: ${e.description}");
    }
  }

  void _sendMessage() async {
    if (_chatId.isEmpty || _messageContent.isEmpty) {
      _addLogToConsole("single chat id or message content is null");
      return;
    }

    var msg = EMMessage.createTxtSendMessage(
      targetId: _chatId,
      content: _messageContent,
    );

    EMClient.getInstance.chatManager.sendMessage(msg);
  }

  void _addLogToConsole(String log) {
    _logText.add(_timeString + ": " + log);
    setState(() {
      scrollController.jumpTo(scrollController.position.maxScrollExtent);
    });
  }

  String get _timeString {
    return DateTime.now().toString().split(".").first;
  }

  @override
  void dispose() {
    EMClient.getInstance.chatManager.removeMessageEvent("UNIQUE_HANDLER_ID");
    EMClient.getInstance.chatManager.removeEventHandler("UNIQUE_HANDLER_ID");
    super.dispose();
  }
}

运行项目

以 iOS 为例,首先打开模拟器,之后在终端输入:

flutter run

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

1 回复

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


当然,下面是一个关于如何在Flutter项目中使用im_flutter_sdk插件进行即时通讯的基本示例代码。请注意,这只是一个基本的实现示例,具体的使用可能会根据im_flutter_sdk的版本和即时通讯平台(如环信、融云等)的不同而有所差异。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加im_flutter_sdk的依赖:

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

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

2. 初始化SDK

在你的main.dart文件中,初始化SDK并进行基本的配置。以下是一个示例:

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

void main() {
  // 初始化SDK
  IMFlutterSDK.init({
    "appKey": "你的AppKey",  // 替换为你的AppKey
    "serverHost": "你的服务器地址",  // 替换为你的服务器地址
    // 其他配置项,如是否启用调试模式等
  });

  runApp(MyApp());
}

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

class IMHomeScreen extends StatefulWidget {
  @override
  _IMHomeScreenState createState() => _IMHomeScreenState();
}

class _IMHomeScreenState extends State<IMHomeScreen> {
  @override
  void initState() {
    super.initState();
    // 可以在这里添加登录逻辑
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('IM Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('这里是IM首页'),
            // 你可以添加按钮来触发发送消息、查看聊天列表等操作
            ElevatedButton(
              onPressed: () {
                // 示例:发送消息
                sendMessage("接收者ID", "Hello, this is a test message!");
              },
              child: Text('发送消息'),
            ),
          ],
        ),
      ),
    );
  }

  void sendMessage(String toUserId, String content) {
    // 发送消息的示例代码,具体实现需要参考im_flutter_sdk的文档
    IMFlutterSDK.sendMessage({
      "toUserId": toUserId,
      "content": content,
      "messageType": "text",  // 根据需要设置消息类型,如文本、图片等
    }).then((result) {
      // 处理发送结果
      print("发送结果: $result");
    }).catchError((error) {
      // 处理发送错误
      print("发送错误: $error");
    });
  }
}

3. 处理回调和事件

为了处理即时通讯中的各种回调和事件(如收到新消息、用户登录状态变化等),你需要在适当的地方添加事件监听器。例如:

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

  // 添加收到新消息的监听器
  IMFlutterSDK.addMessageListener((message) {
    // 处理新消息
    print("收到新消息: $message");
  });

  // 添加登录状态变化的监听器
  IMFlutterSDK.addConnectionListener((status) {
    // 处理登录状态变化
    print("登录状态变化: $status");
  });

  // 可以在这里添加登录逻辑
  IMFlutterSDK.login({
    "userId": "你的用户ID",
    "token": "你的登录Token",  // 或者其他登录凭证
  }).then((result) {
    // 处理登录结果
    print("登录结果: $result");
  }).catchError((error) {
    // 处理登录错误
    print("登录错误: $error");
  });
}

4. 清理资源

在适当的时机(如应用退出时),记得清理资源:

@override
void dispose() {
  // 移除监听器
  IMFlutterSDK.removeMessageListener(null);  // 或者传入具体的监听器ID
  IMFlutterSDK.removeConnectionListener(null);  // 或者传入具体的监听器ID

  // 注销登录(可选)
  IMFlutterSDK.logout().then((result) {
    // 处理注销结果
    print("注销结果: $result");
  }).catchError((error) {
    // 处理注销错误
    print("注销错误: $error");
  });

  super.dispose();
}

注意事项

  1. 依赖版本:确保你使用的im_flutter_sdk版本与你的即时通讯平台兼容。
  2. 文档:详细的功能和API使用方法请参考im_flutter_sdk的官方文档。
  3. 错误处理:在实际应用中,添加更详细的错误处理逻辑,以提高应用的健壮性。
  4. UI设计:根据实际需求,设计更符合用户习惯的UI界面。

以上示例代码仅用于演示如何在Flutter项目中使用im_flutter_sdk插件进行基本的即时通讯功能。具体实现时,请根据你的即时通讯平台和业务需求进行调整。

回到顶部