IM SDK for HarmonyOS 开发指引

概述

游密即时通讯SDK(IM SDK)为玩家提供完整的游戏内互动服务,游戏开发者无需关注IM通讯复杂的内部工作流程,只需调用IM SDK提供的接口,即可快速实现世界聊天、公会聊天、组队聊天、文字、表情、语音等多项功能。

IM SDK接口调用顺序

IM SDK接口调用顺序

四步集成IM SDK

第一步 注册账号

游密官网注册游密账号。

第二步 添加游戏,获取Appkey

在控制台添加游戏,获得接入需要的Appkey、Appsecret。

第三步 下载IM SDK包体

下载地址

第四步 开发环境配置

开发环境配置

快速接入

1. 导入IM SDK

环境要求:

DevEco Studio版本: 5.0.0 Release(Build Version: 5.0.3.910)及以上

HarmonyOS SDK版本: 5.0.0 Release(API Version 12 Release)及以上

手机系统OpenHarmony版本:5.0.0.31(Beta2)及以上

导入SDK

两种方法导入HAR包:

1. 手动导入

下载youme_im_3.0.11.har包,放到⼯程libs中。在⼯程中配置引⽤:

"dependencies": {
"@youme/im":"file:./libs/youme_im_3.0.11.har",
}
2. ohpm导入

在⼯程中配置:

"dependencies": {
"@youme/im":"3.0.11",
}

运⾏命令:

ohpm install @youme/im

权限申请

在模块的 module.json5 中 requestPermissions添加网络和麦克风权限,配置如下:

"requestPermissions": [
  {
    "name": "ohos.permission.INTERNET",
  },
  {
    "name": "ohos.permission.MICROPHONE",
    "reason": "$string:mic_reason",
    "usedScene": {
      "abilities": [
        "FormAbility"
      ],
      "when": "inuse"
    }
  }

使用Native C++接口

har包安装在该模块的oh_modules目录,目录下有提供 Native C++ 的 include头文件 和 so库文件。\ 若要使用Native C++接口,可以再CMake里配置使用。\ C++接口API说明书请参考 IM SDK for C++使用指南。

#CMakeLists.txt示例

#包含include目录
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules/@youme/im/include)
#包含so的目录
link_directories("../../../oh_modules/@youme/im/libs/${OHOS_ARCH}")
#把libyim.so添加到链接库里
target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libyim.so)
//papi_init.cpp 引用示例

#include "YIM.h"
#include "YIMPlatformDefine.h"
...

//使用C++回调接口IYIMLoginCallback
class CNAPICallback: public IYIMLoginCallback
{
public:
    /*
    * 功能:登录回调
    * @param errorcode:错误码
    * @param userID:用户ID
    */
    virtual void OnLogin(YIMErrorcode errorcode, const XCHAR * userID) {
        OH_LOG_INFO(LOG_APP, "login with code %d", errorcode);
        if(errorcode == YIMErrorcode_Success) {
            YIMManager::CreateInstance()->GetChatRoomManager()->JoinChatRoom(ROOM_NAME);
        }        
    }
};

...

//使用YIMManager主接口
    XString ver = YIMManager::CreateInstance()->GetSDKVersion();

    static auto cb = new CNAPICallback;
    YIMManager::CreateInstance()->SetLoginCallback(cb);
    YIMManager::CreateInstance()->SetServerZone(ServerZone_China);

    auto code = YIMManager::CreateInstance()->Init(APP_KEY, APP_SECRET, "");

2. 初始化

成功导入SDK后,应用启动的第一时间需要调用初始化接口。

import包名

import { YIMClient, YIMObserver, YIMDefine, YIMMessage } from '@youme/im'

YIMClient是一个单例类,可以通过.getInstance()获取到它的实例。通过它就可以调用IM SDK的API接口。

