功能使用

本文介绍客户端SDK主要接口功能使用示例。

长连接

建立客户端与服务端之间的长连接是SDK操作的前提条件,因此客户端接入过程中,建立长连接是尤为重要的步骤。

初始化和建连过程:建连

初始化

客户端SDK建立长连接前需要先进行初始化。

初始化接口是客户端SDK准备资源,与服务端建立连接的步骤。参数说明如下:

  • deviceId:用作标识当前设备的唯一ID,如何获取deviceId,请参考下方各端的API示例代码中描述。

  • token回调函数:token回调函数是提供给SDK内部调用,用来获取建连所需要的token令牌。在回调函数的实现里,需要开发者调用自己的应用服务提供的接口来获取到token信息,并将token返回给SDK,SDK通过token与服务端建立连接。

Android端示例代码:

EngineConfig config = new EngineConfig();

// 此处填写设备Id(可自定义实现,自定义时需要和请求AppSever段的deviceId参数保持一致)
config.deviceId = "设备ID(可自定义实现)";

// 此处填写token获取的回调函数,当SDK登录时,会根据当前状态决定是否找上层获取token
config.tokenAccessor = (userId, callback) -> {
      // 此处需要根据当前userId,去AppServer侧获取token信息(AppServer通过POP接口拿到token,然后返回给端上)
        TokenRequest request = new TokenRequest();
        request.userId = userId;
        request.deviceId = "设备ID(可自定义实现)";
        request.deviceType = "android";
        RetrofitManager.getApiService().getToken(request).invoke(new Callback<Token>() {
            @Override
            public void onSuccess(Token data) {
                callback.onSuccess(data);
            }
            @Override
            public void onError(Error error) {
                callback.onError(error);
            }
        });
};

InteractionEngine.instance().init(config);

iOS端示例代码:

- (AVCIInteractionEngineConfig *)interactionEngineConfig {
    if (!_interactionEngineConfig) {
        _interactionEngineConfig = [[AVCIInteractionEngineConfig alloc] init];
        _interactionEngineConfig.deviceID = AUIInteractionAccountManager.deviceId;  // 此处填写设备Id(可自定义实现,自定义时需要和请求AppSever段的deviceId参数保持一致)
        _interactionEngineConfig.requestToken = ^(void (^ _Nonnull onRequestedToken)(NSString * _Nonnull, NSString * _Nonnull)) {
            // 通过自建的AppServer提供的获取Token接口获取最新Token并传递给IMSDK
            [AUIInteractionLiveService fetchToken:^(NSString * _Nullable accessToken, NSString * _Nullable refreshToken, NSError * _Nullable error) {
                if (onRequestedToken) {
                    onRequestedToken(accessToken ?: @"", refreshToken ?: @"");
                }
            }];
        };
    }
    return _interactionEngineConfig;
}

Web端示例代码:

// 创建互动SDK实例
const { InteractionEngine } = window.AliyunInteraction;
const InteractionInstance = InteractionEngine.create();

建立长连接

  • 建连接口必需要在初始化成功之后调用。

  • 建连需要传递userId,该参数是SDK中用户的唯一标识。

Android端示例代码:

// 1. 监听长连接状态变变化
InteractionEngine engine = InteractionEngine.instance();
engine.register(new SimpleEngineListener() {
    @Override
    public void onConnectionStatusChanged(DPSConnectionStatus status) {
        if (status == DPSConnectionStatus.CS_AUTHED) {
            // 3. 长连接建立成功, 获取到互动服务, 后续接口均通过该接口进行操作
            InteractionService interactionService = engine.getInteractionService();
        }
    }
});
// 2. 调用login方法建立长连接
engine.login("<此处填写业务的userId>");

iOS端示例代码:

- (AVCIInteractionEngine *)interactionEngine {
    if (!_interactionEngine) {
        _interactionEngine = [[AVCIInteractionEngine alloc] initWithConfig:self.interactionEngineConfig];
        _interactionEngine.delegate = self;
    }
    return _interactionEngine;
}

- (void)login:(void(^)(BOOL))completed {
    self.loginCompleted = completed;
    [self.interactionEngine loginWithUserID:@"当前用户id"];
}

#pragma -mark AVCIInteractionEngineDelegate

