環(huán)信官方Demo源碼分析及SDK簡(jiǎn)單應(yīng)用-IM集成開發(fā)詳案及具體代碼實(shí)現(xiàn)

環(huán)信官方Demo源碼分析及SDK簡(jiǎn)單應(yīng)用

環(huán)信官方Demo源碼分析及SDK簡(jiǎn)單應(yīng)用-ChatDemoUI3.0

環(huán)信官方Demo源碼分析及SDK簡(jiǎn)單應(yīng)用-LoginActivity

環(huán)信官方Demo源碼分析及SDK簡(jiǎn)單應(yīng)用-主界面的三個(gè)fragment-會(huì)話界面

環(huán)信官方Demo源碼分析及SDK簡(jiǎn)單應(yīng)用-主界面的三個(gè)fragment-通訊錄界面

環(huán)信官方Demo源碼分析及SDK簡(jiǎn)單應(yīng)用-主界面的三個(gè)fragment-設(shè)置界面

環(huán)信官方Demo源碼分析及SDK簡(jiǎn)單應(yīng)用-EaseUI

環(huán)信官方Demo源碼分析及SDK簡(jiǎn)單應(yīng)用-IM集成開發(fā)詳案及具體代碼實(shí)現(xiàn)

前言

手頭工作上,正好需要在已有的兩個(gè)App上集成IM功能。且迭代流程中是有開發(fā)詳案這一項(xiàng)的。就分享給大家,邊寫開發(fā)詳案邊寫代碼。好吧,廢話不多說,我們一起來學(xué)習(xí)如何集成和改造這款簡(jiǎn)單易用而又非常強(qiáng)大的環(huán)信SDK。

具體步驟

迭代點(diǎn)

需要做的功能點(diǎn)及工作

1.集成環(huán)信

2.圍繞UE和UI進(jìn)行編碼

房源詳情增加咨詢按鈕,點(diǎn)擊進(jìn)入咨詢對(duì)話框,并且將房源信息帶入對(duì)話框。

消息中心

主界面TABBAR點(diǎn)擊消息進(jìn)入該界面

包含系統(tǒng)消息入庫(kù)和咨詢用戶列表

從TABBAR點(diǎn)擊“消息”圖標(biāo)進(jìn)入本頁(yè)面后,可以在本頁(yè)面進(jìn)入”系統(tǒng)消息“,并且將咨詢過的用戶會(huì)話顯示在本頁(yè),長(zhǎng)按任意一條會(huì)話,提示刪除當(dāng)前會(huì)話確定。

列表排序:“系統(tǒng)通知“仍然在最上面的位置,不受排序影響

咨詢排序:按最后聊天時(shí)間倒序排列,咨詢列表默認(rèn)顯示20條,多了拖動(dòng)加載分頁(yè)數(shù)據(jù)。

無咨詢用戶時(shí),只顯示”系統(tǒng)通知“入口即可。

咨詢列表:長(zhǎng)按可刪除當(dāng)前聊天對(duì)象,需要有確認(rèn)對(duì)話框(只刪除會(huì)話,不刪除聊天記錄)

根據(jù)UE和UI改造聊天窗口(EaseUI庫(kù))

注意以下幾點(diǎn)

從房源詳情頁(yè)進(jìn)入時(shí),就返回房源詳情頁(yè),從消息中心進(jìn)入時(shí),就返回消息中心。

顯示當(dāng)前咨詢?nèi)说慕?jīng)紀(jì)人姓名,并顯示當(dāng)前咨詢的對(duì)象的在線狀態(tài)(在線/離線)

標(biāo)題頭中的電話按鈕可以直接撥打電話

對(duì)于從房源詳情進(jìn)入時(shí)帶入的房源詳情類型的聊天條目,經(jīng)紀(jì)人可以點(diǎn)擊查看該房源在STM中的詳情。

顯示經(jīng)紀(jì)人照片上傳的照片,如果經(jīng)紀(jì)人沒有上傳照片,就顯示一個(gè)經(jīng)紀(jì)人的占位圖(要區(qū)別于用戶的占位圖)

當(dāng)前用戶頭像默認(rèn)顯示當(dāng)前用戶的頭像,如果沒有頭像,就顯示一個(gè)默認(rèn)的占位圖

聊天內(nèi)容上長(zhǎng)按可復(fù)制

發(fā)送的是手機(jī)號(hào)碼時(shí)可以直接打電話。

思路

先做加法,再做減法