初始化IM SDK

  • 调用示例:

    let error: YIMDefine.YIMErrorcode = YIMClient.getInstance().init(this.appCustom.appKey, this.appCustom.appSecret, this.selectedZone);

  • 接口与参数:
  • 初始化接口init(appKey:string, appSecret:string, serverZone: YIMDefine.YIMServerZone, packageName:string = "", sdkValidDomain:string = "", drDomain:string = "", sdkValidBackupip:string = "", drBackupip:string = ""): YIMDefine.YIMErrorcode
  • appKey :用户游戏产品区别于其它游戏产品的标识,可以在游密官网获取、查看。
  • appSecret :用户游戏产品的密钥,可以在游密官网获取、查看。
  • serverZone :IM服务器区域,一般使用 0 -中国,其余设置值查看服务器部署地区定义

  • 返回值:
  • YIMErrorcode :错误码,详细描述见错误码定义

  • 备注: 此接口本是异步操作,未给出异步回调,一般返回的错误码是Success即表示初始化成功。

    3. 监听全局回调

    IM引擎的一些消息通知是需要设置全局回调来接收的,比如其他人进出房间,消息接收等。\ 新建一个YIMObserver对象,处理您感兴趣的回调,然后添加到IM引擎的观察者列表,就可以完成了。\ 如果不需要接收消息了,可以从观察者列表中删除。\ 具体的全局回调类型请查看API接口。

  • 调用示例:

    
      import { YIMClient, YIMObserver, YIMDefine, YIMMessage } from '@youme/im'
      ...
      observer: YIMObserver = new YIMObserver();
      ...
    
          // 设置监听
          YIMClient.getInstance().addObserver(this.observer);
    
        ...
    
        // 回调接口实现
        this.observer
    
      .onReceiveMessage((msg: YIMMessage.Msg) => {
        //接收别人发送的消息
        ...
      })
      .onOtherJoinRoom((room, user) => {
        //其他人进入房间
        ...
      })
      .onOtherLeaveRoom((room, user) => {
        //其他人离开房间
        ...
      })
      .onUpdateReadStatus((recvID: string, chatType: YIMDefine.YIMChatType, msgSerial: bigint) => {
        //其他人已读了某条消息
        ...
      })
    
           ...   
       }
  • 接口:

    • 添加观察者接口addObserver(observer: YIMObserver)
    • 移除观察者接口deleteObserver(observer: YIMObserver)

4. 登录IM系统

成功初始化IM后,调用IM SDK登录接口登录IM系统。

  • 调用示例:

    Button('用户登录')
    .onClick(() => {
      let errcode: YIMDefine.YIMErrorcode = YIMClient.getInstance().login(this.userId, this.password, "", 
      (errCode: YIMDefine.YIMErrorcode, user: string) => {
        if(errCode == YIMDefine.YIMErrorcode.YIMErrorcode_Success) {
          ...
        } else {
          hilog.error(0x0000, 'YOUMEIM_DEMO_UI', `callback:login err:${errCode} user:${user}`);
          ..
        }
      });
    })
    
  • 接口与参数:

    • 登录接口login(user: string, password:string, token: string, callback: (errCode: YIMDefine.YIMErrorcode, user: string) => void) : YIMDefine.YIMErrorcode

    • user:由调⽤者分配,不可为空字符串,只可由字母或数字或下划线组成,用户首次登录会自动注册所用的用户ID和密码。
    • password:⽤户密码,不可为空字符串,由调用者分配,二次登录时需与首次登录一致,否则会报UsernamePasswordError。
    • token:用户验证token,可选,如不使用token验证传入:""。
    • callback:登录回调。

5. 进入聊天频道

