使用 Flutter 快速实现聊天应用

作者:LeanCloud 小九

你是否曾经想过从头开发一款类似 QQ、微信的聊天应用?又或者,想要在你开发的应用中加入聊天功能,方便用户交流,增强用户粘性?那么,这篇文章就是为你准备的。在这篇文章中,我将介绍如何基于 Flutter 快速实现一款聊天应用。在 2020 年,基于 Flutter 和 BaaS 服务从头开发聊天应用要比大多数人想象中要迅速得多,容易得多。Flutter 的优势在于一份代码可以同时用于 iOS 和 Android 两大平台,进一步加速了应用的开发。

这个基于 Flutter 开发的应用只是一个简单的 Demo,但已经支持如下功能:

  • 登录、登出
  • 发起单聊
  • 发起群聊
  • 支持文字消息、语音消息、图片消息
  • 支持展示未读消息数
  • 支持展示会话成员
  • 支持修改会话名称
  • 支持离线消息推送

应用截屏

如果你是 iOS 用户,还可以从苹果的应用商店安装,亲自体验。

开发环境搭建

Flutter 安装和环境搭建可以查看 Flutter 官方文档,此不赘述。

这个应用将直接使用 [LeanCloud] 这个 BaaS 平台提供的即时通讯解决方案,这就省下了后端开发的时间和精力。因此我们需要先创建 LeanCloud 应用,并在 LeanCloud 「控制台 > 应用 > 设置 > 域名绑定」页面绑定 API 访问域名。暂时没有域名可以略过这一步,LeanCloud 也提供了短期有效的免费体验域名。或者也可以注册LeanCloud 国际版,国际版无需绑定域名。创建应用后,在「控制台 > 应用 > 设置 > 应用 Keys 」页面可以查看 AppID、AppKey 与(REST API)服务器地址(接下来的 SDK 初始化环节需要用到这些信息)。然后按照 LeanCloud SDK 配置文档完成 SDK 初始化配置。

会话列表

大多数聊天应用打开后的第一个页面就是会话列表。会话列表会展示当前用户所参与的会话,会话名称、会话的成员,会话的最后一条消息,还需要展示未读消息数目。

查询当前用户的全部会话只需要下面两行代码:

ConversationQuery query = client.conversationQuery();
await query.find();

按照会话的更新时间排序:

query.orderByDescending('updatedAt');

为了展示会话的最新一条消息,查询的时候要额外加上这行代码:

// 让查询结果附带一条最新消息
query.includeLastMessage = true;

这样会话页面需要的数据就搞定了。

会话查询返回的数据格式是会话(Conversation 类)列表,其中:

  • conversation.name 即会话的名称
  • conversation.members 即会话成员
  • conversation.lastMessage 就是当前会话的最新一条消息了。

基于这些属性,我们可以很方便地在用户界面上显示相关信息。

未读消息数

获取未读消息数也很简单,监听 onUnreadMessageCountUpdated 事件即可。

client.onUnreadMessageCountUpdated = ({
  Client client,
  Conversation conversation,
}) {
  // conversation.unreadMessageCount 即该 conversation 的未读消息数量
};

注意,初始化 Java SDK 的时候需要加上下面这行代码,以开启未读消息数通知:

AVIMOptions.getGlobalOptions().setUnreadNotificationEnabled(true);

swift SDK 默认支持,无需额外设置。

另外需要在以下两处清除未读消息数:

  • 在对话列表点击某对话进入到对话页面时
  • 用户正在某个对话页面聊天,并在这个对话中收到了消息时

会话详情页面

这里简单介绍下如何实现加载历史消息,修改会话名称,图片语音消息。

上拉加载更多历史消息

很简单,先查最近的 10 条消息,然后以第一页的最早的消息作为开始,继续向前拉取消息:

List<Message> messages;
try {
// 第一次查询成功
  messages = await conversation.queryMessage(
    limit: 10,
  );
} catch (e) {
  print(e);
}

try {
  // 返回的消息一定是时间增序排列,也就是最早的消息一定是第一个
  Message oldMessage = messages.first;
  // 以第一页的最早的消息作为开始,继续向前拉取消息
  List<Message> messages2 = await conversation.queryMessage(
    startTimestamp: oldMessage.sentTimestamp,
    startMessageID: oldMessage.id,
    startClosed: true,
    limit: 10,
  );
} catch (e) {
  print(e);
}

修改会话名

更新会话名称就更简单了,只需一行代码:

await conversation.updateInfo(attributes: {
  'name': 'New Name',
});

图片、语音消息

微信中可以发送语音消息,也可以发送图片。要实现类似的功能,一点也不难。 比如发送音频消息,只需两步。

第一步先保存音频文件到云端:

LCFile file = await LCFile.fromPath('message.wav', path);
await file.save();

第二步,发消息:

AudioMessage audioMessage = AudioMessage.from(
  binaryData: file.data,
  format: 'wav',
);
await this.widget.conversation.send(message: audioMessage);

简单吧?图片消息和语音消息类似,只不过存到云端的文件不是音频是图片,发的消息是 ImageMessage

还要注意,移动设备发送图片消息需要相册和相机权限,语音消息需要麦克风权限,别忘了在应用初始化时配置。

离线推送通知

当用户下线以后,收到消息的时候,往往希望能有推送提醒。最简单的一种推送设置就是在 LeanCloud 控制台 > 消息 > 即时通讯 > 设置 > 离线推送设置 页面,填入:

{ "alert": "您有新的消息", "badge": "Increment" }

这样 iOS 设备有离线消息的时候会收到提醒。这里 badge 参数为 iOS 设备专用,用于增加应用 badge 上的数字计数。

注意,iOS 推送一定要正确配置 配置 APNs 推送证书,并在 Xcode 打开推送开关:

xcode 截屏

还要在代码中开启推送,具体参考项目仓库中的 AppDelegate.swift 文件。

如果想在 Android 设备上实现离线推送,要增加一步接入Android 混合推送

给读者的作业

你可能已经注意到这个应用是直接选择联系人列表中的用户名进行聊天。这是因为 LeanCloud 即时通信服务只需要传入一个唯一标识字符串(clientId)就可以表示一个「用户」。这样,如果你现有的应用已经有独立的用户系统,想要加入聊天功能,就很方便了。如果你有兴趣的话,可以尝试接入自己的用户系统,或者尝试使用 LeanCloud 内置的用户系统

此外,这个应用只用到了文本消息、图像消息、语音消息,但其实 LeanCloud SDK 还支持视频消息、文件消息、带地理位置的消息,也支持自定义消息类型。感兴趣的读者可以尝试加上这些功能。

在实际项目中,离线消息的提醒往往会要求更加具体,比如推送中要包括消息的内容或者消息类型等。LeanCloud 也提供了其他几种定制离线推送的方法,感兴趣的话,可以参考文档尝试实现。

参考链接

题图 Daniel Korpai

评论

Loading comments ...