Android端集成

互动消息是用于加强直播间消息沟通、提升交互体验的服务。提供了丰富、易集成的SDK,可在用户开发的直播应用中轻松集成评论、弹幕、点赞等能力。本文介绍Android端集成互动消息应用的操作步骤。

前提条件

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

环境要求

  • Android 5.0(SDK API Level 21)及以上版本。

  • Android Studio 4.0以及以上版本。

集成SDK

  1. 添加Maven仓库。

    repositories {
        maven { url 'https://maven.aliyun.com/nexus/content/repositories/releases' }
    }
  2. 添加SDK依赖。

       // 互动库
       implementation "com.aliyun.sdk.android:AliVCInteractionMessage:1.4.2"
  3. 配置AndroidManifest.xml权限。

       <uses-permission android:name="android.permission.INTERNET" />
       <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  4. 在应用工程的proguard-rules.pro文件中添加如下代码,以防止SDK代码被混淆。

    说明

    v1.4.0、v1.4.1 版本必须添加如下混淆配置。其他版本非必须,可通过aar包自动引入混淆配置。

    ###################### 混淆配置 #########################
    -keep class com.aliyun.im.common.** { *; }
    -keepclassmembers class com.aliyun.im.common.** { *; }
    -keep class com.aliyun.im.interaction.** { *; }
    -keepclassmembers class com.aliyun.im.interaction.** { *; }
    -keep interface com.aliyun.im.AliVCIMInterface { *; }
    -keep interface com.aliyun.im.AliVCIMGroupInterface { *; }
    -keep interface com.aliyun.im.AliVCIMMessageInterface { *; }

使用SDK

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

  1. 初始化

  2. 登录

  3. 相关操作

  4. 登出

  5. 反初始化

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

相关操作

  • 群组操作

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

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

    • 进入群组

    • 离开群组

    • 查询群组信息

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

    • 查询群组最近成员列表

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

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

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

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

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

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

  • 消息操作

    • 单发消息

    • 群发消息

    • 查询最近群发消息列表

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

    • 删除/撤回群消息

    • 查询历史消息

注意事项

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及“-”, 不能包含其他字符

初始化

App入口(如Application/ActivityonCreate中)进行初始化配置。

ImSdkConfig config = new ImSdkConfig();
config.deviceId = "deviceId"; //[选填]
config.appId = "appId"; //[必填],传空会返回初始化失败-2
config.appSign = "appSign"; //[必填],传空会返回初始化失败-2
config.logLevel = ImLogLevel.DEBUG; //[选填],指定Log日志可输出的最小等级,默认是ImLogLevel.DEBUG;若需要关闭Log日志,则设置为ImLogLevel.NONE;
// 初始化返回非0,表示初始化失败,其中1001:重复初始化、1002:创建底层引擎失败、-1:底层重复初始化、-2:初始化配置信息有误
int ret = AliVCIMEngine.instance().init(context, config);

监听长连接状态

AliVCIMEngine.instance().addSdkListener(new ImSdkListener() {
    @Override
    public void onConnecting() {

    }
    @Override
    public void onConnectSuccess() {
    }
    @Override
    public void onConnectFailed(com.aliyun.im.common.Error error) {
    }
    @Override
    public void onDisconnect(int code) {
    }
    // 登录token失效(如token过期)会通过该接口获取新的token,务必实现该接口
    @Override
    public void onTokenExpired(ImTokenCallback callback) {
        // 第一步,实现新token的生成,若需要网络请求等耗时操作,请务必抛到异步线程实现;
        // 第二步,若token生成失败,则通过 callback.onError() 回调错误信息;
        // 		若token生成成功,则通过 callback.onSuccess() 回调token信息;
    }
    @Override
    public void onReconnectSuccess(ArrayList<ImGroupInfo> groupStatus) {
    }

    /**
     * v1.4.1版本开始,新增连接状态的回调:一共有4个状态
     * ImLinkState.IDLE:初始化状态;登录前,处于该状态;
     * ImLinkState.CONNECTING:连接中;登录中或断连重连中,处于该状态;
     * ImLinkState.CONNECTED:已连接;登录成功或断连重连成功,处于该状态;
     * ImLinkState.DISCONNECTED:已断连;因断网等异常情况导致断连,处于该状态;
     * 
     * 可以结合各种连接状态的变化,增加相关交互提示;例如 CONNECTED -> DISCONNECTED,提示用户检查网络状态等
     */
    @Override
    public void onLinkStateEvent(ImLinkStateEvent event) {
        // 获取连接变化前的状态
        ImLinkState previousState = event.getPreviousState();
        // 获取连接变化后的状态
        ImLinkState currentStateState = event.getCurrentState();
    }
});

登录

ImLoginReq req = new ImLoginReq();

req.user.userId = userId;
//透传业务额外信息
Map<String, Object> data = new HashMap<>();
data.put("level", "high");
req.user.userExtension = App.getGson().toJson(data).toString();

req.userAuth = new ImAuth(nonce,  timestamp, role, app_token);
AliVCIMEngine.instance().login(req, new ImSdkCallback());

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

  • 管理员(值:admin)

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

  • 非管理员(值:非admin)

登出

AliVCIMEngine.instance().logout();

反初始化

登出后进行反初始化。

 AliVCIMEngine.instance().unInit();

消息服务

//消息服务
AliVCIMMessageInterface messageInterface = AliVCIMEngine.instance().getMessageManager();

非管理员操作

监听消息

//监听消息
messageInterface.addMessageListener(new ImMessageListener() {
    @Override
    public void onRecvC2cMessage(ImMessage msg) {
        
    }
    @Override
    public void onRecvGroupMessage(ImMessage msg, String groupId) {
    }

    @Override
    public void onDeleteGroupMessage(String msgId, String groupId) {
    }
});

发送C2C消息

ImSendMessageToUserReq req = new ImSendMessageToUserReq();
req.type = 88888;
req.data = "This is a test message";
req.receiverId = userInput.getText().toString();
// 需确保对方在线,否则会返回错误码424,此时建议待对方上线后再重发
messageInterface.sendC2cMessage(req, new ImSdkValueCallback<ImSendMessageToUserRsp>() {
    @Override
    public void onSuccess(ImSendMessageToUserRsp data) {
        Log.v(ImTag.TAG, "发送C2C消息成功:" + data.messageId);
    }
    @Override
    public void onFailure(Error error) {
        Log.v(ImTag.TAG, "发送C2C消息失败:error" + error.code);
    }
});

在群组内发送全员消息

ImSendMessageToGroupReq req = new ImSendMessageToGroupReq();
/**
 * 设置消息等级,默认是普通消息ImMessageLevel.NORMAL,可接受消息丢失,如弹幕等;
 * 若是高优消息,可设置为ImMessageLevel.HIGH,提高消息可靠性;
 */
req.level = ImMessageLevel.NORMAL;
req.type = 88888;
req.data = "a test";
req.groupId = groupId;
// 需确保已经加入群成功(即在AliVCIMGroupInterface.joinGroup回调成功之后),再发送群组消息,否则会返回错误码425
messageInterface.sendGroupMessage(req, new ImSdkValueCallback<ImSendMessageToGroupRsp>() {
    @Override
    public void onSuccess(ImSendMessageToGroupRsp data) {
        Log.v(ImTag.TAG, "发送群消息成功:" + data.messageId);
    }
    @Override
    public void onFailure(Error error) {
        Log.v(ImTag.TAG, "发送群消息失败" + error.code);
    }
});

查询最近消息列表

ImListRecentMessageReq req;
req.groupId = groupId;
messageInterface.listRecentMessage(req, new ImSdkValueCallback<ImListRecentMessageRsp>() {
    @Override
    public void onSuccess(ImListRecentMessageRsp data) {
    }
    @Override
    public void onFailure(com.aliyun.im.common.Error error) {
    }
});

查询历史消息