登录成功后,如果有群组聊天需要,比如游戏里面的世界、工会、区域等,需要进入聊天频道;调用方为聊天频道设置一个唯一的频道ID,可以进入多个频道。

  • 调用示例:

    Button('加入聊天室')
    .onClick(() => {
      let errcode :YIMDefine.YIMErrorcode = YIMClient.getInstance().joinChatRoom(this.roomId, (err, room) => {
        if(err == YIMDefine.YIMErrorcode.YIMErrorcode_Success) {
          this.getRoomMemberCount(room);
          ...
        } else {
          hilog.error(0x0000, 'YOUMEIM_DEMO_UI', `callback:join_room err:${err} room:${room}`);
          ...
        }
      });
      if(errcode != YIMDefine.YIMErrorcode.YIMErrorcode_Success) {
        ...
      }
    })
    
  • 接口与参数

    • 进入频道接口joinChatRoom(room: string, callback: (errCode: YIMDefine.YIMErrorcode, room: string) => void) : YIMDefine.YIMErrorcode

    • room:请求加入的频道ID,仅支持数字、字母、下划线组成的字符串,区分大小写,长度限制为255字节。
    • callback:加入频道回调。

6. 发送文本消息

在成功登录IM后,即可发送IM消息。

  • 调用示例:

    // 发送文本消息
    Button('发送文字')
    .onClick(() => {
      let out: [YIMDefine.YIMErrorcode, bigint] = YIMClient.getInstance().sendTextMessage(this.sendTo,
        YIMDef.YIMChatType.ChatType_PrivateChat, this.msgToSend, "",
        (reqId: bigint, errCode: YIMDefine.YIMErrorcode, sendTime: number, isForbidRoom: boolean, reasonType: number, forbidEndTime: number, msgId: bigint)=>{
          if(errCode == YIMDefine.YIMErrorcode.YIMErrorcode_Success) {
            ...
          } else {
            hilog.error(0x0000, 'YOUMEIM_DEMO_UI', `callback:send_msg_status err:${errCode} reqId:${reqId} sendTime:${sendTime} msgId:${msgId}`);
            ...
          }
        });
      if(out[0] == YIMDefine.YIMErrorcode.YIMErrorcode_Success) {
        ...
      } else {
        ...
      }
    })
    
  • 接口与参数:

    • 发文本消息接口sendTextMessage(receiver: string, chatType: number, msg: string, param: string, callback: funcOnSendMessage) : [YIMDefine.YIMErrorcode, bigint]

    • receiver:接收者ID,私聊传入用户ID,频道聊天传入频道ID。
    • chatType:聊天类型,私聊传1,频道聊天传2;需要频道聊天得先成功进入频道后发文本消息,此频道内的成员才能接收到消息。
    • msg:聊天内容。
    • param: 发送文本附加信息。
    • callback:发送文本消息回调。
  • 发送文本消息回调:

    funcOnSendMessage = (reqId: bigint, errCode: YIMDefine.YIMErrorcode, sendTime: number, isForbidRoom: boolean, reasonType: number, forbidEndTime: number, msgId: bigint) => void

    reqId: 消息序列号,用于校验一条消息发送成功与否的标识,long类型。
    errCode: 错误码。 sendTime: 消息发送时间,long类型。
    isForbidRoom: 若发送的是频道消息,显示在此频道是否被禁言,true-被禁言,false-未被禁言,boolean类型。
    reasonType: 若在频道被禁言,禁言原因类型,0-未知,1-发广告,2-侮辱,3-政治敏感,4-恐怖主义,5-反动,6-色情,7-其它,int类型。
    forbidEndTime: 若在频道被禁言,禁言结束时间,long类型。
    msgId: 返回服务器messageID,与接收消息时的getMessageID()是统一的。

  • 拓展功能: 发送消息时,可以将玩家头像、昵称、角色等级、vip等级等要素打包成json格式发送。

7. 发送语音消息