我們來按照原有代碼改造和設(shè)計(jì)環(huán)信SDK部分相關(guān)代碼改造,兩個(gè)部分來做工作。將具體的功能點(diǎn)拆分并給出實(shí)現(xiàn)。

我們?cè)贒emo上修改,修改完成后剔除無關(guān)代碼抽取成獨(dú)立的我們需要的相關(guān)代碼。整個(gè)工作也就結(jié)束了。

通過之前的代碼閱讀,我們知道整個(gè)Demo是一個(gè)相對(duì)完整的App,而我們實(shí)際工作中集成個(gè)im基本出不了這個(gè)范圍。

就好比這次迭代也是。

因?yàn)閷?shí)際整個(gè)涉及的只有會(huì)話列表和聊天界面,我們主要關(guān)注ConversationListFragmentChatActivity就行了。

實(shí)現(xiàn)

SeeHouse相關(guān)改造

原有代碼改造

房源詳情增加咨詢按鈕,點(diǎn)擊進(jìn)入咨詢對(duì)話框,并且將房源信息帶入對(duì)話框。

主界面TABBAR點(diǎn)擊消息進(jìn)入該界面

涉及環(huán)信SDK部分相關(guān)代碼改造

包含系統(tǒng)消息入庫(kù)和咨詢用戶列表

同列表,不同type類型區(qū)分,并置頂系統(tǒng)消息

從TABBAR點(diǎn)擊“消息”圖標(biāo)進(jìn)入本頁(yè)面后,可以在本頁(yè)面進(jìn)入”系統(tǒng)消息“,并且將咨詢過的用戶會(huì)話顯示在本頁(yè),長(zhǎng)按任意一條會(huì)話,提示刪除當(dāng)前會(huì)話確定。

直接貼過去,Demo已經(jīng)實(shí)現(xiàn)。

列表排序:“系統(tǒng)通知“仍然在最上面的位置,不受排序影響根據(jù)Type來判斷類型,并排序置頂。

咨詢排序:按最后聊天時(shí)間倒序排列,咨詢列表默認(rèn)顯示20條,多了拖動(dòng)加載分頁(yè)數(shù)據(jù)。sort算法改一下,看下本身是否帶分頁(yè)。

無咨詢用戶時(shí),只顯示”系統(tǒng)通知“入口即可。

無需實(shí)現(xiàn)。

咨詢列表:長(zhǎng)按可刪除當(dāng)前聊天對(duì)象,需要有確認(rèn)對(duì)話框(只刪除會(huì)話,不刪除聊天記錄)

環(huán)信的哥哥們已經(jīng)幫我們實(shí)現(xiàn)了。但是根據(jù)要求呢,我沒只需要?jiǎng)h除會(huì)話,所以我們把第二項(xiàng)注釋掉。

我們把對(duì)應(yīng)處的判斷代碼和對(duì)應(yīng)的menu文件em_delete_message中的標(biāo)簽給注釋掉??葱Ч?。

從房源詳情頁(yè)進(jìn)入時(shí),就返回房源詳情頁(yè),從消息中心進(jìn)入時(shí),就返回消息中心。?

直接finish();

顯示當(dāng)前咨詢?nèi)说慕?jīng)紀(jì)人姓名,并顯示當(dāng)前咨詢的對(duì)象的在線狀態(tài)(在線/離線)官方的EaseUi是這么說的

我們來找下EaseTitleBar

我們來看下他的布局

http://schemas.android.com/apk/res/android"android:id="@+id/root"? ? android:layout_width="match_parent"? ? android:layout_height="@dimen/height_top_bar"? ? android:background="@color/top_bar_normal_bg"? ? android:gravity="center_vertical" >?? ? ?? ? ? ? ? ? ?? ? ?? ? ?? ? ? ? ? ? ?

其實(shí)有title和rightview的。

我們來對(duì)title加入一個(gè)是否在線的狀態(tài)

1.獲取token

MacBook:~ mli$ curl -X POST "https://a1.easemob.com/1177170 ... ot%3B-d '{"grant_type":"client_credentials","client_id":"YXA6vcNInEeatzGVyK0tA","client_secret":"YXA6YACo7qumFfgYdWher3D3Cs"}'

{"access_token":"YWMtOT73nvcIEeaPCCuTQsCAAAVuOB_MQchxsIsxVJFXsW6lZ8f2l__xn8","expires_in":5168429,"application":"bd09c370-d227-11e6-adcc-65700322b4b4"}

2.拿token獲取用戶狀態(tài)

MacBook:~ mli$ curl -X GET -i -H "Authorization: Bearer YWMtOT73nvcIEeaPCCuTQsC6kwAAAVuOB_MQchxsIsxybVJFXsW6lZ8f2l__xn8" "https://a1.easemob.com/1177170 ... ot%3BHTTP/1.1 200 OKServer: Tengine/2.0.3Date: Mon, 20 Feb 2017 05:24:00 GMTContent-Type: application/json;charset=UTF-8Transfer-Encoding: chunkedConnection: keep-aliveAccess-Control-Allow-Origin: *Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Sun, 19-Feb-2017 05:24:00 GMT{? "action" : "get",? "uri" : "http://a1.easemob.com/11771701 ... ot%3B,? "entities" :[],? "data" : {? ? "2" : "offline"? },? "timestamp" : 1487568240699,? "duration" : 25,? "count" : 0}MacBook:~ mli$ curl -X GET -i -H "Authorization: Bearer YWMtOT73nvcIEeaPCCuCkwAAAVuOB_MQchxsIJFXsW6lZ8f2l__xn8" "https://a1.easemob.com/1177170 ... ot%3BHTTP/1.1 200 OKServer: Tengine/2.0.3Date: Mon, 20 Feb 2017 05:24:08 GMTContent-Type: application/json;charset=UTF-8Transfer-Encoding: chunkedConnection: keep-aliveAccess-Control-Allow-Origin: *Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Sun, 19-Feb-2017 05:24:08 GMT{? "action" : "get",? "uri" : "http://a1.easemob.com/11771701 ... ot%3B,? "entities" :[],? "data" : {? ? "1" : "online"? },? "timestamp" : 1487568248135,? "duration" : 14,? "count" : 0MacBook:~ mli$

我們可以看到2是離線,1是在線的。

注意一點(diǎn)

所以昵稱是在咱自己的體系的。可以從現(xiàn)有的App里提取,如果有的話。

我們知道從列表ConversationListFragment->ChatActivity->ChatFragment

那么如何接受和發(fā)送自己與他人的頭像和昵稱呢?

我們來玩這個(gè)ChatFragment

在OnSetMessageAttributes中,設(shè)置我們要發(fā)送時(shí)的消息擴(kuò)展屬性。

那么接收怎么辦呢,我們來看下DemoHelper中的getUserInfo()方法。

無聊的用鄙人蹩腳的英文寫了一把注釋。英文若是寫的不對(duì)就不對(duì)吧。

標(biāo)題頭中的電話按鈕可以直接撥打電話

修改刪除按鈕為打電話,并改動(dòng)相關(guān)代碼

顯示經(jīng)紀(jì)人照片上傳的照片,如果經(jīng)紀(jì)人沒有上傳照片,就顯示一個(gè)經(jīng)紀(jì)人的占位圖(要區(qū)別于用戶的占位圖)

修改原demo

當(dāng)前用戶頭像默認(rèn)顯示當(dāng)前用戶的頭像,如果沒有頭像,就顯示一個(gè)默認(rèn)的占位圖

修改原demo。

聊天內(nèi)容上長(zhǎng)按可復(fù)制

自帶了,后面我們可能需要去掉轉(zhuǎn)發(fā)。

發(fā)送的是手機(jī)號(hào)碼時(shí)可以直接打電話。

我們?cè)匍L(zhǎng)按后判斷其是否為電話號(hào)碼,如果是添加一項(xiàng)撥打電話。

引用關(guān)系是這樣的

ChatFragment->ContextMenuActivity->em_context_menu_for_location.xml

最后調(diào)回ChatFragment的onActivityResult

我們來改em_context_menu_for_location.xml

http://schemas.android.com/apk/res/android"android:layout_width="match_parent"? ? android:layout_height="wrap_content"? ? android:layout_marginLeft="20dp"? ? android:layout_marginRight="20dp"? ? android:gravity="center_horizontal"? ? android:orientation="vertical" >?? ? ?? ? ?? ? ?? -->? ? ? ?

再來改ContextMenuActivity

/** * Copyright (C) 2016 Hyphenate Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *http://www.apache.org/licenses/LICENSE-2.0* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.hyphenate.chatuidemo.ui;?import android.content.Intent;import android.os.Bundle;import android.text.TextUtils;import android.view.MotionEvent;import android.view.View;import android.widget.TextView;?import com.easemob.redpacketsdk.constant.RPConstant;import com.hyphenate.chat.EMMessage;import com.hyphenate.chatuidemo.Constant;import com.hyphenate.chatuidemo.R;?public class ContextMenuActivity extends BaseActivity {? ? public static final int RESULT_CODE_COPY = 1;? ? public static final int RESULT_CODE_DELETE = 2;? ? public static final int RESULT_CODE_FORWARD = 3;? ? public static final int RESUTL_CALL_PHONE = 4;? ? String phoneNumber;? ? @Override? ? protected void onCreate(Bundle savedInstanceState) {? ? ? ? super.onCreate(savedInstanceState);? ? ? ? EMMessage message = getIntent().getParcelableExtra("message");? ? ? ? boolean isChatroom = getIntent().getBooleanExtra("ischatroom", false);? ? ? ? phoneNumber = getIntent().getStringExtra("phone_number");? ? ? ? ? ? ? ? int type = message.getType().ordinal();? ? ? ? if (type == EMMessage.Type.TXT.ordinal()) {? ? ? ? ? ? if(message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_VIDEO_CALL, false)? ? ? ? ? ? ? ? ? ? || message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_VOICE_CALL, false)? ? ? ? ? ? ? ? ? ? //red packet code : 屏蔽紅包消息、轉(zhuǎn)賬消息的轉(zhuǎn)發(fā)功能? ? ? ? ? ? ? ? ? ? || message.getBooleanAttribute(RPConstant.MESSAGE_ATTR_IS_RED_PACKET_MESSAGE, false)? ? ? ? ? ? ? ? ? ? || message.getBooleanAttribute(RPConstant.MESSAGE_ATTR_IS_TRANSFER_PACKET_MESSAGE, false)){? ? ? ? ? ? ? ? ? ? //end of red packet code? ? ? ? ? ? ? ? setContentView(R.layout.em_context_menu_for_location);? ? ? ? ? ? }else if(message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_BIG_EXPRESSION, false)){? ? ? ? ? ? ? ? setContentView(R.layout.em_context_menu_for_image);? ? ? ? ? ? }else{? ? ? ? ? ? ? ? //for text content? ? ? ? ? ? ? ? setContentView(R.layout.em_context_menu_for_text);? ? ? ? ? ? ? ? //for call phone number? ? ? ? ? ? ? ? TextView callPhone = (TextView) findViewById(R.id.call_phone);? ? ? ? ? ? ? ? if(!TextUtils.isEmpty(phoneNumber)){? ? ? ? ? ? ? ? ? ? callPhone.setVisibility(View.VISIBLE);? ? ? ? ? ? ? ? ? ? callPhone.setText("撥打電話:" + phoneNumber);? ? ? ? ? ? ? ? }else{? ? ? ? ? ? ? ? ? ? callPhone.setVisibility(View.GONE);? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? } else if (type == EMMessage.Type.LOCATION.ordinal()) {? ? ? ? ? ? setContentView(R.layout.em_context_menu_for_location);? ? ? ? } else if (type == EMMessage.Type.IMAGE.ordinal()) {? ? ? ? ? ? setContentView(R.layout.em_context_menu_for_image);? ? ? ? } else if (type == EMMessage.Type.VOICE.ordinal()) {? ? ? ? ? ? setContentView(R.layout.em_context_menu_for_voice);? ? ? ? } else if (type == EMMessage.Type.VIDEO.ordinal()) {? ? ? ? ? ? setContentView(R.layout.em_context_menu_for_video);? ? ? ? } else if (type == EMMessage.Type.FILE.ordinal()) {? ? ? ? ? ? setContentView(R.layout.em_context_menu_for_location);? ? ? ? }? ? ? ? if (isChatroom? ? ? ? ? ? ? ? //red packet code : 屏蔽紅包消息、轉(zhuǎn)賬消息的撤回功能? ? ? ? ? ? ? ? || message.getBooleanAttribute(RPConstant.MESSAGE_ATTR_IS_RED_PACKET_MESSAGE, false)? ? ? ? ? ? ? ? || message.getBooleanAttribute(RPConstant.MESSAGE_ATTR_IS_TRANSFER_PACKET_MESSAGE, false)) {? ? ? ? ? ? ? ? //end of red packet code? ? ? ? ? ? View v = (View) findViewById(R.id.forward);? ? ? ? ? ? if (v != null) {? ? ? ? ? ? ? ? v.setVisibility(View.GONE);? ? ? ? ? ? }? ? ? ? }? ? }?? ? @Override? ? public boolean onTouchEvent(MotionEvent event) {? ? ? ? finish();? ? ? ? return true;? ? }?? ? public void copy(View view){? ? ? ? setResult(RESULT_CODE_COPY);? ? ? ? finish();? ? }? ? public void delete(View view){? ? ? ? setResult(RESULT_CODE_DELETE);? ? ? ? finish();? ? }? ? public void forward(View view){? ? ? ? setResult(RESULT_CODE_FORWARD);? ? ? ? finish();? ? }?? ? public void call(View view) {? ? ? ? Intent it = new Intent();? ? ? ? it.putExtra("phone_number",phoneNumber);? ? ? ? setResult(RESUTL_CALL_PHONE,it);? ? ? ? finish();? ? }}

再來判斷內(nèi)容是否為電話號(hào)碼

String phoneNumber="";

if(isPhoneNumber(content)){

phoneNumber = content;

}

// no message forward when in chat room

startActivityForResult((new Intent(getActivity(), ContextMenuActivity.class)).putExtra("message",message)

//if message's context is a phone number ,make it can be call it.

.putExtra("ischatroom", chatType == EaseConstant.CHATTYPE_CHATROOM).putExtra("phone_number",phoneNumber),

REQUEST_CODE_CONTEXT_MENU);

onActivityResult部分

public void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (requestCode == REQUEST_CODE_CONTEXT_MENU) {

//for Context MenuActivity Result

switch (resultCode) {

case ContextMenuActivity.RESULT_CODE_COPY: // copy

clipboard.setPrimaryClip(ClipData.newPlainText(null,

((EMTextMessageBody) contextMenuMessage.getBody()).getMessage()));

break;

case ContextMenuActivity.RESULT_CODE_DELETE: // delete

conversation.removeMessage(contextMenuMessage.getMsgId());

messageList.refresh();

break;

?

?

//? ? ? ? ? ? case ContextMenuActivity.RESULT_CODE_FORWARD: // forward

//? ? ? ? ? ? ? ? Intent intent = new Intent(getActivity(), ForwardMessageActivity.class);

//? ? ? ? ? ? ? ? intent.putExtra("forward_msg_id", contextMenuMessage.getMsgId());

//? ? ? ? ? ? ? ? startActivity(intent);

//

//? ? ? ? ? ? ? ? break;

?

case ContextMenuActivity.RESUTL_CALL_PHONE:

Intent intent = new Intent(Intent.ACTION_DIAL);

Uri callData = Uri.parse("tel:" +data.getStringExtra("phone_number"));

intent.setData(callData);

startActivity(intent);

break;

?

default:

break;

}

}

記住先提取字符串中的數(shù)字,再去匹配正則。

STM集成

在本質(zhì)上是相同的。不同的是一個(gè)是用戶端,一個(gè)是經(jīng)紀(jì)人端

標(biāo)注下需要注意的幾個(gè)地方

頭像和昵稱的擴(kuò)展互通,是SeeHouse和STM兩邊都需要做的。

因?yàn)橛幸粭l對(duì)于從房源詳情進(jìn)入時(shí)帶入的房源詳情類型的聊天條目,經(jīng)紀(jì)人可以點(diǎn)擊查看該房源在STM中的詳情。是在STM中單獨(dú)實(shí)現(xiàn)的。SeeHouse負(fù)責(zé)帶入,STM負(fù)責(zé)點(diǎn)擊跳轉(zhuǎn)。

對(duì)于從房源詳情進(jìn)入時(shí)帶入的房源詳情類型的聊天條目,經(jīng)紀(jì)人可以點(diǎn)擊查看該房源在STM中的詳情。

創(chuàng)建圖文chatrow并設(shè)置對(duì)應(yīng)點(diǎn)擊事件代碼。

集成至目標(biāo)App

不需要的代碼,我們只做注釋,不刪除,防止后面增加了,需要了。避免一系列麻煩。

?剔除紅包庫(kù)?

在ChatUIDemo3.0的build.gradle中注釋編譯紅包依賴庫(kù)。

各種編譯,遇到報(bào)錯(cuò)就刪除相關(guān)代碼

剔除不需要的代碼

注意EaseUI下有個(gè)SimpleDemo

目標(biāo)App集成與調(diào)試

因?yàn)槭枪镜纳虡I(yè)項(xiàng)目,這里就不貼出來了。接著完成需調(diào)試才能完成的功能點(diǎn)

總結(jié)

好了,至此,我們開發(fā)詳案寫完了,代碼也寫完了。因?yàn)楸疚膶懙臅r(shí)候UI還未出,所以后面就是根據(jù)UI改改的調(diào)整調(diào)整界面的小事情了。

有任何問題或者其他事宜請(qǐng)聯(lián)系我:5108168@qq.com,歡迎指正和勘誤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容