移动客服Android SDK API

消息

发送文本消息

//发送一条文本消息, content 为消息文字内容, toChatUsername为客服设置的IM服务号
        Message message = Message.createTxtSendMessage(content, toChatUsername);
        ChatClient.getInstance().getChat().sendMessage(message, new Callback() {});

发送语音消息

//filePath为语音文件路径, length为录音时间(秒), toChatUsername为IM服务号
    Message message = Message.createVoiceSendMessage(filePath, length, toChatUsername);
    ChatClient.getInstance().getChat().sendMessage(message, new Callback(){});

发送图片消息

//filePath为图片路径, false为不发送原图(默认超过100k的图片都会压缩后发给对方),需要发送原图传true, toChatUsername为IM服务号 
        Message message = Message.createImageSendMessage(filePath, false, toChatUsername);
        ChatClient.getInstance().getChat().sendMessage(message, new Callback(){});

发送地理位置

//latitude为维度,longitude为经度,locAddress为具体位置内容, toChatUsername为IM服务号
     Message message = Message.createLocationSendMessage(latitude, longitude, locAddress, toChatUsername);
     ChatClient.getInstance().getChat().sendMessage(message, new Callback(){});

发送文件消息

//filePath为本地文件路径,toChatUsername为IM服务号
    Message message = Message.createFileSendMessage(filePath, toChatUsername);
    ChatClient.getInstance().getChat().sendMessage(message, new Callback(){});

发送透传消息

//机器人转人工的地方有用到
       Message message = Message.createSendMessage(Message.Type.CMD);
        String action = "action";//具体的action
        message.addBody(new EMCmdMessageBody(action));
        message.setTo(toChatUsername);
        ChatClient.getInstance().getChat().sendMessage(message, new Callback(){});

发送扩展消息

任何消息类型,均可发送扩展消息。某些功能是通过扩展消息实现的,例如:指定技能组、指定客服、传递访客的昵称电话等。

Message message = Message.createTxtSendMessage(content, toChatUsername);
        // 增加自己特定的属性
        message.setAttribute("attribute1", "value");
        ChatClient.getInstance().getChat().sendMessage(message, new Callback() {});

发送带访客属性的消息

当需要为客服提供访客属性(昵称、电话等)时,需要为消息带上访客属性扩展。发送文本消息示例:

VisitorInfo info = ContentFactory.createVisitorInfo(null);
		info.nickName("user nick")
		    .name("truly name")
		    .qq("10000")
		    .companyName("环信")
		    .description("")
		    .email("abc@123.com");
Message message = Message.createTxtSendMessage(content, toChatUsername);
message.addContent(info);
ChatClient.getInstance().getChat().sendMessage(message, new Callback() {});

发送轨迹消息

VisitorTrack track = ContentFactory.createVisitorTrack(null);
		track.title("test_track1")  //显示标题
                 .price("¥235") //显示价格
                 .desc("假两件衬衣+V领毛衣上衣") //描述
                 .imageUrl("http://o8ugkv090.bkt.clouddn.com/em_three.png")//显示图片
                 .itemUrl("http://www.baidu.com"); //点击会跳转到哪
Message message = Message.createTxtSendMessage(content, toChatUsername);
message.addContent(track);
ChatClient.getInstance().getChat().sendMessage(message, new Callback() {});

发送订单消息

OrderInfo info = ContentFactory.createOrderInfo(null);
   info.title("test_order1")
			    .orderTitle("订单号:7890")
			    .price("¥128")
			    .desc("2015早春新款高腰复古牛仔裙")
			    .imageUrl(IMAGE_URL_1)
			    .itemUrl("http://www.baidu.com");
   Message message = Message.createTxtSendMessage(content, toChatUsername);
   message.addContent(info);
   ChatClient.getInstance().getChat().sendMessage(message, new Callback() {});

指定客服消息

调度时,指定某个客服。

客服账号为客服的登录邮箱地址。

AgentIdentityInfo info = ContentFactory.createAgentIdentityInfo(null);
   info.agentName(agentName); //客服账号
   Message message = Message.createTxtSendMessage(content, toChatUsername);
   message.addContent(info);
   ChatClient.getInstance().getChat().sendMessage(message, new Callback() {});