- (void)onConnectionStatusChanged:(int32_t)status {
    dispatch_async(dispatch_get_main_queue(), ^{
        if (status == 4) {
            self.interactionEngine.interactionService.delegate = self;
            if (self.loginCompleted) {
                self.loginCompleted(YES);
            }
            self.loginCompleted = nil;
        }
    });
}

Web端示例代码:

// 先通过 Appserver 获取 SDK 所需的 token,请根据你实际情况更换
// 注意:web 端调用 Appserver 的 token 接口时,参数 deviceType 需要是 'web'
// 而 deviceId 可以通过静态方法 InteractionEngine.getDeviceId 获得,或者可以自行创建一个 uuid
const tokenObj = await Appservices.getToken();
// 接口正确返回后,调用实例的 auth 方法建联
InteractionInstance
  .auth(tokenObj.access_token)
  .then(() => {
    // 认证成功,此时就建立了链接
    // 接下来即可调用 joinGroup 等方法
  });

// 注意:若控制台上出现错误 "Failed to construct 'WebSocket': The URL's scheme must be either 'ws' or 'wss'. 'tls' is not allowed."
// 请检查 deviceType 是否传的是 'web'

断开长连接

为降低客户端不必要的性能和流量消耗,建议在不需要使用直播功能时手动调用断开长连接。

Android端示例代码:

InteractionEngine.instance().logout();

iOS端示例代码:

[self.interactionEngine logoutOnSuccess:^{
    ;
} onFailure:^(AVCIInteractionError * _Nonnull error) {
    NSAssert(NO, @"Logout failure");
}];

Web端示例代码:

InteractionInstance.logout().then(() => {
  // 登出成功,链接断开
});

消息组

创建消息组

  • SDK中所有通信都是基于消息组的,建连之后可以新建一个消息组,以便于进行后续的业务通信。

  • 业务开发中,建议一个消息组对应一个业务实体。例如在直播场景中,每场直播都关联一个对应的消息组。

Android端示例代码:

ImCreateGroupReq req = new ImCreateGroupReq();
// 该字段非必选, 根据业务场景选择使用
req.extension = new HashMap<String, String>() {{
    put("title", "我的群组");
}};
interactionService.createGroup(req, new Callback<ImCreateGroupRsp>() {
    @Override
    public void onSuccess(ImCreateGroupRsp rsp) {
        // 创建成功, 获取群组Id
        String groupId = rsp.groupId;
    }
    @Override
    public void onError(Error error) {
        // 创建失败
        showToast(error.msg);
    }
});

iOS端示例代码:

[self.interactionEngine.interactionService createGroupWithExtension:@{} onSuccess:^(NSString * _Nonnull groupID) {
    S_LOG(([NSString stringWithFormat:@"createGroup,GroupId:%@", groupID]))
} onFailure:^(AVCIInteractionError * _Nonnull error) {
    F_LOG(([NSString stringWithFormat:@"createGroupWithExtension,错误码:%d  详细信息:%@", error.code, error.message]))
}];

Web端示例代码:

interface IExtension {
  [x: string]: string;
}
// 创建接口参数非必填,extension 类型为 IExtension 也是非必填
const params = {
  extension: {
    title: '自定义',
  },
};
InteractionInstance.createGroup(params)
  .then((res) => {
    // 创建消息组成功
    console.log(res.groupId); // 新创建的 groupId
  })
  .catch((err) => {
    // 创建消息组失败
  });

加入消息组

互动通信之前,需要先加入对应的消息组中。

Android端示例代码:

// 1. 加入消息组
ImJoinGroupReq req = new ImJoinGroupReq();
req.groupId = groupId;
// 设置用户昵称
req.userNick = "用户" + engine.getCurrentUserId();
// 设置扩散本次加入的消息(xx加入了消息组)给全组成员
req.broadCastType = BroadcastType.ALL.getValue();
// 设置扩散消息时,携带统计信息内容
req.broadCastStatistics = true;
interactionService.joinGroup(req, new Callback<ImJoinGroupRsp>() {
    @Override
    public void onSuccess(ImJoinGroupRsp rsp) {
    }

    @Override
    public void onError(Error error) {
    }
});


// 2. 监听加入消息组
InteractionEngine.instance().setMessageListener(groupId, new SimpleMessageListener() {
    @Override
    public void onJoinGroup(Message<JoinGroupModel> message) {
        // 进入群组回调
    }
});

iOS端示例代码:

[self.interactionEngine.interactionService joinGroup:groupId userNick:self.userName userAvatar:@"" userExtension:@"{}" broadCastType:2 broadCastStatistics:YES onSuccess:^{
    weakSelf.groupId = groupId;
    S_LOG(([NSString stringWithFormat:@"joinGroup,当前GroupId:%@", groupId]))
} onFailure:^(AVCIInteractionError * _Nonnull error) {
    F_LOG(([NSString stringWithFormat:@"joinGroup,错误码:%d  详细信息:%@", error.code, error.message]))
}];

Web端示例代码:

// 用户昵称、头像、扩展字段由客户自行传入,服务端下发消息时将会返回对应的用户数据
const params = {
  groupId: 'test-id', // 消息组id
  userNick: 'your name', // 用户昵称
  userAvatar: '', // 非必填,传入头像图片地址
  userExtension: '', // 非必填,可传入额外的 JSONString 文本
  broadCastType: 2, // 系统消息扩散类型,0: 不扩散;1:扩散到指定人; 2:扩散到群组
  broadCastStatistics: true, // 是否扩散统计类消息
};
InteractionInstance.joinGroup(params)
  .then(() => {
    // 加入消息组成功
  })
  .catch((err) => {
    // 加入消息组失败
  });

获取消息组详情

查询消息组信息,包含创建人ID、禁言状态、拓展字段等。

Android端示例代码:

ImGetGroupReq req = new ImGetGroupReq();
req.groupId = "<群组Id>";
interactionService.getGroup(req, new Callback<ImGetGroupRsp>() {
    @Override
    public void onSuccess(ImGetGroupRsp rsp) {
        // 创建人Id
        String creatorId = rsp.creatorId;
        // 群组拓展字段
        HashMap<String, String> extension = rsp.extension;
        // 群组禁言状态
        boolean isMuteAll = rsp.isMuteAll;
    }

    @Override
    public void onError(Error error) {
    }
});

iOS端示例代码:

[self.interactionEngine.interactionService getGroup:self.groupId onSuccess:^(AVCIInteractionGroupDetail * _Nonnull groupDetail) {
    S_LOG(([NSString stringWithFormat:@"Group详情,GroupId:%@, 创建时间:%lld, 状态:%d, 创建者id:%@,是否被全体禁言:%@", groupDetail.groupId, groupDetail.createTime, groupDetail.status, groupDetail.creatorId, groupDetail.isMuteAll?@"YES":@"NO"]))
} onFailure:^(AVCIInteractionError * _Nonnull error) {
    F_LOG(([NSString stringWithFormat:@"getGroup,错误码:%d  详细信息:%@", error.code, error.message]))
}];

Web端示例代码:

const params = {
  groupId: 'test-id', // 消息组id
};
InteractionInstance.getGroup(params)
  .then((res) => {
    // 获取消息组信息成功, res 为消息组信息对象
  })
  .catch((err) => {
    // 获取消息组信息失败
  });

获取消息组成员列表

  • 查询当前消息组成员列表的分页查询接口。

  • 在消息组人员进出频率较高的场景(如直播场景)时,分页数据变化较大,不建议使用。

Android端示例代码:

ImListGroupUserReq req = new ImListGroupUserReq();
req.groupId = "<群组Id>";
req.sortType = SortType.TIME_ASC.getValue();
req.pageNum = 1;
req.pageSize = 20;
interactionService.listGroupUser(req, new Callback<ImListGroupUserRsp>() {
    @Override
    public void onSuccess(ImListGroupUserRsp rsp) {
        int total = rsp.total;
        boolean hasMore = rsp.hasMore;
        ArrayList<ImGroupUser> userList = rsp.userList;
    }

    @Override
    public void onError(Error error) {
    }
});

iOS端示例代码:

[self.interactionEngine.interactionService listGroupUserWithGroupID:self.groupId sortType:1 pageNum:1 pageSize:20 onSuccess:^(int32_t total, BOOL hasMore, NSArray<AVCIInteractionGroupUser *> * _Nonnull users) {
    [users enumerateObjectsUsingBlock:^(AVCIInteractionGroupUser * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        S_LOG(([NSString stringWithFormat:@"Group成员,userId:%@, 加入时间:%lld", obj.userId, obj.joinTime]))
    }];
    if (users.count == 0) {
        S_LOG(@"没人在")
    }
} onFailure:^(AVCIInteractionError * _Nonnull error) {
    F_LOG(([NSString stringWithFormat:@"listGroupUserWithGroupID,错误码:%d  详细信息:%@", error.code, error.message]))
}];

