Vue集成融云实现即时通讯聊天室

·  阅读 1876
Vue集成融云实现即时通讯聊天室

前言

最近把Vue+Element二次封装持续完善了,然后开始着手处理即时通讯这一块了。

之前的老代码用的是融云2.x版本,现在4.x了,自然要更新下,融云4.x变化还是挺大的,很多API都换掉了,但是相对来讲还是比较简单上手的。

由于没有原型图,我直接边设计办coding,对于这种自己发挥的需求,我仍然保持微笑。(这应该是对我审美的肯定吧!)先整了个样图出来如下

融云2.png

高处不胜寒,起舞弄清影。

接下来咱们步入正题

分析需求

项目是一个社交APP的后台管理项目,项目中有个模块是关于聊天室的,链接APP内的聊天大厅,如果有用户发布不良信息,可以禁言用户,同时也可以发布公告消息。

任务

  1. 获取token,链接融云
  2. 获取历史消息并模拟聊天展示出来
  3. 发送消息,这个是由后端完成,我发送消息就请求接口
  4. 可以禁言用户,这个也是由后端来统一完成

关于融云

融云提供的即时通讯服务,不需要在 App 之外建立并行的用户体系,不用同步 App 下用户信息到融云,不影响 App 现有的系统架构与帐号体系,与现有业务体系能够实现完美融合。

兼容说明

ChromeFirefoxSafariIEEdgeQQ 浏览器微信 浏览器Android
9+

导入 SDK

融云 4.x 底层使用 Typescript 进行了重构,对 Typescript 的使用者提供了友好的类型化支持,推荐开发者使用 Typescript 进行业务开发以提升代码健壮性及可维护性。

NPM 引入(推荐)

  1. 依赖安装
npm install @rongcloud/imlib-v4
复制代码
  1. 代码集成
// 非 ESModule
const RongIMLib = require('@rongcloud/imlib-v4')
// ESModule
import * as RongIMLib from '@rongcloud/imlib-v4'
复制代码

CDN 引入

  • index.html
<script src="https://cdn.ronghub.com/RongIMLib-4.3.latest.js"></script>
复制代码

App Key

App Key 是使用 IMLib 进行即时通讯功能开发的必要条件,也是应用的唯一性标识。在集成使用 IMLib 之前,请务必先通过 融云开发者后台 (opens new window)注册并获取开发者的专属 App Key

只有在 App Key 相同的情况下,不同用户之间的消息才有可能互通。

初始化

IMLib 提供的所有能力基于 IMLib 初始化后获取的实例对象,因此在使用 IMLib 的能力之前,必须先调用 IMLib 的初始化接口,且务必保证该接口在应用全生命周期内仅被调用一次。

// 应用初始化以获取 RongIMLib 实例对象,请务必保证此过程只被执行一次
const im = RongIMLib.init({ appkey: '<Your-App-Key>' });
复制代码

后续所有代码示例中的 im 均指通过初始化获取到的 RongIMLib 实例对象

设置监听

初始化完成后,应在建立连接之前对 im 对象添加事件监听器,及时获取相关事件通知。

// 添加事件监听
im.watch({
  // 监听会话列表变更事件
  conversation (event) {
    // 假定存在 getExistedConversationList 方法,以获取当前已存在的会话列表数据
    const conversationList = getExistedConversationList()
    // 发生变更的会话列表
    const updatedConversationList = event.updatedConversationList;
    // 通过 im.Conversation.merge 计算最新的会话列表
    const latestConversationList = im.Conversation.merge({ conversationList, updatedConversationList })
  },
  // 监听消息通知
  message (event) {
    // 新接收到的消息内容
    const message = event.message;
  },
  // 监听 IM 连接状态变化
  status (event) {
    console.log('connection status:', event.status);
  },
  // 监听聊天室 KV 数据变更
  chatroom (event) {
    /**
     * 聊天室 KV 存储数据更新
     * @example
     * [
     *  {
     *    "key": "name",
     *    "value": "我是小融融",
     *    "timestamp": 1597591258338, 
     *    "chatroomId": "z002", 
     *    "type": 1 // 1: 更新( 含:修改和新增 )、2: 删除
     *  },
     * ]
     */
    const updatedEntries = event.updatedEntries
  },
  expansion (event) {
    /**
     * 更新的消息拓展数据
     * @example {
     *    expansion: { key: 'value' },      // 设置或更新的扩展值
     *    messageUId: 'URIT-URIT-ODMF-DURR' // 设置或更新扩展的消息 uid
     * }
     */
    const updatedExpansion = event.updatedExpansion;
    /**
     * 删除的消息拓展数据
     * @example {
     *    deletedKeys: ['key1', 'key2'],    // 设置或更新的扩展值
     *    messageUId: 'URIT-URIT-ODMF-DURR' // 设置或更新扩展的消息 uid
     * }
     */
    const deletedExpansion = event.deletedExpansion;
});

复制代码

建立 IM 连接

App Key 是应用的唯一性标识,Token 则是用户的唯一性标识,是用户连接融云 IM 服务所必需的身份凭证。Token 一般由开发者的应用服务器调用融云 Server API 获取 Token 接口获取之后,由应用服务器下发到应用客户端。

我的这个token是从后端获取的,然后存储到本地,用的时候看看过期没,过期了就重新获取。相当于前端只进行部分交互。

  • 获取token
    // 获取token
    getIMToken() {
      getIMToken().then(res => {
        var time = new Date().getTime()
        res.time = time
        // 将token保存下来
        this.gobalToken = res
        var tokenStr = JSON.stringify(res)
        localStorage.setItem('token', tokenStr)
        // 初始化融云
        this.linkToRongs(res.data)
      })
    },
    // 判断token是否过期
    isToken() {
      var now = new Date().getTime()
      // 获取上一次存储的token
      var oldToken = JSON.parse(localStorage.getItem('token'))
      // 判断之前获取的token
      if (oldToken) {
        var tokenTime = oldToken.time
        // 判断时间是否过期了
        if (now - tokenTime > 29 * 24 * 60 * 60 * 1000) {
          this.getIMToken()
        } else {
          this.gobalToken = JSON.parse(localStorage.getItem('token'))
          this.linkToRongs(this.gobalToken.data)
          return
        }
      }
      this.getIMToken()
    }
复制代码
  • 建立连接
im.connect({ token: '<Your-Token>' }).then(user => {
  console.log('链接成功, 链接用户 id 为: ', user.id);
}).catch(error => {
  console.log('链接失败: ', error.code, error.msg);
});
复制代码

获取会话列表

Web 端不具备持久化的数据存储能力,需要开发者开启 IM 商用版 - 单群聊云存储 (opens new window)功能才能生效。 该功能需要在调用 im.connect() 并且建立连接成功之后执行。

IMLib 通过会话数据中的 conversationTypetargetId 两个属性值来标识会话的唯一性,对于两个属性的定义如下:

  1. conversationType 用来标识会话类型(如:单聊、群聊...),其值为 RongIMLib.CONVERSATION_TYPE 中的常量定义
  2. targetId 用来标识与本端进行对话的人员或群组 Id:
  • conversationType 值为 RongIMLib.CONVERSATION_TYPE.PRIVATE,targetId 为对方用户 Id
  • conversationType 值为 RongIMLib.CONVERSATION_TYPE.GROUP,targetId 为当前群组 Id
  • conversationType 值为 RongIMLib.CONVERSATION_TYPE.CHATROOM,targetId 为聊天室 Id
// 获取会话列表
im.Conversation.getList().then(conversationList => {
  console.log('获取会话列表成功', conversationList);
}).catch(error => {
  console.log('获取会话列表失败: ', error.code, error.msg);
});

复制代码

发送消息

该功能需要在调用 im.connect() 并且建立连接成功之后执行。 IMLib 内置消息类型可通过 RongIMLib.MESSAGE_TYPE 获取其常量定义

// 获取指定会话的抽象实例,对于会话的操作基于此实例完成
const conversation = im.Conversation.get({
  // targetId
  targetId: '<TargetId>',
  // 会话类型:RongIMLib.CONVERSATION_TYPE.PRIVATE | RongIMLib.CONVERSATION_TYPE.GROUP
  type: '<Conversation-Type>'
});
// 向会话内发消息
conversation.send({
  // 消息类型,其中 RongIMLib.MESSAGE_TYPE 为 IMLib 内部的内置消息类型常量定义
  messageType: RongIMLib.MESSAGE_TYPE.TEXT, // 'RC:TxtMsg'
  // 消息内容
  content: {
    content: 'Hello RongCloud' // 文本内容
  }
}).then(function(message){
  console.log('发送文字消息成功', message);
}).catch(error => {
  console.log('发送文字消息失败', error.code, error.msg);
});

复制代码

接收消息

当本端作为消息接收的一方,所接收的消息将通过 im.watch() 注册的消息监听向业务层抛出。具体可参考上述 设置监听 部分

获取历史消息

Web 端不具备持久化的数据存储能力,需要开发者开启 IM 商用版 - 单群聊云存储 (opens new window)功能才能生效。 该功能需要在调用 im.connect() 并且建立连接成功之后执行。

const conversation = im.Conversation.get({
  targetId: '<TargetId>',
  type: '<Conversation-Type>'
});
const option = {
  // 获取历史消息的时间戳,默认为 0,表示从当前时间获取
  timestamp: +new Date(),
  // 获取条数,有效值 1-20,默认为 20
  count: 20,
};
conversation.getMessages(option).then(result => {
  const list = result.list;       // 获取到的消息列表
  const hasMore = result.hasMore; // 是否还有历史消息可获取
  console.log('获取历史消息成功', list, hasMore);
}).catch(error => {
  console.log('发送文字消息失败', error.code, error.msg);
});

复制代码

断开连接

断开当前用户连接,连接断开后无法接收消息、发送消息、获取历史消息、获取会话列表... 在下次连接融云成功后,会收取上次离线后的消息,离线消息默认保存 7 天。

im.disconnect().then(() => console.log('断开链接成功'));
复制代码

实战运用

token拿到手,往前走一走

created() {
    this.isToken()
 }
 methods:{
// 获取token
    getIMToken() {
      getIMToken().then(res => {
        var time = new Date().getTime()
        res.time = time
        // 将token保存下来
        this.gobalToken = res
        var tokenStr = JSON.stringify(res)
        localStorage.setItem('token', tokenStr)
        // 初始化融云
        this.linkToRongs(res.data)
      })
    },
    // 判断token是否过期
    isToken() {
      var now = new Date().getTime()
      // 获取上一次存储的token
      var oldToken = JSON.parse(localStorage.getItem('token'))
      // 判断之前获取的token
      if (oldToken) {
        var tokenTime = oldToken.time
        // 判断时间是否过期了
        if (now - tokenTime > 29 * 24 * 60 * 60 * 1000) {
          this.getIMToken()
        } else {
          this.gobalToken = JSON.parse(localStorage.getItem('token'))
          this.linkToRongs(this.gobalToken.data)
          return
        }
      }
      this.getIMToken()
    },
}
复制代码

init初始化,话话道心好好听

一般测试服一个appkey,正式服一个appkey。这个appkey需要自己去申请

 // 链接融云
 linkToRongs(token) {
    const that = this
    let RongClientKey
    if (process.env.VUE_APP_BASE_API2 === '') {//测试服
    RongClientKey = '4215151sadasas'
    } else {//正式服
    RongClientKey = 'adsada12asda1a'
    }
    // 应用初始化以获取 RongIMLib 实例对象,请务必保证此过程只被执行一次
    // eslint-disable-next-line no-undef
    that.rongyun = RongIMLib.init({ appkey: RongClientKey })
}
复制代码

监听先行开路,链接随后就到

初始化完成后,应在建立连接之前对 im 对象添加事件监听器,及时获取相关事件通知。

 // 链接融云
 linkToRongs(token) {
    const that = this
    let RongClientKey
    if (process.env.VUE_APP_BASE_API2 === '') {//测试服
    RongClientKey = '4215151sadasas'
    } else {//正式服
    RongClientKey = 'adsada12asda1a'
    }
    // 应用初始化以获取 RongIMLib 实例对象,请务必保证此过程只被执行一次
    // eslint-disable-next-line no-undef
    that.rongyun = RongIMLib.init({ appkey: RongClientKey })
    const im = that.rongyun
    // 添加事件监听
      im.watch({
        // 监听会话列表变更事件
        conversation(event) {
          // 假定存在 getExistedConversationList 方法,以获取当前已存在的会话列表数据
          const conversationList = that.getExistedConversationList(im)
          // 发生变更的会话列表
          const updatedConversationList = event.updatedConversationList
          // 通过 im.Conversation.merge 计算最新的会话列表
          const latestConversationList = im.Conversation.merge({ conversationList, updatedConversationList })
          console.log(latestConversationList)
        },
        // 监听消息通知
        message(event) {
          //初始化消息都在这
          // 新接收到的消息内容
          const message = event.message
          console.log(message)
        },
        // 监听 IM 连接状态变化
        status(event) {
          console.log('connection status:', event.status)
        },
        // 监听聊天室 KV 数据变更
        chatroom(event) {
          const updatedEntries = event.updatedEntries
          console.log('聊天室 KV 存储数据更新', updatedEntries)
        }
      })
}
复制代码

链接融云先用key,长驱直入无人拦

 // 链接融云
 linkToRongs(token) {
    const that = this
    let RongClientKey
    if (process.env.VUE_APP_BASE_API2 === '') {//测试服
    RongClientKey = '4215151sadasas'
    } else {//正式服
    RongClientKey = 'adsada12asda1a'
    }
    // 应用初始化以获取 RongIMLib 实例对象,请务必保证此过程只被执行一次
    // eslint-disable-next-line no-undef
    that.rongyun = RongIMLib.init({ appkey: RongClientKey })
    const im = that.rongyun
    // 添加事件监听
      im.watch({
        // 监听会话列表变更事件
        conversation(event) {
          // 假定存在 getExistedConversationList 方法,以获取当前已存在的会话列表数据
          const conversationList = that.getExistedConversationList(im)
          // 发生变更的会话列表
          const updatedConversationList = event.updatedConversationList
          // 通过 im.Conversation.merge 计算最新的会话列表
          const latestConversationList = im.Conversation.merge({ conversationList, updatedConversationList })
          console.log(latestConversationList)
        },
        // 监听消息通知
        message(event) {
          //初始化消息都在这
          // 新接收到的消息内容
          const message = event.message
          console.log(message)
        },
        // 监听 IM 连接状态变化
        status(event) {
          console.log('connection status:', event.status)
        },
        // 监听聊天室 KV 数据变更
        chatroom(event) {
          const updatedEntries = event.updatedEntries
          console.log('聊天室 KV 存储数据更新', updatedEntries)
        }
      })
      // 建立 IM 连接
      const chatRoomId = '627865222'
      var count = 50 // 数量
      im.connect({ token: token }).then(user => {
        this.$message.success('加入聊天室成功')
        console.log('链接成功, 链接用户 id 为: ', user.id)
        var chatRoom = im.ChatRoom.get({
          id: chatRoomId
        })
        chatRoom.join({
          count: count // 进入后, 自动拉取 20 条聊天室最新消息
        }).then(function() {
          console.log('加入聊天室成功')
          chatRoom.getInfo().then(function(result) {
            var userCount = result.userCount
            var user = that.uniq(that.messageList)
            // 刷选用户
            user.map(item => {
              that.list.push(item.user)
            })
            that.num = userCount
          })
        })
      }).catch(error => {
        this.$message.success('加入聊天室失败')
        console.log('链接失败: ', error.code, error.msg)
      })
}
复制代码

最后一步最重要,退出聊天要及时

切换页面时,一定要退出聊天厅,不然下次加入聊天厅无法获取之前的消息。当然你也可以获取历史消息,我尝试获取历史消息一直报错,所以才选择打开页面加入,结束就离开。(不退出的话会一直保持连接)

destroyed() {
    var chatRoom = this.rongyun.ChatRoom.get({
      id: '聊天室id'
    })
    chatRoom.quit().then(function() {
      console.log('退出聊天室成功')
    })
  }
复制代码

结尾

即时通讯这一块做起来还是蛮有意思的,总有一些意料之外的事情发生。

生活中充满各种惊喜,代码世界亦是如此。

最后把源码放在了github

融云官方文档

写在最后

我是凉城a,一个前端,热爱技术也热爱生活。

与你相逢,我很开心。

如果你想了解更多,请点这里,期待你的小⭐⭐

  • 文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注😊

  • 本文首发于掘金,未经许可禁止转载💌

分类:
前端
标签: