快速开始

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

前提条件

开始前,请确保你的开发环境满足如下要求:

  • Xcode 12.4 或以上版本,包括命令行工具;
  • iOS 11 或以上版本;
  • Android SDK API 等级 21 或以上版本;
  • Android Studio 4.0 或以上版本,包括 JDK 1.8 或以上版本;
  • CocoaPods 包管理工具;
  • Flutter 3.3.0 或以上版本;
  • Dart 3.3.0 或以上版本;

配置开发或者运行环境如果遇到问题,请参考 这里

项目设置

使用命令创建项目

打开终端,进入需要创建项目的目录,输入命令进行 flutter create 项目创建:

flutter create quick_start

设置 Android

  1. 打开文件 quick_start/android/app/build.gradle 在文件最后添加:
android {
    defaultConfig {
        minSdkVersion 21
    }
}
  1. 打开文件 quick_start/android/app/src/main/AndroidManifest.xml,在 </application> 下添加:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
  1. quick_start/android/app/proguard-rules.pro 中设置免混淆规则:
-keep class io.agora.** {*;}
-dontwarn  io.agora.**

设置 iOS

iOS 需要 iOS 11.0 以上版本,

打开文件 quick_start/ios/Runner.xcodeproj,修改:TARGETS -> General -> Deployment info, 设置 iOS 版本为 11.0。

集成 SDK

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

cd quick_start
flutter pub add shengwang_chat_sdk
flutter pub get

添加示例代码

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

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

修改 _MyHomePageState 代码:

class _MyHomePageState extends State<MyHomePage> {

  ScrollController scrollController = ScrollController();
  String _username = "";
  String _token = "";
  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 token"),
              onChanged: (token) => _token = token,
            ),
            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(height: 10),
            TextField(
              decoration: const InputDecoration(
                  hintText: "Enter the username you want to send"),
              onChanged: (chatId) => _chatId = chatId,
            ),
            TextField(
              decoration: const InputDecoration(hintText: "Enter content"),
              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 {
  }

  void _addChatListener() {
  }

  void _signIn() async {
  }

  void _signOut() async {
  }

  void _sendMessage() async {
  }

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

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

初始化 SDK

_initSDK 方法中添加 SDK 初始化:

void _initSDK() async {
    ChatOptions options = ChatOptions.withAppId(
        "<#Your AppId#>",
        autoLogin: false,
    );
    await ChatClient.getInstance.init(options);
    // 通知 SDK UI 已准备好。该方法执行后才会收到 `ChatRoomEventHandler`、`ChatContactEventHandler` 和 `ChatGroupEventHandler` 回调。
    await ChatClient.getInstance.startCallback();
}

注册即时通讯 IM 用户

创建用户

声网控制台按照如下步骤创建用户:

  1. 展开控制台左上角下拉框,选择需要开通即时通讯 IM 服务的项目。

  2. 点击左侧导航栏的全部产品

  3. 在下拉列表中找到即时通讯 IM 并点击。

  4. 即时通讯 IM 页面,进入运营管理标签页。

  5. 用户 页签下,点击创建IM用户

  6. 在弹出的对话框中,配置用户相关参数,点击确定

获取用户 token

创建用户后,在用户列表点击对应的用户的操作一栏中的更多,选择查看Token

在弹出的对话框中,可以查看用户 Token,也可以点击重新生成,生成用户 token。

添加登录

_signIn 方法中添加登录代码。

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

    try {
        await ChatClient.getInstance.loginWithToken(_username, _token);
        _addLogToConsole("sign in succeed, username: $_username");
    } on ChatError catch (e) {
        _addLogToConsole("sign in failed, e: ${e.code} , ${e.description}");
    }
}

添加退出

_signOut 方法中添加退出代码。

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

添加发消息

_sendMessage 方法中添加发消息代码。

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

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

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

添加收消息监听

_addChatListener 方法中添加代码。

void _addChatListener() {

  // 添加消息状态变更监听
  ChatClient.getInstance.chatManager.addMessageEvent(
      // ChatMessageEvent 对应的 key。
        "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}",
            );
          },
        ));


  // 添加收消息监听
  ChatClient.getInstance.chatManager.addEventHandler(
    // ChatEventHandler 对应的 key。
    "UNIQUE_HANDLER_ID",
    ChatEventHandler(
      onMessagesReceived: (messages) {
        for (var msg in messages) {
          switch (msg.body.type) {
            case MessageType.TXT:
              {
                ChatTextMessageBody body = msg.body as ChatTextMessageBody;
                _addLogToConsole(
                  "receive text message: ${body.content}, from: ${msg.from}",
                );
              }
              break;
            case MessageType.IMAGE:
              {
                _addLogToConsole(
                  "receive image message, from: ${msg.from}",
                );
              }
              break;
            case MessageType.VIDEO:
              {
                _addLogToConsole(
                  "receive video message, from: ${msg.from}",
                );
              }
              break;
            case MessageType.LOCATION:
              {
                _addLogToConsole(
                  "receive location message, from: ${msg.from}",
                );
              }
              break;
            case MessageType.VOICE:
              {
                _addLogToConsole(
                  "receive voice message, from: ${msg.from}",
                );
              }
              break;
            case MessageType.FILE:
              {
                _addLogToConsole(
                  "receive image message, from: ${msg.from}",
                );
              }
              break;
            case MessageType.CUSTOM:
              {
                _addLogToConsole(
                  "receive custom message, from: ${msg.from}",
                );
              }
              break;
            case MessageType.COMBINE:
                {
                  _addLogToConsole(
                      "receive combine message, from: ${msg.from}");
              }
              break;
            case MessageType.CMD:
              {
                // 当前回调中不会有 CMD 类型消息,CMD 类型消息通过 `ChatEventHandler#onCmdMessagesReceived` 回调接收
              }
              break;
          }
        }
      },
    ),
  );
}

移除消息监听

dispose 方法中添加代码移除监听:

@override
void dispose() {
  // 移除消息状态监听
  ChatClient.getInstance.chatManager.removeMessageEvent("UNIQUE_HANDLER_ID");
  // 移除收消息监听
  ChatClient.getInstance.chatManager.removeEventHandler("UNIQUE_HANDLER_ID");
  super.dispose();
}

运行项目

以 iOS 为例,首先打开模拟器,然后在终端运行以下命令。

flutter run

后续步骤

为保障通信安全,在正式生产环境中,你需要在自己的 app 服务端生成 Token。详见使用 Token 鉴权

Libraries

shengwang_chat_sdk