鸿蒙端集成

更新时间:
复制为 MD 格式

介绍如何在鸿蒙(HarmonyOS)应用中集成互动消息SDK,实现评论、弹幕、点赞等直播互动能力。

前提条件

客户端集成前,请确保已完成服务端集成,并提供客户端访问的获取鉴权Token的接口。详细操作,请参见服务端集成

环境要求

在开始集前,请确保开发环境满足以下要求:

  • 已联系华为商务人员,签署合作计划,开通相关权限,获取 DevEco Studio 5.0.3.900 Release 或以上版本。

  • 获取配套 文档中心的 HarmonyOS NEXT SDK 或以上版本。

  • 获取配套 API Version 12的 HarmonyOS NEXT 5.0.0.102 操作系统或以上版本,支持音视频的鸿蒙设备,且已开启“允许调试”选项。

  • 如果需要使用真机调试,请参考 鸿蒙官网文档 进行配置。

  • 鸿蒙设备已经连接到 Internet。

  • 注册华为开发者账号 并完成实名认证。

集成SDK

  1. ohpm自动集成。

在鸿蒙主工程 entry 目录中的 oh-package.json5 中添加 SDK 依赖,然后点击 "Sync Now"。

{
  "dependencies": {
    "@aliyun_video_cloud/alivc-im-sdk": "最新版本x.y.z"
  }
}
说明

具体最新版本x.y.z可前往版本更新说明查询。

  1. 添加 SDK 依赖权限。

权限名称

权限说明

使用目的

ohos.permission.INTERNET

使用网络

连接通道、收发消息需要网络连接

使用SDK

SDK使用需遵循如下操作顺序:

  1. 初始化

  2. 登录

  3. 相关操作

  4. 登出

  5. 反初始化

  6. 其他

其中相关操作包含群组操作和消息操作,详细说明如下:

相关操作

  • 群组操作

    • 创建群组(需要以管理员身份进行登录才能操作)

    • 关闭群组(仅限群主/群管理员操作)

    • 进入群组

    • 离开群组

    • 查询群组信息

    • 修改群组信息(仅限群主/群管理员操作)

    • 查询群组最近成员列表

    • 查询群组全部成员(仅限群主/群管理员操作)

    • 对群组进行禁言(仅限群主/群管理员操作)

    • 对群组取消禁言(仅限群主/群管理员操作)

    • 对群组的用户进行禁言(仅限群主/群管理员操作)

    • 对群组的用户取消禁言(仅限群主/群管理员操作)

    • 查询群组内被禁言的用户列表(仅限群主/群管理员操作)

  • 消息操作

    • 单发消息

    • 群发消息

    • 查询最近群发消息列表

    • 查询全部群发消息(仅限群主/群管理员操作)

    • 删除/撤回群消息

    • 查询历史消息

注意事项

ID需遵循以下规则:

appid :最长64位,仅限于A~Z,a~z, 0~9及“-”, 不能包含其他字符。

userid:最长64位,仅限于A~Z,a~z, 0~9及“-”, 不能包含其他字符。

groupid:最长64位,仅限于A~Z,a~z, 0~9及“-”, 不能包含其他字符。

初始化

在使用SDK前需要进行初始化,可以在相关业务模块的主入口设置。

// 创建SDK配置
let config = new ImSdkConfig("your_app_id", "your_app_sign");
config.logLevel = ImLogLevel.DEBUG;
// 初始化SDK
let ret = AliVCIMEngine.getInstance().init(this.getUIContext().getHostContext()!, config);
if (ret == 0) {
  // 初始化成功,添加监听器
  addListeners();
}

监听长连接状态

初始化成功后,添加监听。

// 添加SDK状态监听器:可以按需监听对应的回调
let engineListener: AliVCIMEngineListener = new AliVCIMEngineListener()
  .setOnLinkStateEventListener((event: ImLinkStateEvent): void => {
    // 连接状态变化
  })
  .setOnExitListener((exitCode: number): void => {
    // 登录退出回调:1主动退出 2被踢出 3超时等其他原因 4在其他端上登录
  })
  .setOnTokenExpiredListener((getTokenCallback: AliVCIMTokenCallback): void => {
    // Token过期处理
  })
  .setOnReconnectSuccessListener((groupStatus: ImGroupInfo[]): void => {
    // 重连成功回调:断连期间群组信息可能发送变化
  });