指定技能组消息

调度时,指定某个技能组。

技能组名称须和客服系统设置的技能组名称完全一致,中英文均可。

QueueIdentityInfo info = ContentFactory.createQueueIdentityInfo(null);
		info.queueName(queueName); // 技能组名称
   Message message = Message.createTxtSendMessage(content, toChatUsername);
   message.addContent(info);
   ChatClient.getInstance().getChat().sendMessage(message, new Callback() {});

接收消息

通过注册消息监听来接收消息。

ChatClient.getInstance().getChat().addMessageListener(new ChatManager.MessageListener() {
            @Override
            public void onMessage(List<Message> list) {
                //收到普通消息
            }

            @Override
            public void onCmdMessage(List<Message> list) {
                 //收到命令消息,命令消息不存数据库,一般用来作为系统通知,例如留言评论更新,
                 //会话被客服接入,被转接,被关闭提醒
            }

            @Override
            public void onMessageStatusUpdate() {
            //消息的状态修改,一般可以用来刷新列表,显示最新的状态

            }

            @Override
            public void onMessageSent() {
            //发送消息后,会调用,可以在此刷新列表,显示最新的消息

            }
        });
        
//        不需要的时候移除listener,如在activity的onDestroy()时
ChatClient.getInstance().getChat().removeMessageListener(msgListener);

检测消息类型

message.getType() == Message.Type.LOCATION  位置消息
message.getType() == Message.Type.FILE   文件消息
message.getType() == Message.Type.IMAGE  图片消息
message.getType() == Message.Type.VOICE  语音消息
message.getType() == Message.Type.CMD    命令消息
message.getType() == Message.Type.TXT    文本消息或文本扩展消息
     //当文本消息时,需要其他其他的检测,可能为其他类型的消息
     MessageHelper.getEvalRequest(message) != null  满意度评价消息
     MessageHelper.getOrderInfo(message) != null    订单消息
     MessageHelper.getVisitorTrack(message) != null 轨迹消息
     MessageHelper.getRobotMenu(message) != null  机器人菜单消息
     MessageHelper.getToCustomServiceInfo(message) != null  转接客服按钮消息
     

监听消息状态

通过 message 设置消息的成功失败监听。

message.setMessageStatusCallback(new Callback(){});

获取聊天记录

Conversation conversation = ChatClient.getInstance().getChat().getConversation(toChatUsername);
//获取此会话的所有消息
 List<Message> messages = conversation.getAllMessages();
 //SDK初始化加载的聊天记录为20条,到顶时需要去DB里获取更多
//获取startMsgId之前的pagesize条消息,此方法获取的messages SDK会自动存入到此会话中,APP中无需再次把获取到的messages添加到会话中
List<Message> messages = conversation.loadMoreMsgFromDB(startMsgId, pageSize);

获取未读消息数量

Conversation conversation = ChatClient.getInstance().getChat().getConversation(toChatUsername);
 conversation.getUnreadMsgCount()

未读消息数清零

Conversation conversation = ChatClient.getInstance().getChat().getConversation(toChatUsername);
 //指定会话消息未读数清零
 conversation.markAllMessagesAsRead();
 //把一条消息置为已读
 conversation.markMessageAsRead(messageId);
 //所有未读消息数清零
 ChatClient.getInstance().getChat().markAllConversationsAsRead();

获取消息总数

Conversation conversation = ChatClient.getInstance().getChat().getConversation(toChatUsername);
//获取此会话在本地的所有的消息数量
conversation.getAllMsgCount()
//如果只是获取当前在内存的消息数量,调用
conversation.getAllMessages().size()

会话

获取所有会话

Map<String, Conversation> conversations = ChatClient.getInstance().getChat().getAllConversations();

删除会话及聊天记录

//删除和某个user会话,如果需要保留聊天记录,传false
ChatClient.getInstance().getChat().deleteConversation(username, true);
 //删除当前会话的某条聊天记录
 Conversation conversation = ChatClient.getInstance().getChat().getConversation(toChatUsername);
conversation.removeMessage(deleteMsg.msgId);

留言

获取所有留言