在成功登录IM后,可以发送语音消息。

  • 按住语音按钮时,调用StartRecordAudioMessage接口,启动录音。
  • 松开按钮,调用StopAndSendAudioMessage接口,发送语音消息。
  • 按住过程若需要取消发送,调用cancelAudioMessage取消本次语音发送。
  • 调用示例:

    Button(this.speek_btn_text)
    .onTouch(async (event:TouchEvent) => {
      if(event.type == TouchType.Down) {
        // 启动语音  
        let out: [YIMDefine.YIMErrorcode, bigint] = YIMClient.getInstance().StartRecordAudioMessage(this.sendTo, YIMDefine.YIMChatType.ChatType_RoomChat,
          (reqId: bigint, errCode: YIMDefine.YIMErrorcode, text: string, audioPath: string, audioTime: number, sendTime: number, isForbidRoom: boolean, reasonType: number, forbidEndTime: number, msgId: bigint) => {
            if(errCode == 0) {
              ...
            } else {
              hilog.error(0x0000, 'YOUMEIM_DEMO_UI', `callback:send_audio_msg_status err:${errCode} reqId:${reqId} sendTime:${sendTime} msgId:${msgId}`);
              ...
            }
          },
          (reqId: bigint, errCode: YIMDefine.YIMErrorcode, text: string, audioPath: string, audioTime: number) => {
            hilog.info(0x0000, 'YOUMEIM_DEMO_UI',  `开始发送语音回调,请求ID:${reqId} code:${errCode} \n`);
          });
        if(out[0] == YIMDefine.YIMErrorcode.YIMErrorcode_Success) {
          ...
        } 
      }else if(event.type == TouchType.Up) {
        // 停止并发送语音消息
        let ret: YIMDefine.YIMErrorcode = YIMClient.getInstance().StopAndSendAudioMessage('');
      }
    })
  • 接口与参数:

    • 发送语音消息接口StartRecordAudioMessage(receiver: string, chatType: number, complete: (reqId: bigint, errCode: YIMDefine.YIMErrorcode, text: string, audioPath: string, audioTime: number, sendTime: number, isForbidRoom: boolean, reasonType: number, forbidEndTime: number, msgId: bigint) => void, before_send?: (reqId: bigint, errCode: YIMDefine.YIMErrorcode, text: string, audioPath: string, audioTime: number) => void) : [YIMDefine.YIMErrorcode, bigint]

    • 结束录音接口StopAndSendAudioMessage(extra: string) : YIMDefine.YIMErrorcode

    • 取消录音接口cancelAudioMessage() : YIMDefine.YIMErrorcode

    • receiver:接收者ID(⽤户ID或者频道ID)。
    • chatType:消息类型,表示私聊还是频道消息。
    • extra:发送语音消息附加信息,主要用于调用方特别需求。
  • 回调接口与参数:

    发送完成回调complete: (reqId: bigint, errCode: YIMDefine.YIMErrorcode, text: string, audioPath: string, audioTime: number, sendTime: number, isForbidRoom: boolean, reasonType: number, forbidEndTime: number, msgId: bigint) => void

    录音完成,开始发送时回调before_send: (reqId: bigint, errCode: YIMDefine.YIMErrorcode, text: string, audioPath: string, audioTime: number) => void

    reqId: 消息序列号,用于校验一条消息发送成功与否的标识,long类型。
    errCode: 错误码。 text: 语音转文字识别的文本内容,如果带语音转文字参数为false,该字段为空字符串。 audioPath: 录音生成的wav文件的本地完整路径。 audioTime: 录音时长(单位秒)。 sendTime: 消息发送时间,long类型。
    isForbidRoom: 若发送的是频道消息,显示在此频道是否被禁言,true-被禁言,false-未被禁言,boolean类型。
    reasonType: 若在频道被禁言,禁言原因类型,0-未知,1-发广告,2-侮辱,3-政治敏感,4-恐怖主义,5-反动,6-色情,7-其它,int类型。
    forbidEndTime: 若在频道被禁言,禁言结束时间,long类型。
    msgId: 返回服务器messageID,与接收消息时的getMessageID()是统一的。

  • 备注:
    语音消息发送成功,接收方会收到onReceiveMessage回调,能从该回调中下载语音文件。