AliVCIMEngine.getInstance().addEngineListener(engineListener);

登录

  1. 生成登录token。

private getTokenAuth(userId: string, role: string): ImAuth {
  const appId: string = 'your_app_id';
  const appKey: string = 'your_app_key';
  const nonce: string = "your_nonce";
  const tokenDuration: number = 24*60*60; // 1天有效期;跟服务端生成的Token的过期时长一致;
  const timestamp: number = Math.floor(Date.now() / 1000) + tokenDuration;
  const pendingShaStr: string = appId + appKey + userId + nonce + timestamp + role;
  const appToken: string = CryptoJS.SHA256(pendingShaStr).toString(CryptoJS.enc.Hex);
  
  let auth = new ImAuth(appToken, timestamp);
  auth.role = role;
  auth.nonce = nonce;
  return auth;
}
说明

token相关信息说明可前往服务端集成查看,务必传入相关的参数信息,否则会登录失败。

其中role参数,有两种角色:

  • 管理员(值:admin)

admin角色,可以创建/关闭群组,如果不需要可以设置为空。其中,非管理员的所有操作,管理员均能执行。

  • 非管理员(值:非admin即可)

不可执行需要管理员权限的操作,若执行会返回失败。

  1. 登录并等待结果

let user = new ImUser(userId);
let auth = this.getTokenAuth(userId, "your_role");
let loginReq = new ImLoginReq(user, auth);

AliVCIMEngine.getInstance().login(loginReq)
  .then(() => {
    // 登录成功
  })
  .catch((error: ImError) => {
    // 登录失败
  });

登出

AliVCIMEngine.getInstance().logout()
  .then(() => {
    // 登出成功
  })
  .catch((error: ImError) => {
    // 登出失败
  });

反初始化

  1. 移除监听器。

AliVCIMEngine.getInstance().removeSdkListener(engineListener);
AliVCIMEngine.getInstance().getGroupManager()?.removeGroupListener(groupListener);
AliVCIMEngine.getInstance().getMessageManager()?.removeMessageListener(messageListener);
  1. 反初始化SDK。

AliVCIMEngine.getInstance().unInit();

消息服务

非管理员操作

监听消息

// 添加消息监听器
let messageListener: AliVCIMMessageListener = new AliVCIMMessageListener()
  .setOnReceiveGroupMessageListener((groupId: string, message: ImGroupMessage) => {
    // 收到群组消息
  })
  .setOnDeleteMessageListener((groupId: string, messageId: string): void => {
    // 群组消息撤回通知
  })
  .setOnReceiveC2cMessageListener( (message: ImMessage) => {
    // 收到C2C消息
  });
AliVCIMEngine.getInstance().getMessageManager()?.addMessageListener(messageListener);

发送单聊消息