/**
     * 获取所有留言
     * @param projectId  留言ProjectId  进入“管理员模式 → 留言”,可以看到这个Project ID
     * @param targetUser    接入环信移动客服系统使用的关联的IM服务号
     * @param page      第几页数据,从0开始
     * @param pageSize  每页显示的条数
     * @param callback
     */
TicketManager.getInstance().getTickets(projectId, targetUser, page, pageSize, new ValueCallBack(){})

创建一个新的留言

/**
     * 创建一个新的留言
     *
     * @param postContent
     * @param projectId 留言ProjectId  进入“管理员模式 → 留言”,可以看到这个Project ID
     * @param imUser  接入环信移动客服系统使用的关联的IM服务号
     * @param callback
     */
TicketManager.getInstance().createLeaveMessage(postContent, projectId, imUser, new ValueCallBack(){});

获取一个留言的所有评论

/**
     * 获取一个留言的所有评论 此API获取最新100个评论
     *
     * @param projectId 留言ProjectId  进入“管理员模式 → 留言”,可以看到这个Project ID
     * @param ticketId  留言ID
     * @param targetUser  接入环信移动客服系统使用的关联的IM服务号
     * @param callback
     */
   TicketManager.getInstance().getComments(projectId, ticketId, targetUser, new ValueCallBack(){});
   
   /**
     * 获取一个留言的所有评论 分页获取
     *
     * @param projectId 留言ProjectId  进入“管理员模式 → 留言”,可以看到这个Project ID
     * @param ticketId  留言ID
     * @param targetUser  接入环信移动客服系统使用的关联的IM服务号
     * @param callback
     * @param page  第几页,页码从0开始
     * @param size  每页显示多少个
     */
   TicketManager.getInstance().getComments(projectId, ticketId, targetUser, new ValueCallBack(){}, page, size);

给一个留言添加评论

/**
     * 给一个留言添加评论
     *
     * @param projectId         留言ProjectId  进入“管理员模式 → 留言”,可以看到这个Project ID
     * @param ticketId          留言ID
     * @param targetUser        接入环信移动客服系统使用的关联的IM服务号
     * @param newCommentBodyJson
     * @param callback
     */
   TicketManager.getInstance().createComment(projectId, ticketId, targetUser, newCommentBodyByJson, new ValueCallBack(){});

获取工作状态

/**
     * 是否显示留言信息(一般在上班显示联系客服界面,在下班情况下显示留言界面)
     * 返回true 为下班状态, 返回false为上班状态
     */
  TicketManager.getInstance().getWorkStatus(new ValueCallBack(){});

设置当前登录用户的推送昵称

更新当前用户的在苹果 APNS 推送的昵称 如果个人的昵称被更改,也要去环信服务器更新下 nickname 防止显示差异。

//此方法传入一个字符串String类型的参数,返回成功或失败的一个Boolean类型的返回值
ChatClient.getInstance().updateNickToServer(nickname)

实时音视频

监听呼入通话

通过注册相应 action 的 BroadcastReceiver 来监听呼叫过来的通话,接到广播后开发者可以调起 APP 里的通话 Activity。

IntentFilter callFilter = new IntentFilter(ChatClient.getInstance().callManager().getIncomingCallBroadcastAction());
registerReceiver(new CallReceiver(), callFilter);

private class CallReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // 拨打方username
        String from = intent.getStringExtra("from");
        // call type
        String type = intent.getStringExtra("type");
                //跳转到通话页面
    }
}

监听通话状态

通过 addCallStateChangeListener 监听通话状态。

注意:在收到 DISCONNNECTED 回调时才能 finish 当前页面(保证通话所占用的资源都释放完),然后开始下一个通话

ChatClient.getInstance().callManager().addCallStateChangeListener(new CallStateChangeListener() {
    @Override
    public void onCallStateChanged(CallState callState, CallError error) {
        switch (callState) {
        case CONNECTING: // 正在连接对方
           
            break;
        case CONNECTED: // 双方已经建立连接
           
            break;

        case ACCEPTED: // 电话接通成功
           
            break;
        case DISCONNNECTED: // 电话断了

            break;
        case NETWORK_UNSTABLE: //网络不稳定
            if(error == CallError.ERROR_NO_DATA){
        //无通话数据
        }else{
        }
        break;
    case NETWORK_NORMAL: //网络恢复正常
        break;
        default:
            break;
        }
    }
});

拨打语音通话

/**
* 拨打语音通话
* @param to
* @throws EMServiceNotReadyException
*/
try {
    ChatClient.getInstance().callManager().makeVoiceCall(username);
} catch (EMServiceNotReadyException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

拨打视频通话

/**
* 拨打视频通话
* @param to
* @throws EMServiceNotReadyException
*/
try {
    ChatClient.getInstance().callManager().makeVideoCall(username);
} catch (EMServiceNotReadyException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

接听通话

/**
* 接听通话
* @throws EMNoActiveCallException
* @throws EMNetworkUnconnectedException
*/
try {
    ChatClient.getInstance().callManager().answerCall();
} catch (EMNoActiveCallException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (EMNetworkUnconnectedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

拒绝接听

/**
* 拒绝接听
* @throws EMNoActiveCallException
*/
try {
    ChatClient.getInstance().callManager().rejectCall();
} catch (EMNoActiveCallException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

挂断通话

/**
* 挂断通话
*/
ChatClient.getInstance().callManager().endCall();

暂停和恢复语音或视频数据传输

  • 暂停语音数据传输:

ChatClient.getInstance().callManager().pauseVoiceTransfer();

  • 恢复语音数据传输:

ChatClient.getInstance().callManager().resumeVoiceTransfer();

  • 暂停视频(图像)数据传输:

ChatClient.getInstance().callManager().pauseVideoTransfer();

  • 恢复视频(图像)数据传输:

ChatClient.getInstance().callManager().resumeVoiceTransfer();

调用后对方会收到相应VOICE_PAUSE、VOICE_RESUME、VIDEO_PAUSE、VIDEO_RESUME的callstate的变动通知。

切换摄像头

视频通话时如果有前置摄像头,默认使用前置的,提供切换 API 切换到别的摄像头。

ChatClient.getInstance().callManager().switchCamera();

视频通话设置显示自己和对方图像的 surfaceView

视频通话需要预先设置 localSurfaceView、oppositeSurfaceView, 而且必须在Activity.onCreate(Context context)方法中设置,之后才能正确捕捉 Surface 的变化。

ChatClient.getInstance().callManager().setSurfaceView(localSurface, oppositeSurface);

高级功能

显示排队人数

首先,初始化时,需要调用option.showVisitorWaitCount(),然后添加WaitListener.

注:“显示排队人数”功能为增值服务,需要在移动客服系统开通该功能才能使用。如需开通,请提供租户ID并联系环信商务经理。

ChatClient.getInstance().chatManager().addVisitorWaitListener(new ChatManager.VisitorWaitListener() {
            @Override
            public void waitCount(final int num) {
                if (getActivity() == null){
                    return;
                }
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (num > 0){
                            tvTipWaitCount.setVisibility(View.VISIBLE);
                            tvTipWaitCount.setText(getString(R.string.current_wait_count, num));
                        }else{
                            tvTipWaitCount.setVisibility(View.GONE);
                        }
                    }
                });
            }
        });

显示坐席输入状态

首先,初始化时,需要调用options.showAgentInputState(),然后添加AgentInputListener.

注:“显示坐席输入状态”功能为增值服务,需要在移动客服系统开通该功能才能使用。如需开通,请提供租户ID并联系环信商务经理。

ChatManager.AgentInputListener agentInputListener = new ChatManager.AgentInputListener() {
        @Override
        public void onInputState(final String input) {
            if (getActivity() == null){
                return;
            }
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (input != null) {
                        titleBar.setTitle(input);
                    } else {
                        if (!TextUtils.isEmpty(titleName)) {
                            titleBar.setTitle(titleName);
                        } else {
                            titleBar.setTitle(toChatUsername);
                        }
                    }
                }
            });

        }
    };
    // 在onCreate中调用添加监听
    ChatClient.getInstance().chatManager().addAgentInputListener(agentInputListener);
    // 在onDestroy中调用移除监听    
    ChatClient.getInstance().chatManager().removeAgentInputListener(agentInputListener);