8. 接收消息

  • 通过onReceiveMessage接口被动接收消息,需要开发者实现
  • 调用示例:

    this.observer
      .onReceiveMessage((msg: YIMMessage.Msg) => {
    
        if (msgType == YIMDef.YIMMessageBodyType.MessageBodyType_TXT) {
          //收到文本消息
          ...
        } else if (msgType == YIMDef.YIMMessageBodyType.MessageBodyType_Voice) {
          //收到语音消息
          ...
          //下载这条语音消息
          YIMClient.getInstance().downloadFile(msg.msgId, "", (errCode: YIMDefine.YIMErrorcode, message: YIMMessage.Msg, path: string) => {
            if (errCode == 0) {
              //下载成功
              ...
              //播放这条语音
              YIMClient.getInstance().startPlayAudio(path);
            } else {
              hilog.error(0x0000, 'YOUMEIM_DEMO_UI', `callback:download_file err:${errCode}  msgId:${msg.msgId}`);
              ...
            }
    
          });
          return;
        } else {
          //收到其他类型消息
          ...
          return;
        }
      })

9. 接收语音消息并播放

  • 通过msgType分拣出语音消息(YYIMDefine.IMMessageBodyType.MessageBodyType_Voice)
  • msgId获得消息ID。
  • 调用downloadFile接口下载语音消息。
  • 成功下载语音消息后,调用startPlayAudio接口播放语音消息。
  • 调用示例:

    //下载这条语音消息
    YIMClient.getInstance().downloadFile(msgId, "", (errCode: YIMDefine.YIMErrorcode, message: YIMMessage.Msg, path: string) => {
    if (errCode == 0) {
      //下载成功
      ...
      //播放这条语音
      YIMClient.getInstance().startPlayAudio(path);
    } else {
      hilog.error(0x0000, 'YOUMEIM_DEMO_UI', `callback:download_file err:${errCode}  msgId:${msgId}`);
      ...
    }
    
    });
    
  • 接口和参数:

    • 下载语音消息接口downloadFile(messageID: bigint, path: string, callback: (errCode: YIMDefine.YIMErrorcode, message: YIMMessage.Msg, path: string) => void

    • 播放语音消息接口startPlayAudio(path: string) : YIMDefine.YIMErrorcode

    • messageID:消息ID。
    • path:语音文件保存路径。
    • path:待播放文件路径。
    • callback:回调。
  • 回调接口与参数:
    下载语音接口是异步操作,下载语音成功的标识是onDownload回调的错误码为Success,调用downloadFile接口同步返回值是Success才能收到onDownload回调。成功下载语音消息后即可播放语音消息。

    • 下载回调接口: (errCode: YIMDefine.YIMErrorcode, message: YIMMessage.Msg, path: string) => void

    • errCode:错误码。
    • message:消息基类。
    • path:保存路径。

10. 登出IM系统

注销账号时,调用登出接口logout登出IM系统。

  • 调用示例:

    Button('用户登出')
    .onClick(() => {
      YIMClient.getInstance().logout((errCode:nuYIMDefine.YIMErrorcodember) => {
        if(errCode == 0) {
          ...
        } else {
          hilog.error(0x0000, 'YOUMEIM_DEMO_UI', `callback:logout err:${errCode}`);
          ...
        }
      });
    })
  • 接口:
    • 登出接口logout(callback: (errCode: YIMDefine.YIMErrorcode) => void) : YIMDefine.YIMErrorcode

典型场景集成方案

主要分为世界频道聊天,用户私聊,直播聊天室;集成的时都需要先初始化SDK,登录IM系统。

启动应用,初始化SDK

应用启动的第一时间需要调用初始化接口。

  • 接口与参数:

    • init:初始化接口。
    • appKey:用户游戏产品区别于其它游戏产品的标识,可以在游密官网获取、查看。
    • appSecret:用户游戏产品的密钥,可以在游密官网获取、查看。
    • serverZone:IM服务器区域,一般使用0-中国,其余设置值查看服务器部署地区定义
  • 代码示例与详细说明:

登录应用时,登录IM系统

登录界面介绍

  • 点击登录按钮时,调用IM SDK登录接口。
  • 接口与参数:

    • login:登录接口。
    • user:由调⽤者分配,不可为空字符串,只可由字母或数字或下划线组成。
    • password:⽤户密码,不可为空字符串。
    • token:用户验证token,可选,如不使用token验证传入:""。
    • callback:登录回调。
  • 代码示例与详细说明:

典型场景

世界频道聊天

频道

  • 进入应用后,调用加入频道接口,进入世界、公会、区域等需要进入的聊天频道。
  • 应用需要为各个聊天频道设置一个唯一的频道ID。
  • 成功进入频道后,发送频道消息,文本、语音消息等。
  • 接口与参数

    • joinChatRoom:加入频道。
    • room:请求加入的频道ID。
    • callback:加入频道回调。
  • 代码示例与详细说明:

用户私聊

  • 成功登录IM系统后,可和其它登录IM的用户发私聊消息,文本、语音消息等;发文本消息接口的聊天类型参数使用 1-私聊类型。
  • 调用流程查看发送文本消息发送语音消息

直播聊天室

  • 用户集成直播SDK后,导入IM SDK。
  • 初始化IM SDK。
  • 登录IM 系统。
  • 进入指定的聊天频道。
  • 发送频道消息(例如:弹幕式),调用流程查看发送文本消息

文本消息发送

频道

  • 点击发送按钮,调用发消息接口,将输入框中的内容发送出去。
  • 发送出的消息出现在聊天框右侧。
  • 表情消息可以将表情信息打包成Json格式发送。
  • 相关接口与参数:

    • sendTextMessage:发文字消息接口。
    • receiver:接收者ID,私聊传入用户ID,频道聊天传入频道ID。
    • chatType:聊天类型,私聊/频道聊天。
    • msg:聊天内容。
    • param: 发送文本附加信息。
    • callback:发送文本消息回调。
  • 代码示例与详细说明:

  • 拓展功能: 发送消息时,可以将玩家头像、昵称、角色等级、vip等级等要素打包成json格式发送。

语音消息发送

发送语音消息

  • 按住语音按钮时,调用StartRecordAudioMessage
  • 松开按钮,调用StopAndSendAudioMessage接口,发送语音消息。
  • 按住过程若需要取消发送,调用cancelAudioMessage取消发送。
  • 相关接口与参数:

    • StartRecordAudioMessage:发送语音消息接口。
    • StopAndSendAudioMessage:结束录音接口。
    • cancelAudioMessage:取消录音接口。
    • receiver:接收者ID(⽤户ID或者频道ID)。
    • chatType:消息类型,表示私聊还是频道消息。
    • extra:语音消息附带信息。
  • 代码示例与详细说明:

接收消息

接收消息

  • 通过onReceiveMessage接口被动接收消息,需要开发者实现,接收消息进行相应的展示,如果是语音消息需要下载语音,以及下载完成后的语音播放。
  • 相关接口与参数:

    • onReceiveMessage:收消息接口。
  • 代码示例与详细说明:

接收语音消息和播放

接收语音消息

  • 通过msgType分拣出语音消息(YIMMessageBodyType.MessageBodyType_Voice)
  • msgId获得消息ID。
  • 点击语音气泡,调用downloadFile接口下载语音文件。
  • 调用方播放语音文件。
  • 相关接口与参数:

    • downloadFile:下载语音文件接口。
    • startPlayAudio:播放语音文件接口。

    • messageID:消息ID。
    • path:保存路径。
    • callback:回调。
  • 代码示例与详细说明:

登出IM系统

更换账号

  • 如下两种情况需要登出IM系统:
  • 注销账号时,调用logout接口登出IM系统。
  • 退出应用时,调用logout接口登出IM系统。
  • 相关接口:

    • logout:登出接口。
  • 代码示例与详细说明: