商城客服功能-------环信即时通讯

商城中基本上都添加了客服的功能,是买家和买家更方便的沟通。下面介绍的第三方即时通讯是环信。在客服这一模块中我们要做的就是,实现客服与买家之间的交流(包括发送文字,表情,图片,语音,文档,地理位置等),发送订单消息,商品信息等,实现二者之间的互动,买家给客服打分。补充就是六天纪录的删除,发送信息的时间,接接收消息的提醒等。

1、注册账号,并申请客服账号在文档里做出了详细的说明,地址:http://docs.easemob.com/cs/300visitoraccess/10nativeapp

2、创建应用,关联app,

3、下载sdk和环信的的ui框架(ui框架使用与否看自己)

4、这里为了快速展示,就使用官方提供的ui框架。把下载的sdk考入程序

5、环信的账号注册分为两种,开放注册和授权注册。我们要选择开放注册才可以让用户自由的注册账号。

6、下面就是整个程序最重要的部分了,聊天界面。

7、商品消息的发送-----绘制客户端和服务端的轨迹消息。

8、订单信息的发送,同样绘制两端的轨迹消息。

9、客服邀请用户打分

10、全局监听,想要实现消息轨迹的绘制

11、语音

进入代码开发:

1、首先创建一个单例类,用来初始化EaseUI,对EasaUI进行配置

empty

public class CustomHelper {
	private static CustomHelper customhelper;
	private String TAG = "CustomHelper";
	private Context appContext;
	private EaseUI easeUI;
	private EMConnectionListener connectionListener;
	/**
	 * EMEventListener
	 */
	protected EMEventListener eventListener = null;
	private boolean alreadyNotified = false;

	private CustomHelper() {

	}

	public synchronized static CustomHelper getInstance() {
		if (customhelper == null) {
			customhelper = new CustomHelper();
		}
		return customhelper;
	}

	public void init(Context context) {
		CustomConfigManager.init(context);

		EMChat.getInstance().setAppkey(CustomConfig.DEFALUT_APPKEY);

		// EMChat.getInstance().setAutoLogin(false);

		EaseUI.getInstance().init(context);

		if (EaseUI.getInstance().init(context)) {
			appContext = context;
			// 在小米手机上当app被kill时使用小米推送进行消息提示,SDK已支持,可选
			EMChatManager.getInstance().setMipushConfig("2882303761517370134",
					"5131737040134");
			// 设为调试模式,打成正式包时,最好设为false,以免消耗额外的资源
			// EMChat.getInstance().setDebugMode(true);
			// get easeui instance
			easeUI = EaseUI.getInstance();
			// 调用easeui的api设置providers
			setEaseUIProviders();
			// demoModel = new DemoModel(context);
			// 初始化PreferenceManager
			// PreferenceManager.init(context);
			// 设置全局监听
			setGlobalListeners();
		

		}
	}

	/**
	 * 检测是否为订单消息或者为轨迹消息
	 * 
	 * @param message
	 * @return
	 */
	public boolean isPictureTxtMessage(EMMessage message) {
		JSONObject jsonObj = null;
		try {
			jsonObj = message
					.getJSONObjectAttribute(CustomConfig.MESSAGE_ATTR_MSGTYPE);
		} catch (EaseMobException e) {
		}
		if (jsonObj == null) {
			return false;
		}
		if (jsonObj.has("order") || jsonObj.has("track")) {
			return true;
		}
		return false;
	}

	/**
	 * 检测是否为订单消息或者为轨迹消息
	 * 
	 * @param message
	 * @return
	 */
	public boolean isTRACKTxtMessage(EMMessage message) {
		JSONObject jsonObj = null;
		try {
			jsonObj = message
					.getJSONObjectAttribute(CustomConfig.MESSAGE_ATTR_MSGTYPE);
		} catch (EaseMobException e) {
		}
		if (jsonObj == null) {
			return false;
		}
		if (jsonObj.has("track")) {
			return true;
		}
		return false;
	}

	/**
	 * 检测是否为订单消息或者为轨迹消息
	 * 
	 * @param message
	 * @return
	 */
	public boolean isORDERTxtMessage(EMMessage message) {
		JSONObject jsonObj = null;
		try {
			jsonObj = message
					.getJSONObjectAttribute(CustomConfig.MESSAGE_ATTR_MSGTYPE);
		} catch (EaseMobException e) {
		}
		if (jsonObj == null) {
			return false;
		}
		if (jsonObj.has("order")) {
			return true;
		}
		return false;
	}

	// //设置头次昂
	protected void setEaseUIProviders() {
	

		// 不设置,则使用easeui默认的
		easeUI.getNotifier()
				.setNotificationInfoProvider(
						new com.easemob.easeui.model.EaseNotifier.EaseNotificationInfoProvider() {

							public String getTitle(EMMessage message) {
								// 修改标题,这里使用默认
								return null;
							}

							@Override
							public int getSmallIcon(EMMessage message) {
								// 设置小图标,这里为默认
								return 0;
							}

							// @Override
							// public String getDisplayedText(EMMessage message)
							// {
							// // 设置状态栏的消息提示,可以根据message的类型做相应提示
							// String ticker =
							// EaseCommonUtils.getMessageDigest(message,
							// appContext);
							// if (message.getType() == Type.TXT) {
							// ticker = ticker.replaceAll("\\[.{2,3}\\]",
							// "[表情]");
							// }
							// return message.getFrom() + ": " + ticker;
							// }

							// public String getLatestText(EMMessage message,
							// int fromUsersNum, int
							// messageNum) {
							// return null;
							// // return fromUsersNum + "个基友,发来了" + messageNum +
							// "条消息";
							// }
							@Override
							public String getDisplayedText(EMMessage message) {
								// 设置状态栏的消息提示,可以根据message的类型做相应提示
								String ticker = EaseCommonUtils
										.getMessageDigest(message, appContext);
								if (message.getType() == EMMessage.Type.TXT) {
									ticker = ticker.replaceAll("\\[.{2,3}\\]",
											"[表情]");
								}
								if (message.getFrom().equals(
										MLSPUtil.get(appContext,
												CustomConfig.DEFALUT_IM, ""))) {
									return "具商客服: " + ticker;
								} else {
									return message.getFrom() + ": " + ticker;
								}
							}

							/**
							 * 根据消息条数来判断如果显示
							 * 
							 * @param message
							 *            接收到的消息
							 * @param fromUsersNum
							 *            发送人的数量
							 * @param messageNum
							 *            消息数量
							 * @return
							 */
							@Override
							public String getLatestText(EMMessage message,
									int fromUsersNum, int messageNum) {
								// 当只有一个人,发来一条消息时,显示消息内容 TODO 表情符显示为图片
								if (fromUsersNum == 1 && messageNum == 1) {
									return "具商客服:"
											+ EaseCommonUtils.getMessageDigest(
													message, appContext)
													.replace("\\[.{2,3}\\]",
															"[表情]");
								} else {
									
									
									return "具商发来 " + messageNum + " 条消息";
								}
							}

							@Override
							public Intent getLaunchIntent(EMMessage message) {
								
								//联系客服
//						    	if (TextUtils.isEmpty(CustomConfigManager.getInstance().getCurrentIM())) {
						    		
						    	String	tochatUserName = CustomConfig.DEFALUT_IM;
						    	
//						    	} else {
//						    		tochatUserName = CustomConfigManager.getInstance().getCurrentIM();
//						    		
//						    	}
								// 设置点击通知栏跳转事件
								Intent intent = new Intent(appContext,
										ChatActivity.class);
								ChatType chatType = message.getChatType();
								if (chatType == ChatType.Chat) { // 单聊信息
									intent.putExtra(EaseConstant.EXTRA_USER_ID,
											message.getFrom());
									intent.putExtra(
											EaseConstant.EXTRA_CHAT_TYPE,
											Constant.CHATTYPE_SINGLE);
									// intent.putExtra(EaseConstant.EXTRA_SHOW_USERNICK,
									// true);
								}
								return intent;
							}
						});

		// 设置表情provider
		easeUI.setEmojiconInfoProvider(new EaseUI.EaseEmojiconInfoProvider() {
			@Override
			public EaseEmojicon getEmojiconInfo(String emojiconIdentityCode) {
				EaseEmojiconGroupEntity data = EmojiconExampleGroupData
						.getData();
				for (EaseEmojicon emojicon : data.getEmojiconList()) {
					if (emojicon.getIdentityCode().equals(emojiconIdentityCode)) {
						return emojicon;
					}
				}
				return null;
			}

			@Override
			public Map
   
   
    
     getTextEmojiconMapping() {
				// 返回文字表情emoji文本和图片(resource id或者本地路径)的映射map
				return null;
			}
		});

	}

	/**
	 * 判断是否为满意度调查类型的消息
	 * 
	 * @param message
	 * @return
	 */
	public boolean isCtrlTypeMessage(EMMessage message) {
		JSONObject jsonObj = null;
		try {
			jsonObj = message
					.getJSONObjectAttribute(CustomConfig.C_ATTR_KEY_WEICHAT);
			if (jsonObj.has(CustomConfig.C_ATTR_CTRLTYPE)) {
				String type = jsonObj.getString(CustomConfig.C_ATTR_CTRLTYPE);
				if (type.equalsIgnoreCase(CustomConfig.C_ATTR_INVITEENQUIRY)
						|| type.equalsIgnoreCase(CustomConfig.C_ATTR_ENQUIRY)) {
					return true;
				}
			}
		} catch (EaseMobException e) {
			e.printStackTrace();
		} catch (JSONException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 判断是否为用户轨迹类型的消息
	 * 
	 * @param message
	 * @return
	 */
	public boolean isTrackMessage(EMMessage message) {
		JSONObject jsonObj = null;
		try {
			jsonObj = message
					.getJSONObjectAttribute(CustomConfig.C_ATTR_KEY_MSGTYPE);
			if (jsonObj.has(CustomConfig.C_ATTR_TRACK)) {
				return true;
			}
		} catch (EaseMobException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 判断是否为订单消息
	 * 
	 * @param message
	 * @return
	 */
	public boolean isOrderFormMessage(EMMessage message) {
		JSONObject jsonObj = null;
		try {
			jsonObj = message
					.getJSONObjectAttribute(CustomConfig.C_ATTR_KEY_MSGTYPE);
			if (jsonObj.has(CustomConfig.C_ATTR_ORDER)) {
				return true;
			}
		} catch (EaseMobException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 设置全局事件监听
	 */
	protected void setGlobalListeners() {
		// create the global connection listener
		connectionListener = new EMConnectionListener() {
			@Override
			public void onDisconnected(int error) {
				if (error == EMError.USER_REMOVED) {
					onCurrentAccountRemoved();

				} else if (error == EMError.CONNECTION_CONFLICT) {
					onConnectionConflict();

				}
			}

			@Override
			public void onConnected() {
				// in case group and contact were already synced, we supposed to
				// notify sdk we are ready to receive the events
				CustomHelper.getInstance().notifyForRecevingEvents();
			}
		};
		// 注册连接监听
		EMChatManager.getInstance().addConnectionListener(connectionListener);
		// 注册消息事件监听
		registerEventListener();
	}

	/**
	 * 账号在别的设备登录
	 */
	protected void onConnectionConflict() {
		Intent intent = new Intent(appContext, MainFragment.class);
		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		intent.putExtra(Constant.ACCOUNT_CONFLICT, true);
		appContext.startActivity(intent);
		// popActivity(appContext);
		((Activity) appContext).finish();

	}

	/**
	 * 账号被移除
	 */
	protected void onCurrentAccountRemoved() {
		Intent intent = new Intent(appContext, MainFragment.class);
		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		intent.putExtra(Constant.ACCOUNT_REMOVED, true);
		appContext.startActivity(intent);
		((Activity) appContext).finish();

	}

	/**
	 * 全局事件监听 因为可能会有UI页面先处理到这个消息,所以一般如果UI页面已经处理,这里就不需要再次处理 activityList.size()
	 * <= 0 意味着所有页面都已经在后台运行,或者已经离开Activity Stack
	 */
	protected void registerEventListener() {
		eventListener = new EMEventListener() {
			private BroadcastReceiver broadCastReceiver = null;

			@Override
			public void onEvent(EMNotifierEvent event) {
				EMMessage message = null;
				if (event.getData() instanceof EMMessage) {
					message = (EMMessage) event.getData();
					EMLog.d(TAG, "receive the event : " + event.getEvent()
							+ ",id : " + message.getMsgId());
				}

				switch (event.getEvent()) {
				case EventNewMessage:
					// 应用在后台,不需要刷新UI,通知栏提示新消息
					if (!easeUI.hasForegroundActivies()) {
						getNotifier().onNewMsg(message);
					}
					break;
				case EventOfflineMessage:
					if (!easeUI.hasForegroundActivies()) {
						EMLog.d(TAG, "received offline messages");
						List
    
    
     
      messages = (List
     
     
      
      ) event
								.getData();
						getNotifier().onNewMesg(messages);
					}
					break;
				// below is just giving a example to show a cmd toast, the app
				// should not follow this
				// so be careful of this
				case EventNewCMDMessage: {

					EMLog.d(TAG, "收到透传消息");
					// 获取消息body
					CmdMessageBody cmdMsgBody = (CmdMessageBody) message
							.getBody();
					final String action = cmdMsgBody.action;// 获取自定义action

					// 获取扩展属性 此处省略
					// message.getStringAttribute("");
					EMLog.d(TAG, String.format("透传消息:action:%s,message:%s",
							action, message.toString()));
					final String str = appContext
							.getString(R.string.receive_the_passthrough);

					final String CMD_TOAST_BROADCAST = "easemob.demo.cmd.toast";
					IntentFilter cmdFilter = new IntentFilter(
							CMD_TOAST_BROADCAST);

					if (broadCastReceiver == null) {
						broadCastReceiver = new BroadcastReceiver() {

							@Override
							public void onReceive(Context context, Intent intent) {
								// TODO Auto-generated method stub
								Toast.makeText(appContext,
										intent.getStringExtra("cmd_value"),
										Toast.LENGTH_SHORT).show();
							}
						};

						// 注册广播接收者
						appContext.registerReceiver(broadCastReceiver,
								cmdFilter);
					}

					Intent broadcastIntent = new Intent(CMD_TOAST_BROADCAST);
					broadcastIntent.putExtra("cmd_value", str + action);
					appContext.sendBroadcast(broadcastIntent, null);

					break;
				}
				case EventDeliveryAck:
					message.setDelivered(true);
					break;
				case EventReadAck:
					message.setAcked(true);
					break;
				// add other events in case you are interested in
				default:
					break;
				}

			}
		};

		EMChatManager.getInstance().registerEventListener(eventListener);
	}

	/**
	 * 是否登录成功过
	 * 
	 * @return
	 */
	public boolean isLoggedIn() {
		return EMChat.getInstance().isLoggedIn();
	}

	/**
	 * 退出登录
	 * 
	 * @param unbindDeviceToken
	 *            是否解绑设备token(使用GCM才有)
	 * @param callback
	 *            callback
	 */
	public void logout(boolean unbindDeviceToken, final EMCallBack callback) {
		EMChatManager.getInstance().logout(unbindDeviceToken, new EMCallBack() {

			@Override
			public void onSuccess() {
				if (callback != null) {
					callback.onSuccess();
				}

			}

			@Override
			public void onProgress(int progress, String status) {
				if (callback != null) {
					callback.onProgress(progress, status);
				}
			}

			@Override
			public void onError(int code, String error) {
				if (callback != null) {
					callback.onError(code, error);
				}
			}
		});
	}

	/**
	 * 获取消息通知类
	 * 
	 * @return
	 */
	public EaseNotifier getNotifier() {
		return easeUI.getNotifier();
	}

	public synchronized void notifyForRecevingEvents() {
		if (alreadyNotified) {
			return;
		}

		// 通知sdk,UI 已经初始化完毕,注册了相应的receiver和listener, 可以接受broadcast了
		EMChat.getInstance().setAppInited();
		alreadyNotified = true;
	}

}

     
     
    
    
   
   

2、接着就要在application做一些全局工作

3、最重要的就是要实现聊天和商品信息的发送和轨迹绘制

 a、通过官方的文档,我们可以看出,发送文本信息要用

 b、商品的轨迹绘制,信息需要包括商品名称,价格,图片,链接,说明。消息展示则需要我们自己定义排版,在布局中的控件的id名称则需要和EasaUI中定义的一样,否则会出错,亲身踩坑。

empty
/**
	 * 监听事件 父类
	 */
	  @Override
	    protected void setUpView() {
	        setChatFragmentHelper(this);   
	        super.setUpView();
	    }
	    
	   
	   /**
	   轨迹消息
	   **/
	   	private void sendPictureTxtMessage() {
		// //创建一条文本消息
		EMMessage message = EMMessage.createTxtSendMessage("商品消息已经发送到客服",
				toChatUsername);
		
		TrackMessageEntity msg=new TrackMessageEntity(25, channame, chanprice, "木床", chantu,"http://114.55.99.240/Commodity_Show.aspx?id="+chanid);
		//发送json扩展
//		JSONObject jsonMsgType = MessageHelper.getMessageExtFromPicture(witchCHAT);
		JSONObject jsonMsgType=msg.getJSONObject();
	
		if (jsonMsgType != null) {
			// 给消息设置扩展
			message.setAttribute("msgtype",jsonMsgType);
			  setUserAttibutes(message);
		        setSkillGroup(message);
			sendMessage(message);
		}
	} 
	   
	   
	    /**
     * ---------------------------------------------------
     * 设置自定义消息提供者
     *
     * @return
     */
    public EaseCustomChatRowProvider onSetCustomChatRowProvider() {
        return new CustomChatRowProvider();
    }

	/**
     * 自定义实现ChatRow提供者
     */
    class CustomChatRowProvider implements EaseCustomChatRowProvider {
        /**
         * 返回自定义消息的个数(这个个数必须和你自定义的ChatRow界面个数一致,否则会数组越界)
         * FATAL EXCEPTION: main Process: com.easemob.easeui.customer, PID: 32217
         * java.lang.ArrayIndexOutOfBoundsException: length=18; index=18
         * at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:6588)
         *
         * @return
         */
        public int getCustomChatRowTypeCount() {
            return 6;
        }

        /**
         * 返回消息的类型
         *
         * @param message
         * @return
         */
        public int getCustomChatRowType(EMMessage message) {
        	Log.v("--88--", "buju ");
            if (message.getType() == EMMessage.Type.TXT) {
                if (CustomHelper.getInstance().isCtrlTypeMessage(message)) {
                    return message.direct == EMMessage.Direct.RECEIVE ? 2 : 1;
                } 
                else if (CustomHelper.getInstance().isTrackMessage(message)) {
                    return message.direct == EMMessage.Direct.RECEIVE ? 4 : 3;
                } 
            	else if (CustomHelper.getInstance().isOrderFormMessage(message)) {
                    return message.direct == EMMessage.Direct.RECEIVE ? 6 : 5;
                }
            }
            return 0;
        }

        /**
         * 返回自定义消息的实现
         *
         * @param message
         * @param position
         * @param adapter
         * @return
         */
        public EaseChatRow getCustomChatRow(EMMessage message, int position, BaseAdapter adapter) {
            if (message.getType() == EMMessage.Type.TXT) {
                if (CustomHelper.getInstance().isCtrlTypeMessage(message)) {
                    CtrlTypeChatRow ctrlTypeChatRow = new CtrlTypeChatRow(mActivity, message, position, adapter);
                    ctrlTypeChatRow.setmChatRowListener(new MyChatRowListener());
                    return ctrlTypeChatRow;
                } 
                else if (CustomHelper.getInstance().isTrackMessage(message)) {
                    return new TrackChatRow(getActivity(), message, position, adapter);
                } 
                else if (CustomHelper.getInstance().isOrderFormMessage(message)) {
//                    return new OrderChatRow(mActivity, message, position, adapter);
                }
            }
            return null;
        }
    }

	@Override
	public void onMessageBubbleLongClick(EMMessage message) {
		// TODO Auto-generated method stub
		
	}
	/**
     * ------------------------------------------------------------------
     * 

* 满意度评价的回调接口,为了实现客户端在满意度ChatRow中发送满意度类型的消息 */ class MyChatRowListener implements CtrlTypeChatRow.CustomerChatRowListener { @Override public void onChatRowInteraction(EnquiryEntity enquiryEntity) { EMMessage message = EMMessage.createTxtSendMessage("客服图文混排消息", toChatUsername); JSONObject jsonWeiChat = new JSONObject(); JSONObject jsonCtrlArgs = new JSONObject(); try { jsonCtrlArgs.put("inviteId", enquiryEntity.getInviteId()); jsonCtrlArgs.put("serviceSessionId", enquiryEntity.getServiceSessionId()); jsonCtrlArgs.put("detail", enquiryEntity.getDetail()); jsonCtrlArgs.put("summary", enquiryEntity.getSummary()); jsonWeiChat.put("ctrlType", "enquiry"); jsonWeiChat.put("ctrlArgs", jsonCtrlArgs); } catch (JSONException e) { e.printStackTrace(); } message.setAttribute(CustomConfig.C_ATTR_KEY_WEICHAT, jsonWeiChat); sendMessage(message); } }

c、判断客服消息的唯独数量:

EMConversation conversation = EMChatManager.getInstance().getConversation(CustomConfig.DEFALUT_IM);
int chatnumint=conversation.getUnreadMsgCount();

环信客服的介入看似复杂,其实并不复杂

附:1、环信客服集成的ui框架,es上使用ui   http://download.csdn.net/detail/heiya0409/9711950

2、在as上不使用官方ui,自己布局的bao   http://download.csdn.net/detail/heiya0409/9711958




  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值