Web端示例代码:

const params = {
  groupId: 'test-id', // 消息组id
  sortType: 1, // 排序方式,0-时间递增顺序,1-时间递减顺序
  pageNum: 1, // 分页拉取的索引下标,第一次调用传1,后续调用+1
  pageSize: 20, // 分页拉取的大小,默认20条,最大50条
};
InteractionInstance.listGroupUser(params)
  .then((res) => {
    // 获取消息组成员列表成功
    const {
      total, // 总数
      userList, // 返回的消息组的在线成员列表
      hasMore, // 是否还剩数据
    } = res;
  })
  .catch((err) => {
    // 获取消息组成员列表失败
  });

获取消息组禁言列表

查询消息组中被禁言的用户列表。

Android端示例代码:

ImListMuteUsersReq req = new ImListMuteUsersReq();
req.groupId = "<群组Id>";
interactionService.listMuteUsers(req, new Callback<ImListMuteUsersRsp>() {
    @Override
    public void onSuccess(ImListMuteUsersRsp rsp) {
        ArrayList<ImMuteUser> muteUserModelList = rsp.muteUserModelList;
    }

    @Override
    public void onError(Error error) {
    }
});

iOS端示例代码:

[self.interactionEngine.interactionService listMuteUsersWithGroupID:self.groupId onSuccess:^(NSArray<AVCIInteractionMuteUser *> * _Nonnull users) {
    [users enumerateObjectsUsingBlock:^(AVCIInteractionMuteUser * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        S_LOG(([NSString stringWithFormat:@"被禁言用户,userId:%@", obj.userId]))
    }];
    if (users.count == 0) {
        S_LOG(@"没有被禁言用户")
    }
} onFailure:^(AVCIInteractionError * _Nonnull error) {
    F_LOG(([NSString stringWithFormat:@"listMuteUsersWithGroupID,错误码:%d  详细信息:%@", error.code, error.message]))
}];

Web端示例代码:

const params = {
  groupId: 'test-id', // 消息组id
};
InteractionInstance.listMuteUsers(params)
  .then((res) => {
    // 获取消息组禁言列表成功
    const {
      muteUserModelList, // 禁言用户列表
    } = res;
  })
  .catch((err) => {
    // 获取消息组禁言列表失败
  });

禁言消息组

  • 对消息组禁言,即开启全员禁言。

  • 与之对应的是取消禁言消息组接口:cancelMuteAll

Android端示例代码:

// 1. 禁言消息组
ImMuteAllReq req = new ImMuteAllReq();
req.groupId = "<群组Id>";
// 将本地全员禁言的消息发送给组内全员
req.broadCastType = BroadcastType.ALL.getValue();
interactionService.muteAll(req, new Callback<ImMuteAllRsp>() {
    @Override
    public void onSuccess(ImMuteAllRsp rsp) {

    }

    @Override
    public void onError(Error error) {
    }
});


// 2. 监听禁言消息组
InteractionEngine.instance().setMessageListener(groupId, new SimpleMessageListener() {
    @Override
    public void onMuteGroup(Message<MuteGroupModel> message) {
        // 消息组禁言回调
    }

    @Override
    public void onCancelMuteGroup(Message<CancelMuteGroupModel> message) {
        // 消息组取消禁言回调
    }
});

iOS端示例代码:

[self.interactionEngine.interactionService muteAll:self.groupId broadCastType:2 onSuccess:^{
    S_LOG(@"已全体禁言")
} onFailure:^(AVCIInteractionError * _Nonnull error) {
    F_LOG(([NSString stringWithFormat:@"muteAll,错误码:%d  详细信息:%@", error.code, error.message]))
}];
}

Web端示例代码:

const params = {
  groupId: 'test-id', // 消息组id
  broadCastType: 2, // 系统消息扩散类型,0: 不扩散;1:扩散到指定人; 2:扩散到群组
};
InteractionInstance.muteAll(params)
  .then(() => {
    // 消息组禁言成功
  })
  .catch((err) => {
    // 消息组禁言失败
  });

禁言消息组内指定成员

  • 对消息组内指定成员禁言。

  • 与之对应的是取消禁言消息组内指定成员接口:cancelMuteUser