//该接口主要用户直播结束后的历史消息回放,用户无需进入群组可查询,比较耗时,在直播过程中不建议使用,另外该接口后续会收费。
ImListHistoryMessageReq req = new ImListHistoryMessageReq();
req.groupId = "群ID";
req.nextPageToken = 231231;  //不传时表示第一页,遍历时服务端会返回下一页Token,客户端获取下一页时应带上
req.type = 99999;            // 自定义消息类型,需大于10000
req.sortType = ImSortType.ASC;
req.pageSize = 20;
req.beginTime = 0; // 按时间范围遍历,开始时间,单秒,为0时表示最早时间
req.endTime = 0;   // 按时间范围遍历,结束时间,单秒,为0时表示最晚时间
messageInterface.listHistoryMessage(req, new ImSdkValueCallback<ImListHistoryMessageRsp>() {
    @Override
    public void onSuccess(ImListHistoryMessageRsp rsp) {
    }
    @Override
    public void onFailure(Error error) {
    }
});

删除消息

ImDeleteMessageReq req = new ImDeleteMessageReq();
req.groupId = "群ID";
req.messageId = "消息ID";
messageInterface.deleteMessage(req, new ImSdkCallback() {
    @Override
    public void onSuccess() {
                
    }

    @Override
    public void onFailure(Error error) {

    }
});

管理员操作

查询消息列表

//该接口(仅限群主/群管理员操作)
ImListMessageReq req = new ImListMessageReq();
req.groupId = "群ID";
req.nextPageToken = 231231;  //不传时表示第一页,遍历时服务端会返回下一页Token,客户端获取下一页时应带上
req.type = 99999;            // 自定义消息类型,需大于10000
req.sortType = ImSortType.ASC;
req.pageSize = 20;
req.beginTime = 0; // 按时间范围遍历,开始时间,单秒,为0时表示最早时间
req.endTime = 0;   // 按时间范围遍历,结束时间,单秒,为0时表示最晚时间
messageInterface.listMessage(req, new ImSdkValueCallback<ImListMessageRsp>() {
    @Override
    public void onSuccess(ImListMessageRsp rsp) {
    }
    @Override
    public void onFailure(Error error) {
    }
});

群组服务

//群组服务
AliVCIMGroupInterface groupInterface = AliVCIMEngine.instance().getGroupManager();

非管理员操作

监听群组状态

groupManager.addGroupListener(new ImGroupListener() {
    /**
     * 群组成员变化通知
     * @param groupMemberChangeInfo 群成员变化信息
     * @apiNote v1.4.1新增;若重写该接口,则不再回调旧接口,请务必迁移旧的逻辑;
     */
    @Override
    public void onMemberChange(ImGroupMemberChangeInfo groupMemberChangeInfo) {
        // 可以监听这个回调,在群人员变化后,更新当前房间的人数、累积访问量(观看数)
        // 若当前是大群(群人数超过一定量级),即groupMemberChangeInfo.isBigGroup()返回true,群成员变化的通知会控制频率,通知可能不及时;若需要实时通知,可通过OpenAPI对接该回调接口;
    }

    /**
     * 退出群组通知
     * @param groupId 群组ID
     * @param reason 退出原因 , 1: 群被解散, 2:被踢出来了
     */
    @Override
    public void onExit(String groupId, int reason) {
    }

    /**
     * 群组禁言状态通知
     * @param groupId 群组ID
     * @param status 群组禁言状态
     */
    @Override
    public void onMuteChange(String groupId, ImGroupMuteStatus status) {
    }

    /**
     * 群组信息变化通知
     * @param groupId 群组ID
     * @param info 群组信息
     */
    @Override
    public void onInfoChange(String groupId, ImGroupInfoStatus info) {
    }
});

加入群组

ImJoinGroupReq req = new ImJoinGroupReq();
req.groupId = groupId;
groupInterface.joinGroup(req, new ImSdkValueCallback<ImJoinGroupRsp>() {
    @Override
    public void onSuccess(ImJoinGroupRsp data) {
        
    }

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

离开群组

ImLeaveGroupReq req = new ImLeaveGroupReq();
req.groupId = groupId;
groupInterface.leaveGroup(req, new ImSdkCallback() {
    @Override
    public void onSuccess() {
        
    }

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

查看最近群组成员

ImListRecentGroupUserReq req = new ImListRecentGroupUserReq();
req.groupId = groupId;
groupManager.listRecentGroupUser(req, new ImSdkValueCallback<ImListRecentGroupUserRsp>() {
    @Override
    public void onSuccess(ImListRecentGroupUserRsp data) {
    }
    @Override
    public void onFailure(Error error) {
    }
});

管理员操作

创建群组

ImCreateGroupReq req = new ImCreateGroupReq();
req.groupName = "羽毛球群";
Map<String, Object> data = new HashMap<>();
data.put("desc", "一三五晚8-10");
req.groupMeta = App.getGson().toJson(data).toString();
groupInterface.createGroup(req, new ImSdkValueCallback<ImCreateGroupRsp>() {
    @Override
    public void onSuccess(ImCreateGroupRsp data) {
        Log.v(ImTag.TAG, "Create Group Success:" + data.groupId);
        
    }
    @Override
    public void onFailure(com.aliyun.im.common.Error error) {
        Log.v(ImTag.TAG, "Create Group Failure:" + error.getCode());
    }
});

删除群组

ImCloseGroupReq req = new ImCloseGroupReq();
req.groupId = groupId;
groupInterface.closeGroup(req, new ImSdkCallback() {
    @Override
    public void onSuccess() {
        
    }

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

修改群组

ImModifyGroupReq req = new ImModifyGroupReq();
req.groupId = groupId;
req.admins.add(adminUserId);//指定群管理员ID列表,最多设置3个管理员;若需要清空列表,则配置空列表或者不设置,同时必须设置req.forceUpdateAdmins=true;
req.groupMeta = "群信息拓展字段";//添加群拓展信息;若需要清空,则配置空字符串或者不设置,同时必须设置req.forceUpdateGroupMeta=true;
groupInterface.modifyGroup(req, new ImSdkCallback() {
    @Override
    public void onSuccess() {
        
    }

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

查询群组成员

ImListGroupUserReq req = new ImListGroupUserReq();
req.groupId = groupId;
req.sortType = ImSortType.ASC;
req.pageSize = 30;
groupManager.listGroupUser(req, new ImSdkValueCallback<ImListGroupUserRsp>() {
    @Override
    public void onSuccess(ImListGroupUserRsp data) {
    }
    @Override
    public void onFailure(Error error) {
    }
});

全体禁言

ImMuteAllReq req = new ImMuteAllReq();
req.groupId = groupId;
groupInterface.muteAll(req, new ImSdkCallback() {
    @Override
    public void onSuccess() {
        
    }

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

取消禁言

ImCancelMuteAllReq req = new ImCancelMuteAllReq();
req.groupId = groupId;
groupInterface.cancelMuteAll(req, new ImSdkCallback() {
    @Override
    public void onSuccess() {
        
    }

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

禁言指定用户

ImMuteUserReq req = new ImMuteUserReq();
req.groupId = groupId;
req.userList.add(muteUserId);
groupInterface.muteUser(req, new ImSdkCallback() {
    @Override
    public void onSuccess() {
        
    }

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

取消禁言

ImCancelMuteUserReq req = new ImCancelMuteUserReq();
req.groupId = groupId;
req.userList.add(muteUserId);
groupInterface.cancelMuteUser(req, new ImSdkCallback() {
    @Override
    public void onSuccess() {
        
    }

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

查询禁言用户

ImListMuteUsersReq req = new ImListMuteUsersReq();
req.groupId = groupId;
groupManager.listMuteUsers(req, new ImSdkValueCallback<ImListMuteUsersRsp>() {
    @Override
    public void onSuccess(ImListMuteUsersRsp data) {
        
    }
    @Override
    public void onFailure(Error error) {
    }
});