let content = new ImMessageContent(this._messageType/*自定义消息类型*/, data/*消息内容*/);
content.setMessageLevel(ImMessageLevel.NORMAL); // 设置消息等级,默认为NORMAL,使用详情参见【消息分级限流】说明
let sendMessageOption = new ImSendMessageOption();
sendMessageOption.enableAudit(false); // 设置是否开启安全审核,默认不开启
let req = new ImSendMessageToUserReq(receiverId/*目标用户ID*/, content, sendMessageOption);
// 需确保对方在线,否则会返回错误码424,此时建议待对方上线后再重发
AliVCIMEngine.getInstance().getMessageManager()?.sendC2cMessage(req)
  .then((rsp: ImSendMessageToUserRsp) => {
    this.showToast(`私聊成功:消息ID=${rsp.messageId}`);
  })
  .catch((error: ImError) => {
    this.showToast(`私聊失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

发送群聊消息

let content = new ImMessageContent(this._messageType/*自定义消息类型*/, data/*消息内容*/);
content.setMessageLevel(ImMessageLevel.NORMAL); // 设置消息等级,默认为NORMAL,使用详情参见【消息分级限流】说明
let sendMessageOption = new ImSendGroupMessageOption();
sendMessageOption.enableAudit(false); // 设置是否开启安全审核,默认不开启;
sendMessageOption.enableStorage(false); // 设置是否存储消息,默认不存储;若开启,发送的消息会存储在数据库,「查询历史消息」或者「查询消息列表」时会返回该消息;
sendMessageOption.enableCache(false); // 设置是否缓存消息,默认不缓存;若开启,发送的消息会缓存在内存中(注意:只缓存最近50条),「查询最近消息列表」时会返回该消息;
sendMessageOption.enableMuteCheck(true); // 设置是否开启禁言检测,默认开启;若不开启,则发送的消息不受禁言的限制;
sendMessageOption.setRepeatCount(1); // 设置消息计数增长值,默认为1,主要用于聚合同类型消息,例如点赞消息场景,即可以聚合n次点赞后再返送1条消息,repeatCount设置为n
let req = new ImSendMessageToGroupReq(groupId/*目标群组ID*/, content, sendMessageOption);
// 需确保已经加入群成功(即在AliVCIMGroupInterface.joinGroup回调成功之后),再发送群组消息,否则会返回错误码425
AliVCIMEngine.getInstance().getMessageManager()?.sendGroupMessage(req)
  .then((rsp: ImSendMessageToGroupRsp) => {
    this.showToast(`发送消息成功:消息ID=${rsp.messageId}`);
  })
  .catch((error: ImError) => {
    this.showToast(`发送消息失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

查询最近消息列表

let req = new ImListRecentMessageReq(groupId/*目标群组ID*/);
AliVCIMEngine.getInstance().getMessageManager()?.listRecentMessage(req)
  .then((rsp: ImListRecentMessageRsp) => {
    this.showToast(`查询最近消息列表成功: 共${rsp.messageList.length}条`);
    this.logInfo('消息列表:' + JSON.stringify(rsp, null, 2));
  })
  .catch((error: ImError) => {
    this.showToast(`查询最近消息列表失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

查询历史消息

let req = new ImListHistoryMessageReq(this._groupId/*目标群组ID*/, 88888/*目标消息类型*/);
req.nextPageToken = 231231; // 不传时表示第一页,遍历时服务端会返回下一页Token,客户端获取下一页时应带上
req.sortType = ImSortType.ASC; // 返回消息的顺序;默认为时间递增
req.pageSize = 10; // 每次请求返回的最大消息数; 范围:10~30
req.beginTime = 0; // 按时间范围遍历,开始时间,不传时表示最早时间,单位:秒
req.endTime = 0; // 按时间范围遍历,结束时间,不传时表示最晚时间,单位:秒
AliVCIMEngine.getInstance().getMessageManager()?.listHistoryMessage(req)
  .then((rsp: ImListHistoryMessageRsp) => {
    this.showToast(`查询历史消息成功:共${rsp.messageList.length}`);
    this.logInfo('消息列表:' + JSON.stringify(rsp, null, 2));
    this._lastMsgPageToken = rsp.nextPageToken;
  })
  .catch((error: ImError) => {
    this.showToast(`查询历史消息失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

撤回消息

let req = new ImDeleteMessageReq(groupId/*目标群组ID*/, messageId/*目标消息ID*/);
AliVCIMEngine.getInstance().getMessageManager()?.deleteMessage(req)
  .then(() => {
    this.showToast(`撤回消息成功`);
  })
  .catch((error: ImError) => {
    this.showToast(`撤回消息失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

管理员操作

查询消息列表

//该接口(仅限群主/群管理员操作)
let req = new ImListMessageReq(this._groupId/*目标群组ID*/, 88888/*目标消息类型*/);
req.nextPageToken = 231231; // 不传时表示第一页,遍历时服务端会返回下一页Token,客户端获取下一页时应带上
req.sortType = ImSortType.ASC; // 返回消息的顺序;默认为时间递增
req.pageSize = 10; // 每次请求返回的最大消息数; 范围:10~30
req.beginTime = 0; // 按时间范围遍历,开始时间,不传时表示最早时间,单位:秒
req.endTime = 0; // 按时间范围遍历,结束时间,不传时表示最晚时间,单位:秒
AliVCIMEngine.getInstance().getMessageManager()?.listMessage(req)
  .then((rsp: ImListMessageRsp) => {
    this.showToast(`查询消息列表成功: 共${rsp.messageList.length}条`);
    this.logInfo('消息列表:' + JSON.stringify(rsp, null, 2));
    this._lastMsgPageToken = rsp.nextPageToken;
  })
  .catch((error: ImError) => {
    this.showToast(`查询消息列表失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

群组服务

非管理员操作

监听群组状态

// 添加群组监听器
let groupListener: AliVCIMGroupListener = new AliVCIMGroupListener()
  .setOnMemberChangeListener((changeInfo: ImGroupMemberChangeInfo) => {
    // 群成员变化通知
  })
  .setOnGroupExitListener((groupId: string, reason: number) => {
    // 退出群组通知: 1群被解散 2被踢出来
  })
  .setOnMuteChangeListener((muteStatus: ImGroupMuteStatus) => {
    // 群组禁言状态变化通知
  })
  .setOnInfoChangeListener((infoStatus: ImGroupInfoStatus) => {
    // 群组信息变化通知
  });
AliVCIMEngine.getInstance().getGroupManager()?.addGroupListener(groupListener);

加入群组

let req = new ImJoinGroupReq(groupId/*目标群组ID*/);
AliVCIMEngine.getInstance().getGroupManager()?.joinGroup(req)
  .then((rsp: ImJoinGroupRsp) => {
    this._groupId = groupId;
    this.showToast('加入群组成功');
    this.logInfo('群组信息:' + JSON.stringify(rsp, null, 2));
  })
  .catch((error: ImError) => {
    this.showToast(`加入群组失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
    this.exitCurrentPage();
  });

离开群组

let req = new ImLeaveGroupReq(groupId/*目标群组ID*/);
AliVCIMEngine.getInstance().getGroupManager()?.leaveGroup(req)
  .then(() => {
    this.showToast('退出群组成功');
  })
  .catch((error: ImError) => {
    this.showToast(`退出群组失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

查询群组信息

let req = new ImQueryGroupReq(groupId/*目标群组ID*/);
AliVCIMEngine.getInstance().getGroupManager()?.queryGroup(req)
  .then((rsp: ImQueryGroupRsp) => {
    this.showToast(`查询群组成功: ${rsp.groupInfo.groupId}`);
    this.logInfo('群组信息:' + JSON.stringify(rsp.groupInfo, null, 2));
  })
  .catch((error: ImError) => {
    this.showToast(`查询群组失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

查看最近群组成员

重要

如果当前群组为超级大群,则不支持查询用户列表,即该接口不可用。

let req = new ImListRecentGroupUserReq(groupId/*目标群组ID*/);
AliVCIMEngine.getInstance().getGroupManager()?.listRecentGroupUser(req)
  .then((rsp: ImListRecentGroupUserRsp) => {
    this.showToast(`列出最近群组用户成功: 共${rsp.total}人`);
    this.logInfo('用户列表:' + JSON.stringify(rsp, null, 2));
  })
  .catch((error: ImError) => {
    this.showToast(`列出最近群组用户失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

管理员操作

创建群组

说明

您最多可以创建5,000个群组(已关闭的群组不计入此额度)。为了确保资源的有效利用,请务必及时关闭不再使用的群组。

let req = new ImCreateGroupReq(groupId/*目标群组ID*/);
req.groupName = "测试群组"; // 群组名称
req.groupMeta = "用于测试场景"; // 自定义拓展信息

AliVCIMEngine.getInstance().getGroupManager()?.createGroup(req)
  .then((rsp: ImCreateGroupRsp) => {
    this.showToast(`创建群组成功: groupId=${rsp.groupId}, alreadyExist=${rsp.alreadyExist}`);
  })
  .catch((error: ImError) => {
    this.showToast(`创建群组失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

删除群组

let req = new ImCloseGroupReq(groupId/*目标群组ID*/);
AliVCIMEngine.getInstance().getGroupManager()?.closeGroup(req)
  .then(() => {
    this.showToast('关闭群组成功');
  })
  .catch((error: ImError) => {
    this.showToast(`关闭群组失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

修改群组

let req = new ImModifyGroupReq(this._groupId/*目标群组ID*/);
req.forceUpdateGroupMeta = false; // 为true表示强制刷新groupMeta信息,若groupMeta为空则表示清空;为false,则只有groupMeta不空才更新groupMeta信息
req.groupMeta = "";
req.forceUpdateAdmins = false; // 为true表示强制刷新admins信息,若admins为空则表示清空;为false,则只有admins不空才更新admins信息
req.admins = [];
AliVCIMEngine.getInstance().getGroupManager()?.modifyGroup(req)
  .then(() => {
    this.showToast('修改群组成功');
  })
  .catch((error: ImError) => {
    this.showToast(`修改群组失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

查询群组成员

let req = new ImListGroupUserReq(this._groupId/*群组ID*/);
req.sortType = ImSortType.ASC; // 排序方式:ASC-先加入优先,DESC-后加入优先
req.nextPageToken = 0; // 默认表示第一页;遍历时服务端会返回下一页的Token,获取取下一页时应带上
req.pageSize = 30; // 每次请求返回的最大人数;最大不超过50 
AliVCIMEngine.getInstance().getGroupManager()?.listGroupUser(req)
  .then((rsp: ImListGroupUserRsp) => {
    this.showToast(`列出群组用户成功: 共${rsp.userList.length}人`);
    this.logInfo('用户列表:' + JSON.stringify(rsp, null, 2));
    this._lastUserPageToken = rsp.nextPageToken;
  })
  .catch((error: ImError) => {
    this.showToast(`列出群组用户失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

全体禁言

let req = new ImMuteAllReq(groupId/*目标群组ID*/);
AliVCIMEngine.getInstance().getGroupManager()?.muteAll(req)
  .then(() => {
    this.showToast('全员禁言成功');
  })
  .catch((error: ImError) => {
    this.showToast(`全员禁言失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

取消禁言

let req = new ImCancelMuteAllReq(groupId/*目标群组ID*/);
AliVCIMEngine.getInstance().getGroupManager()?.cancelMuteAll(req)
  .then(() => {
    this.showToast('取消全员禁言成功');
  })
  .catch((error: ImError) => {
    this.showToast(`取消全员禁言失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

禁言指定用户

let req = new ImMuteUserReq(groupId/*目标群组ID*/, [userId]/*目标禁言的用户ID列表*/);
AliVCIMEngine.getInstance().getGroupManager()?.muteUser(req)
  .then(() => {
    this.showToast('禁言用户成功');
  })
  .catch((error: ImError) => {
    this.showToast(`禁言用户失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

取消用户禁言

let req = new ImCancelMuteUserReq(groupId/*目标群组ID*/, [userId]/*目标取消禁言的用户ID列表*/);
AliVCIMEngine.getInstance().getGroupManager()?.cancelMuteUser(req)
  .then(() => {
    this.showToast('取消禁言用户成功');
  })
  .catch((error: ImError) => {
    this.showToast(`取消禁言用户失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

查询禁言用户

let req = new ImListMuteUsersReq(groupId/*目标群组ID*/);
AliVCIMEngine.getInstance().getGroupManager()?.listMuteUsers(req)
  .then((rsp: ImListMuteUsersRsp) => {
    this.showToast(`列出禁言用户成功: 全员禁言=${rsp.muteAll}`);
    this.logInfo('禁言用户列表:' + JSON.stringify(rsp, null, 2));
  })
  .catch((error: ImError) => {
    this.showToast(`列出禁言用户失败:errorCode=${error.errorCode}, errorMsg=${error.errorMsg}`);
  });

其他

辅助API接口,用于一些业务场景的判断和处理。

// 判断SDK是否已初始化,业务侧可用此接口判断SDK是否已经实例化
AliVCIMEngine.getInstance().isInit();

/**
 * 获取当前的登录状态
 * 1、只有登出状态「LOGOUT」才能执行登录操作
 * 2、只有登录状态「LOGIN」才能执行入群等操作
 */
AliVCIMEngine.getInstance().getCurrentState();