Android端示例代码:

// 1. 禁言操作
ImMuteUserReq req = new ImMuteUserReq();
req.groupId = "<群组Id>";
req.muteUserList = new ArrayList<>(Arrays.asList(
        "userId1", "userId2", "userId3"
));
interactionService.muteUser(req, new Callback<ImMuteUserRsp>() {
    @Override
    public void onSuccess(ImMuteUserRsp rsp) {
    }

    @Override
    public void onError(Error error) {
    }
});


// 2. 监听禁言
InteractionEngine.instance().setMessageListener(groupId, new SimpleMessageListener() {
    @Override
    public void onMuteUser(Message<MuteUserModel> message) {
        // 个人禁言回调
    }

    @Override
    public void onCancelMuteUser(Message<CancelMuteUserModel> message) {
        // 个人取消禁言回调
    }
});

iOS端示例代码:

[self.interactionEngine.interactionService muteUsers:@[@"userId1", @"userId2", @"userId3"] groupID:self.groupId muteTime:0 broadCastType:2 onSuccess:^{
    S_LOG(([NSString stringWithFormat:@"已设置禁言:%@", uids]))
} onFailure:^(AVCIInteractionError * _Nonnull error) {
    F_LOG(([NSString stringWithFormat:@"muteUsers,错误码:%d  详细信息:%@", error.code, error.message]))
}];

Web端示例代码:

const params = {
  groupId: 'test-id', // 消息组id
  muteUserList: ['mute_user_id'], // 需要禁言的用户列表,最大200个
  // 取消禁言的用户列表字段名为 cancelMuteUserList
  muteTime: 0, // 非必填,禁言的时间,单位为s,如果不传或者传0则采用默认禁言时间
  broadCastType: 2, // 系统消息扩散类型,0: 不扩散;1:扩散到指定人; 2:扩散到群组
};
InteractionInstance.muteUser(params)
  .then(() => {
    // 禁言用户成功
  })
  .catch((err) => {
    // 禁言用户失败
  });

退出消息组

客户离开时需调用该方法,如直播场景中,离开LiveActivity时调用,以保证服务端数据的准确性。

Android端示例代码:

// 1. 退出消息组
ImLeaveGroupReq req = new ImLeaveGroupReq();
req.groupId = "<群组Id>";
// 设置扩散本次离开的消息(xx离开了消息组)给全组成员
req.broadCastType = BroadcastType.ALL.getValue();
interactionService.leaveGroup(req, new Callback<ImLeaveGroupRsp>() {
    @Override
    public void onSuccess(ImLeaveGroupRsp rsp) {
    }

    @Override
    public void onError(Error error) {
    }
});


// 2. 监听退出消息组
InteractionEngine.instance().setMessageListener(groupId, new SimpleMessageListener() {
    @Override
    public void onLeaveGroup(Message<LeaveGroupModel> message) {
        // 离开消息组回调
    }
});

iOS端示例代码:

[self.interactionEngine.interactionService leaveGroup:self.groupId broadCastType:2 onSuccess:^{
    weakSelf.groupId = nil;
    S_LOG(([NSString stringWithFormat:@"leaveGroup,当前GroupId:%@", self.groupId]))
} onFailure:^(AVCIInteractionError * _Nonnull error) {
    F_LOG(([NSString stringWithFormat:@"leaveGroup,错误码:%d  详细信息:%@", error.code, error.message]))
}];

Web端示例代码:

const params = {
  groupId: 'test-id', // 消息组id
  broadCastType: 2, // 系统消息扩散类型,0: 不扩散;1:扩散到指定人; 2:扩散到群组
};
InteractionInstance.leaveGroup(params)
  .then(() => {
    // 离开消息组成功
  })
  .catch((err) => {
    // 离开消息组失败
  });

消息

消息组消息分为系统消息和自定义消息。type字段值小于等于10000时表示系统消息,系统消息是SDK默认提供的信息类型,不受禁言限制。type字段值大于10000时表示自定义消息,自定义消息是由业务开发时自行拓展的消息,默认受禁言限制。

系统消息(点赞)

系统提供预置的点赞消息类型。

Android端示例代码:

// 1. 发起点赞
ImSendLikeReq req = new ImSendLikeReq();
req.groupId = "<群组Id>";
// 点赞数量 (上层注意做动作merge处理, 如1s最多请求一次)
req.count = 10;
interactionService.sendLike(req, new Callback<ImSendLikeRsp>() {
    @Override
    public void onSuccess(ImSendLikeRsp rsp) {
    }

    @Override
    public void onError(Error error) {
    }
});


// 2. 监听点赞
InteractionEngine.instance().setMessageListener(groupId, new SimpleMessageListener() {
    @Override
    public void onLikeReceived(Message<LikeModel> message) {
        // 点赞回调
    }
});

iOS端示例代码:

// 发送
[self.interactionEngine.interactionService sendLikeWithGroupID:self.groupId count:1 broadCastType:2 onSuccess:^{
    S_LOG(@"已发送点赞")
} onFailure:^(AVCIInteractionError * _Nonnull error) {
    F_LOG(([NSString stringWithFormat:@"sendLikeWithGroupID,错误码:%d  详细信息:%@", error.code, error.message]))
}];
// 接收
- (void)onLikeReceived:(AVCIInteractionGroupMessage *)message {
    NSString *msg = [NSString stringWithFormat:@"onMessageReceived:%@, type:%d, gid:%@, uid:%@, nick_name:%@", message.data, message.type, message.groupId, message.senderInfo.userID, message.senderInfo.userNick];
    A_MSG(msg);
}

Web端点赞及系统消息处理示例:

const params = {
  groupId: 'test-id', // 消息组id
  count: 1, // 点赞数
  broadCastType: 2, // 系统消息扩散类型,0: 不扩散;1:扩散到指定人; 2:扩散到群组
};
// 点赞接口
InteractionInstance.sendLike(params)
  .then(() => {
    // 点赞成功,将会收到 PaaSLikeInfo 类型的消息
  })
  .catch((err) => {
    // 点赞失败
  });

// 处理系统事件
const { InteractionEventNames, InteractionMessageTypes } = window.AliyunInteraction;
InteractionInstance.on(InteractionEventNames.Message, (eventData) => {
  console.log('收到信息啦', eventData);
  const { type, data, messageId, senderId, senderInfo } = eventData;
  switch (type) {
    case InteractionMessageTypes.PaaSLikeInfo:
      // 点赞事件 1001,data 为点赞数据
      break;
    case InteractionMessageTypes.PaaSUserJoin:
      // 用户加入事件 1002,data 为直播间统计数据
      break;
    case InteractionMessageTypes.PaaSUserLeave:
      // 用户离开事件 1003
      break;
    case InteractionMessageTypes.PaaSMuteGroup:
      // 互动消息组被禁言 1004
      break;
    case InteractionMessageTypes.PaaSCancelMuteGroup:
      // 互动消息组取消禁言 1005
      break;
    case InteractionMessageTypes.PaaSMuteUser:
      // 某个用户被禁言 1006,data 为用户信息
      break;
    case InteractionMessageTypes.PaaSCancelMuteUser:
      // 某个用户被取消禁言 1007,data 为用户信息
      break;
    default:
      break;
  }
});

自定义消息

自定义消息分为向组内全员和向组内指定用户两种方式,两者参数几乎一致,向组内指定用户方式多了一个receiverIdList参数。

Android端示例代码:

// 1. 向组内全员发消息
ImSendMessageToGroupReq req = new ImSendMessageToGroupReq();
req.groupId = groupId;
// 指定消息类型
req.type = MSG_TYPE_COMMENT;
// 指定是否跳过安全审核
req.skipAudit = false;
// 指定是否跳过禁言处理
req.skipMuteCheck = false;
// 指定发送数据
Map<String, Object> data = new HashMap<>();
req.data = App.getGson().toJson(new HashMap<String, Object>() {{
    put("content", inputText);
}});
interactionService.sendMessageToGroup(req, new Callback<ImSendMessageToGroupRsp>() {
    @Override
    public void onSuccess(ImSendMessageToGroupRsp rsp) {

    }
    @Override
    public void onError(Error error) {
    }
});


// 2. 向组内指定用户发消息
ImSendMessageToGroupUsersReq req = new ImSendMessageToGroupUsersReq();
req.groupId = groupId;
// 指定消息类型
req.type = MSG_TYPE_COMMENT;
// 指定是否跳过安全审核
req.skipAudit = false;
// 指定是否跳过禁言处理
req.skipMuteCheck = false;
// 指定发送数据
Map<String, Object> data = new HashMap<>();
req.data = App.getGson().toJson(new HashMap<String, Object>() {{
    put("content", inputText);
}});
// 指定接收对象
req.receiverIdList = new ArrayList<String>() {{
    add("<接收消息的userId>");
}};
interactionService.sendMessageToGroupUsers(req, new Callback<ImSendMessageToGroupUsersRsp>() {
    @Override
    public void onSuccess(ImSendMessageToGroupUsersRsp rsp) {

    }
    @Override
    public void onError(Error error) {
    }
});


// 3. 消息监听
InteractionEngine.instance().setMessageListener(groupId, new SimpleMessageListener() {
    @Override
    public void onCustomMessageReceived(Message<String> message) {
        // 自定义消息回调
    }
});

iOS端示例代码:

// 全局发送
[self.interactionEngine.interactionService sendTextMessage:@"发送消息" groupID:self.groupId type:10001 skipMuteCheck:NO skipAudit:NO onSuccess:^{
    S_LOG(@"已发送成功")
} onFailure:^(AVCIInteractionError * _Nonnull error) {
    F_LOG(([NSString stringWithFormat:@"sendTextMessage,错误码:%d  详细信息:%@", error.code, error.message]))
}];

// 给指定用户id发送消息
[self.interactionEngine.interactionService sendTextMessageToGroupUsers:@"发送消息" groupID:self.groupId type:10001 userIDs:@[@"id1", @"id2"] skipMuteCheck:NO skipAudit:NO onSuccess:^{
    S_LOG(@"已发送成功")
} onFailure:^(AVCIInteractionError * _Nonnull error) {
    F_LOG(([NSString stringWithFormat:@"sendTextMessageToGroupUsers,错误码:%d  详细信息:%@", error.code, error.message]))
}];

// 接收
- (void)onCustomMessageReceived:(AVCIInteractionGroupMessage *)message {
    NSString *msg = [NSString stringWithFormat:@"onMessageReceived:%@, type:%d, gid:%@, uid:%@, nick_name:%@", message.data, message.type, message.groupId, message.senderInfo.userID, message.senderInfo.userNick];
    A_MSG(msg);
}

Web端发送消息及自定义消息处理示例 :

// 此处是自定义的 Interaction 消息类型,约定 type > 10000,你可以根据你业务需要进行修改
export enum CustomMessageTypes {
  Comment = 10001, // 评论
  LiveStart = 10003, // 开始直播
  LiveStop = 10004, // 结束直播
  LiveInfo = 10005, // 直播间信息
}

const params: any = {
  groupId: 'test-id', // 消息组id
  type: CustomMessageTypes.Comment, // 消息类型,大于10000位自定义消息
  data: JSON.stringify({ content: 'test' }), // 消息体,JSONString
  skipMuteCheck: false,  // 跳过禁言检测,true: 忽略被禁言用户,还可发消息;false: 当被禁言时,消息无法发送,默认为false,即为不跳过禁言检测。
  skipAudit: false, // 跳过安全审核,true: 发送的消息不经过阿里云安全审核服务审核;false:发送的消息经过阿里云安全审核服务审核,审核失败则不发送;
};
// 若是想整个消息组都广播,使用 sendMessageToGroup
InteractionInstance.sendMessageToGroup(params)
  .then(() => {
    // 发送成功
  })
  .catch((err) => {
    // 发送失败
  });

// 若是 sendMessageToGroupUsers 接口,参数还有 receiverIdList 指定接收者用户ID列表,最大100人
params.receiverIdList = ['user_id'];
InteractionInstance.sendMessageToGroupUsers(params)
  .then(() => {
    // 发送成功
  })
  .catch((err) => {
    // 发送失败
  });

// 自定义消息处理,可以与上面系统消息处理放在一个 switch 中
const { InteractionEventNames } = window.AliyunInteraction;
InteractionInstance.on(InteractionEventNames.Message, (eventData) => {
  console.log('收到信息啦', eventData);
  const { type, data, messageId, senderId, senderInfo } = eventData;
  switch (type) {
    case CustomMessageTypes.Comment:
      // 接收到评论消息
      break;
    case CustomMessageTypes.LiveStart:
      // 直播开始
      break;
    case CustomMessageTypes.LiveStop:
      // 直播结束
      break;
    case CustomMessageTypes.LiveInfo:
      // 直播间消息
      break;
    default:
      break;
  }
});