====== Android 访客端demo集成(含UI库) ====== * 为了方便您快速了解我们的访客端SDK所提供的各种能力,我们对外开放了访客端集成Demo的全部源码,里面包含了对话过程中的业务处理及上层UI库; * 通过这个Demo源码,可以帮助产品人员快速了解我们的访客端功能,可以帮助研发人员快速了解集成技术逻辑,帮助测试人员通过对比demo和您自己的app,更快定位问题; * 我们的访客端Demo里提供了一整套UI,您可以直接使用这套UI,当然我们更建议您用作参考,根据您的APP风格和实际业务场景,设计您自己的一套UI和业务使用流程,减少访客在使用您app过程中所产生的割裂感; * 在SDK集成过程中,针对您遇到的问题我们建议您先对比下Demo里的处理逻辑,帮助您快速解决您遇到的问题,如果Demo仍无法解答您心中的疑惑,请直接联系我们商务或技术支持,我们会全力为您提供所需要的帮助! ==== Demo源码下载 ==== 您可以通过如下方式获取到源代码: * 下载代码压缩包:客服云sdk 及 Demo 下载 http://www.easemob.com/download/cs {{:cs:300visitoraccess:客服云-安卓端demo下载.png?nolink|}} ==== 访客端Demo使用 ==== 当您在手机上安装完访客端demo应用后,首次使用需先经过简单的扫码配置,然后就可以开始发起正常对话了,详细说明如下: {{:cs:300visitoraccess:客服云-安卓端demo下载后使用配置.png?nolink|}} ==== 访客端Demo与您自己APP的区别 ==== 访客端Demo与客户的APP以及SDK之间的关系说明如下: * 对象不同:我们的demo主要供产品、研发、测试等内部使用,便于了解功能的,您的APP是面对终端用户的; * 使用不同:我们访客端Demo是不上架应用商店,您的App是需要上架到各大应用商店提供给访客下载的; * 功能不同:我们访客端Demo仅提供的是对话的功能,您的APP里一般都是实现各种例如零售、维修、娱乐等各种功能,对话功能只是对于您的app里的一项补充能力; {{:cs:300visitoraccess:客服云-安卓端demo与sdk的区别.png?nolink|}} ==== 项目集成:详细内容参考demo ==== **app模块主体类介绍:** * LoginActivity:处理登录相关的逻辑,必须先登录环信服务器获取相关信息 * SettingFragment:通过扫码配置appkey相关信息 * CallReceiver:用于接收视频邀请相关的信令 * DemoApplication:继承Application类,需要在AndroidManifest.xml内指定 * DemoHelper:初始化相关信息配置和注册 * HMSPushHelper:配置华为HMS推送相关的工具类 **kefu-easeui模块主体类介绍:** * ChatFragment:聊天界面,app也可继承此fragment续写,参数传入示例可查看demo里的ChatActivity **VideoKit模块主体类介绍(在线视频):** * Calling:视频通话页面唤起类 * CallActivity:视频通话页面(没有赋予悬浮权限),普通效果 * VideoCallWindowService:视频通话页面(已赋予悬浮权限),画中画效果 * AgoraRtcEngine:音视频通话相关(基于声网sdk) **VECKit模块主体类介绍(VEC视频):** * VECKitCalling:视频通话页面唤起类 * CallVideoActivity:视频通话页面(没有赋予悬浮权限),普通效果 * VideoCallWindowService:视频通话页面(已赋予悬浮权限),画中画效果 * AgoraRtcEngine:音视频通话相关(基于声网sdk) ==== 初始化注意事项 ==== 在项目Application类的onCreate方法里调用如下方法: // VEC视频用到 AppStateVecCallback.init(this); // CEC视频用到 AppStateCecCallback.init(this); // UI库里用到 EaseUiStateUtils.getEaseUiStateUtils().init(this); ==== 其它注意事项 ==== 如果使用到询前引导发起视频功能,需要到Demo里拷贝GuideMenuUtils类文件到自己项目里,在对应聊天页面里调用如下方法: // 聊天页面创建时,需要注册 GuideMenuUtils.getGuideMenuUtils().registerReceiver(getContext()); // 聊天页面关闭时,需要取消注册 GuideMenuUtils.getGuideMenuUtils().unregisterReceiver(getContext()); 如果用户自己实现聊天页面,需要在打开聊天页面和关闭聊天页面时调用如下两个方法(如下两个方法目前已经集成在kefu-easeui模块ChatFragment类里面,自行修改) 进入到聊天页面时调用:开启在线上报 EaseUiReportUtils.getEaseUiReportUtils().startReport(im服务号); // ChatFragment类onStart()方法里 关闭聊天页面时调用:停止在线上报 EaseUiReportUtils.getEaseUiReportUtils().closeReport(); // ChatFragment类onDestroyView()方法里 注意:根据自己业务场景是否需要在自己聊天页面里上报,UI库里已经调用此方法,如果自己实现的聊天页面需要用户到kefu-easeui模块ChatFragment类里面注释掉上报代码,在自己聊天页面里进行调用 ==== kefu-easeui模块说明 ==== 注意:当使用到环信kefu-easeui模块时,在ChatFragment类里已经添加如下功能,不需要用户自己调用 // 自定义表情通知 ChatClient.getInstance().emojiconManager().addDelegate(this); ChatClient.getInstance().emojiconManager().removeDelegate(this); // 进入到聊天页面时调用 ChatClient.getInstance().chatManager().bindChat(toChatUsername); ChatClient.getInstance().chatManager().unbindChat(); // 添加座席端输入状态 ChatClient.getInstance().chatManager().addAgentInputListener(agentInputListener); ChatClient.getInstance().chatManager().removeAgentInputListener(agentInputListener); // 待接入时获取等待数 ChatClient.getInstance().chatManager().addVisitorWaitListener(visitorWaitListener); ChatClient.getInstance().chatManager().removeVisitorWaitListener(visitorWaitListener); // 获取机器人欢迎语,默认在ChatFragment类里requestRobotWelcome()方法里对数据进行处理刷新页面显示 ChatFragment类 requestRobotWelcome()方法,方法默认被注释掉,需要用户自行调用。如果自己调用获取机器人欢迎语接口时需要参考requestRobotWelcome()方法处理结果以及更新屏幕显示 ==== VideoKit在线音视频模块主要功能介绍 ==== 音视频(基于声网音视频服务,使用环信 IM 作为信令通道的开源音视频模块) **注册视频信令广播(demo里CallReceiver广播类)** IntentFilter callFilter = new IntentFilter(ChatClient.getInstance().callManager().getIncomingCallBroadcastAction()); callFilter.addAction("calling.state"); CallReceiver callReceiver = new CallReceiver(); // register incoming call receiver context.registerReceiver(callReceiver, callFilter); =====主动发送视频邀请:===== // 只是唤起视图页面,需要单独发送视频邀请信令 Calling.callingRequest(context(), toChatUsername); // 发送视频邀请信令 ChatClient.getInstance().callManager().callVideo(msg, toChatUsername); =====被动收到访客视频邀请信令,唤起视频页面:===== /** * V1.3.1版本之后才可以使用此方法,需要悬浮权限,授予权限将会实现悬浮效果 * 被动唤起视频页面(座席端发起会话到访客端) * @param context * @param intent */ Calling.callingResponse(Context context, Intent intent); =====相关音视频api介绍及使用如下:===== 创建视频引擎AgoraRtcEngine /** * 创建视频数据 * @param context Context * @param appId String * @param handler IAgoraRtcEngineEventHandler */ AgoraRtcEngine engine = AgoraRtcEngine.builder() .addVideoWatermark() // 该方法将一张 PNG 图片作为水印添加到本地发布的直播视频流上 .setVideoEncodingDimension() // 视频编码像素。参数使用查看SDK里方法注解 .setVideoEncoderConfiguration() // 视频编码属性的定义。参数使用查看SDK里方法注解 .setRenderMode() // 设置视频渲染模式。参数使用查看SDK里方法注解 .setMirrorMode() // 设置视频镜像模式。参数使用查看SDK里方法注解 .setClientRole() // 设置直播场景下的用户角色。参数使用查看SDK里方法注解 .setChannelProfile() // 设置频道场景。参数使用查看SDK里方法注解 .build(getApplication(), "appid", new IAgoraRtcEngineEventHandler() { @Override public void onUserJoined(int uid, int elapsed) { // 有人员加入时回调 } @Override public void onJoinChannelSuccess(String channel, int uid, int elapsed) { // 自己加入成功时回调 } @Override public void onLeaveChannel(RtcStats stats) { // 离开channel时回调 } @Override public void onUserOffline(int uid, int reason) { // 人员离开时回调 } }); /** * 创建 RendererView视图 * * 请在主线程调用该方法 * @return SurfaceView */ engine.createRendererView(); engine.createRendererView(Context context); 发送视频通话信令 /** * 发送视频通话信令 * @param chatInviteShoe msg内容 * @param toChatUsername IM服务号 */ ChatClient.getInstance().callManager().callVideo(String chatInviteShoe, String toChatUsername); 拒绝接听信令 /** * 拒绝接听信令 * @param callId callId * @param isConnected 是否已接通,false未接通 */ ChatClient.getInstance().callManager().endCall(int callId, boolean isConnected); 挂断视频信令 /** * 挂断视频 * @param callId callId * @param isConnected 是否已接通,true接通 */ ChatClient.getInstance().callManager().endCall(int callId, boolean isConnected); 音视频(基于声网音视频服务,使用环信 IM 作为信令通道的开源音视频模块)相关详细方法及参数说明参考声网api地址:https://docs.agora.io/cn/Interactive%20Broadcast/API%20Reference/java/index.html ===== VECKit 模块音视频主要方法介绍 ===== VECKit 模块(新版VEC)音视频(基于声网音视频服务,使用环信 IM 作为信令通道的开源音视频模块) **相关音视频api介绍及使用如下:** ==== 注册视频信令广播(demo里CallReceiver广播类) ==== IntentFilter callFilter = new IntentFilter(ChatClient.getInstance().callManager().getIncomingCallBroadcastAction()); callFilter.addAction("calling.state"); CallReceiver callReceiver = new CallReceiver(); // register incoming call receiver context.registerReceiver(callReceiver, callFilter); ==== 主动发送视频邀请信令同时唤起视频视图 ==== // 主动向坐席发送信令(发送信令并且唤起视频视图) VECKitCalling.callingRequest(Context context, String toChatUserName); ==== 被动接收到视频邀请信令同时唤起视图页面 ==== // 接收到坐席发来的信令(发送信令并且唤起视图) VECKitCalling.callingResponse(Context context, Intent intent); ==== 唤起满意度评价视图 ==== // 接收到坐席发来的信令,唤起满意度评价视图 VECKitCalling.callingRetry(Context context, String content); ==== 初始化相关操作 ==== /** * 注册Vec视频通知 * @param classKey 当前类名。当调用unRegisterVecMessageNotify方法释放时传入相同类名 * @param message IVecMessageNotify接口,通知回调: * zuoXiSendThreeUserRequest(ZuoXiSendRequestObj obj)当座席端邀请第三方用户加入时,回调此方法 * createFlatRoom(ZuoXiSendRequestObj obj) 创建电子白板房间时,回调此方法 */ AgoraMessage.newAgoraMessage().registerVecMessageNotify(String classKey, IVecMessageNotify message); /** * 注销通知 * @param classKey 当前类名。registerVecMessageNotify方法传入相同类名 */ AgoraMessage.newAgoraMessage().unRegisterVecMessageNotify(String classKey); // 创建引擎 AgoraRtcEngine agoraRtcEngine = AgoraRtcEngine.builder().build(Context context, String appId, IRtcEngineEventHandler handler) // 设置自己窗口视图 agoraRtcEngine.setupLocalVideo(surfaceView, AgoraRtcEngine.RENDER_MODE_HIDDEN, obj.getUid()); // 加入房间 agoraRtcEngine.joinChannel(obj.getToken(), obj.getChannel(), obj.getUid()); *注:详情参数设置参考demo ==== 主动发送视频邀请信令 ==== // 主动向坐席发送信令(只发送信令) ChatClient.getInstance().callManager().callVecVideo(String content, String toChatUsername) ==== 挂断视频信令 ==== /** * 主动发起视频邀请,坐席未接通状态。主动发送挂断信令 */ VECKitCalling.endCallFromOff(); /** * 视频已接通。发送挂断信令 * @param callBack 回调函数 */ VECKitCalling.endCallFromOn(ValueCallBack callBack); /** * 坐席发起视频邀请,访客未接通状态。访客发送挂断信令 * @param content 显示内容 */ VECKitCalling.endCallFromZuoXi(String content); ==== 发送接通视频信令(只发送信令) ==== // 发送接通视频信令(只发送信令) /** * 坐席发起视频邀请。访客发送接通信令 * @param content 显示内容 */ VECKitCalling.acceptCallFromZuoXi(String content); ==== 智能辅助相关信令 ==== // 注册接口,接收vec相关信令 AgoraMessage.newAgoraMessage().registerVecPushMessage(String classKey, IPushMessage callback); // 释放接口 AgoraMessage.newAgoraMessage().unRegisterVecPushMessage(String classKey); /** * 智能辅助(手电筒):通知坐席端开启手电筒的状态 * @param isOk 是否开启成功:true开启成功,false开启失败 * @param msg 内容(通知坐席端开启失败的原因,如果isOK指定为true,msg传入"") */ AgoraMessage.sendFlashLight(boolean isOk, String msg); /** * 智能辅助(闪光灯):通知坐席端开启光灯的状态 * @param isOk 是否开启成功:true开启成功,false开启失败 * @param msg 内容(通知坐席端开启失败的原因,如果isOK指定为true,msg传入"") */ AgoraMessage.sendCameraTorch(boolean isOk, String msg); /** * 智能辅助(聚焦):通知坐席端开启的状态 * @param msg 内容(通知坐席端聚焦失败的原因,聚焦成功msg传入"") */ AgoraMessage.sendCameraFocus(String msg); /** * 智能辅助(麦克风):通知坐席端开启的状态 * @param msg 内容(通知坐席端开启失败的原因,麦克风开启成功msg传入"") */ AgoraMessage.sendMicrophone(String msg); /** * 智能辅助(相机):通知坐席端开启的状态 * @param msg 内容(通知坐席端开启失败的原因,相机开启成功msg传入"") */ AgoraMessage.sendCamera(String msg); /** * 智能辅助(切换相机):通知坐席端切换的状态 * @param msg 内容(通知坐席端切换相机失败的原因,切换相机成功msg传入"") */ AgoraMessage.sendChangeCamera(String msg); 详情使用请参考demo 音视频(基于声网音视频服务,使用环信 IM 作为信令通道的开源音视频模块)相关详细方法及参数说明参考声网api地址:https://docs.agora.io/cn/Interactive%20Broadcast/API%20Reference/java/index.html