android-使用環信SDK開發即時通信功能及源代碼下載
近期項目中集成即時聊天功能。挑來揀去,終於選擇環信SDK來進行開發,選擇環信的主要原因是接口方便、簡潔。說明文檔清楚易懂。文檔有android、ios、和後臺server端。還是非常全的。
環信官網:http://www.easemob.com/
本篇文章目的主要在於說明環信Demo怎樣實現即時通信的。我在集成環信SDK到我們自己開發的app之前,研究了一下環信demo的代碼。看了兩三天的樣子,基本搞清楚來龍去脈,可是僅僅是清楚來龍去脈。要說到裏面的細節可能得深一步研究,可是這就夠了,已經能夠把demo裏面的功能集成到我們自己的app中了。
所以本篇文章就說明一下怎樣集成環信到自己的app中。
集成起來還是比較快的。最多一周時間集成就搞定了。我們是有自己的用戶體系的。所以我們採用的是將環信與現有的APP用戶體系集成。
集成之前。必定要到上面這個頁面進行了解,怎樣集成。在這裏說明了怎樣集成的方案。這個方法的選擇就須要你自己依據已有的需求進行選擇了。這個就不多說了。應該都明確。
登 錄 原 理
我們的方案是將環信與現有的APP用戶體系集成!
也就是說我們的server須要把現有的用戶在後臺註冊到環信server中,然後app登錄的時候自己主動登錄環信server,然後使用環信的即時通信功能。
這就意味著用戶登錄app的時候,須要登錄兩次,一次是我們的應用server。一次是環信server,僅僅只是給用戶的感覺是登錄了一次,而環信server的登錄是代碼中控制的。用戶看不到也感覺不到。
好友體系原理
登錄之後,就是獲取好友和群組了。環信添加了聊天室的功能,有點相似於松群組的功能。僅僅只是聊天室更加任意些。群組大家都明確,不多說,聊天室呢不同,開放的公共的聊天室。成員能夠隨時進入聊天隨時離開。離開之後自己主動不再收到聊天信息。
好友體系中環信是能夠進行管理的,當然也能夠不使用環信的好友管理體系,而使用應用server來進行好友的管理工作。我們項目中使用的是環信的好友管理體系。主要是方便,只是也不見得省了多少事兒,由於應用server用戶體系的變更,都要由server把該用戶體系的關系的變更通知環信server,然環信server也進行更改,從而保持應用server和環信server用戶體系的一致性。所以大家集成過程中須要自己考慮代價。我們項目中使用環信管理好友體系主要在於app端方便,app端也不進行用戶體系的變更,復雜的操作都在server端實現。所以app端方便實現、開發簡單。
用戶昵稱、頭像
環信server採用了低浸入的方式開發即時通信,也就是說它不保存用戶的信息。也不訪問用戶的信息。這就意味著用戶的昵稱、頭像等等信息環信是沒有保存的。開發人員無法通過環信獲取用戶信息。所以環信專門對與用戶的昵稱、頭像信息給出了解決方式。
方法一 從APPserver獲取昵稱和頭像
方法二 從消息擴展中獲取昵稱和頭像
昵稱或頭像處理的方法一和方法二差別:
方法一:在發送消息時不含有不論什麽擴展,收消息時假設本地不存在發送人的用戶信息則須要從APPserver查詢發送人的昵稱和頭像的URL。
方法二:在發送消息時帶有包括昵稱和頭像URL的消息擴展,收到消息時就可以從消息擴展中取出,不須要再去APPserver獲取。 方法二和方法一相比
長處:收到消息馬上顯示昵稱不用等待APPserver返回數據後顯示。
缺點:每條消息都要帶有擴展,添加消息體積,每次發消息都有一些不必要的數據。
上面是環信給出的用戶昵稱和頭像的兩種解決方式。
這兩種解決方式大家一看就應用明確了,不多說。主要說說我們項目中的解決方式,採用第一種方案。從應用server獲取。保存本地數據庫。之後,查詢操作就是本地操作。那就會有問題了。用戶關系更新或者信息更新呢?這個問題主要解決方法是用戶好友體系的每次更新都會同一時候更新用戶昵稱和頭像,然後更新本地數據庫來解決問題。
到此,這三個問題明確之後,基本就能夠開始進行開發了,你可能會說。還沒有說明即時通信呢?最基本的就是即時通信怎麽沒有說明呢?這個問題大家勿急,後面會有!
^_^
開 發
開發過程。首先就是要研究一下環信demo的代碼,裏面已經進行了封裝。所以把環信demo的代碼看懂,利用的好的代碼全然能夠應用到現有的app中。
這個環信demo的代碼,導入手機直接執行。註冊,用著非常好,代碼執行正常,功能也正常。所以研究這個代碼之後,再集成到自己的app中那就so easy!!
demo裏面用到了幾個jar包,主要是環信的sdk、百度地圖、友盟數據分析、百度地圖定位、圖片載入等這幾個jar包,百度地圖這個應該沒什麽說的,之前我們app裏面集成過,只是有點舊,這次順帶著把百度地圖也更新成最新的了。眼下百度地圖最新的挺好用的。也算是教訓,就是實時更新所應用的第三方的jar!別的jar就沒什麽說的了。
以下就是demo裏面的分包了。demo裏面的分包比較多,只是從分包的名字能夠看出每一個包以下的代碼是什麽作用了。我主要看的是activity包以下的每一個類,由於activity類就是一個個的界面,其它的都是為這個activity類服務的代碼工具類。所以主要看這個就能夠了。
activity包以下的類比較多,只是我們關心的類僅僅有幾個而已。ChatActivity.java類就是即時聊天的界面。這個一定是要集成到自己的app其中的。
其它的三個ContactlistFragment.java、ChatAllHistoryFragment.java、GroupsActivity.java這三個類各自是聯系人界面、回話歷史界面、群組界面。這三個須要依據自己app的需求進行集成。
所以主要研究的工作就是放在這幾個類上。
MainActivity.java就是主界面。主界面集成了上面三個界面,由主界面進行管理界面的顯示。
剩下的工作沒什麽特別的了。搞不明確代碼的能夠給我留言,相互交流一下。
特別提一下以下的幾個類
這個幾個類有點繞。剛開始著實弄混了。
如今看來demo裏面代碼也是用心良苦呀!!
1、先看controller包以下的HXSDKHelper.java類,再看chatuidemo包以下的DemoHXSDKHelper.java類。明顯是繼承關系。後者才是demo中使用的對象類。
而且該父類在controller包下。明顯是控制信息管理類,打開該類查看代碼
從說明能夠看出該類的作用了。
2、再看HXSDKModel.java類。這類名字就是模版類。還有DefaultHXSDKModel.java類和DemoSDKModel.java類。也非常明顯存在繼承關系。
完畢的功能主要是app其中即時通信的一些數據的保存和控制信息顯示信息等。
這幾個類搞清楚之後基本就沒有什麽打的問題了。
主要代碼解說
1、主類MainActivity.java
public class MainActivity extends BaseActivity implements EMEventListener
該類實現了EMEventListener 接口,就一個方法例如以下:
/**
* 監聽事件
*/
@Override
public void onEvent(EMNotifierEvent event) {
switch (event.getEvent()) {
case EventNewMessage: // 普通消息
{
EMMessage message = (EMMessage) event.getData();
// 提示新消息
HXSDKHelper.getInstance().getNotifier().onNewMsg(message);
refreshUI();
break;
}
case EventOfflineMessage: {
refreshUI();
break;
}
case EventConversationListChanged: {
refreshUI();
break;
}
default:
break;
}
}
主要就是監聽新消息、離線消息、回話消息變化等。然後更新界面refreshUI(),更新界面就是刷新未讀消息數、刷新聯系人列表。回話列表等。
在主界面初始化中註冊了三個監聽器,例如以下代碼:
private void init() {
// setContactListener監聽聯系人的變化等
EMContactManager.getInstance().setContactListener(new MyContactListener());
// 註冊一個監聽連接狀態的listener
connectionListener = new MyConnectionListener();
EMChatManager.getInstance().addConnectionListener(connectionListener);
groupChangeListener = new MyGroupChangeListener();
// 註冊群聊相關的listener
}
這三個監聽器就是監聽聯系人變化、群組變化、與環信server鏈接變化的監聽器,這三者的變化都會回調這三個監聽器裏面的對應的方法,方便開發人員通過對應的方法採取對應的措施。
這三個監聽器demo中代碼比較具體,在此就不多說了。
2 聯系人列表ContactlistFragment.java類
/**
* 聯系人列表頁
*/
public class ContactlistFragment extends Fragment {
public static final String TAG = "ContactlistFragment";
private ContactAdapter adapter;
private List<User> contactList;
private ListView listView;
private boolean hidden;
private Sidebar sidebar;
private InputMethodManager inputMethodManager;
private List<String> blackList;
ImageButton clearSearch;
EditText query;
HXContactSyncListener contactSyncListener;
HXBlackListSyncListener blackListSyncListener;
View progressBar;
Handler handler = new Handler();
private User toBeProcessUser;
private String toBeProcessUsername;
/**
* 這裏註冊了兩個監聽器,目的在於同步聯系人信息
* 當聯系人發生變化、黑名單發生變化。通知這裏註冊的監聽器
* 進而刷新界面
*
*/
class HXContactSyncListener implements HXSDKHelper.HXSyncListener {
@Override
public void onSyncSucess(final boolean success) {
EMLog.d(TAG, "on contact list sync success:" + success);
ContactlistFragment.this.getActivity().runOnUiThread(new Runnable() {
public void run() {
getActivity().runOnUiThread(new Runnable(){
@Override
public void run() {
if(success){
progressBar.setVisibility(View.GONE);
refresh();
}else{
String s1 = getResources().getString(R.string.get_failed_please_check);
Toast.makeText(getActivity(), s1, 1).show();
progressBar.setVisibility(View.GONE);
}
}
});
}
});
}
}
class HXBlackListSyncListener implements HXSyncListener{
@Override
public void onSyncSucess(boolean success) {
getActivity().runOnUiThread(new Runnable(){
@Override
public void run() {
blackList = EMContactManager.getInstance().getBlackListUsernames();
refresh();
}
});
}
};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_contact_list, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//防止被T後,沒點確定button然後按了home鍵,長期在後臺又進app導致的crash
if(savedInstanceState != null && savedInstanceState.getBoolean("isConflict", false))
return;
inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
listView = (ListView) getView().findViewById(R.id.list);
sidebar = (Sidebar) getView().findViewById(R.id.sidebar);
sidebar.setListView(listView);
//黑名單列表
blackList = EMContactManager.getInstance().getBlackListUsernames();
contactList = new ArrayList<User>();
// 獲取設置contactlist
getContactList();
//搜索框
query = (EditText) getView().findViewById(R.id.query);
query.setHint(R.string.search);
clearSearch = (ImageButton) getView().findViewById(R.id.search_clear);
query.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
adapter.getFilter().filter(s);
if (s.length() > 0) {
clearSearch.setVisibility(View.VISIBLE);
} else {
clearSearch.setVisibility(View.INVISIBLE);
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void afterTextChanged(Editable s) {
}
});
clearSearch.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
query.getText().clear();
hideSoftKeyboard();
}
});
// 設置adapter
adapter = new ContactAdapter(getActivity(), R.layout.row_contact, contactList);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String username = adapter.getItem(position).getUsername();
if (Constant.NEW_FRIENDS_USERNAME.equals(username)) {
// 進入申請與通知頁面
User user = DemoApplication.getInstance().getContactList().get(Constant.NEW_FRIENDS_USERNAME);
user.setUnreadMsgCount(0);
startActivity(new Intent(getActivity(), NewFriendsMsgActivity.class));
} else if (Constant.GROUP_USERNAME.equals(username)) {
// 進入群聊列表頁面
startActivity(new Intent(getActivity(), GroupsActivity.class));
} else if(Constant.CHAT_ROOM.equals(username)){
//進入聊天室列表頁面
startActivity(new Intent(getActivity(), PublicChatRoomsActivity.class));
}else {
// demo中直接進入聊天頁面,實際通常是進入用戶詳情頁
startActivity(new Intent(getActivity(), ChatActivity.class).putExtra("userId", adapter.getItem(position).getUsername()));
}
}
});
listView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// 隱藏軟鍵盤
if (getActivity().getWindow().getAttributes().softInputMode
!= WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
if (getActivity().getCurrentFocus() != null)
inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
}
return false;
}
});
ImageView addContactView = (ImageView) getView().findViewById(R.id.iv_new_contact);
// 進入加入好友頁
addContactView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(getActivity(), AddContactActivity.class));
}
});
registerForContextMenu(listView);
progressBar = (View) getView().findViewById(R.id.progress_bar);
contactSyncListener = new HXContactSyncListener();
HXSDKHelper.getInstance().addSyncContactListener(contactSyncListener);
blackListSyncListener = new HXBlackListSyncListener();
HXSDKHelper.getInstance().addSyncBlackListListener(blackListSyncListener);
if (!HXSDKHelper.getInstance().isContactsSyncedWithServer()) {
progressBar.setVisibility(View.VISIBLE);
} else {
progressBar.setVisibility(View.GONE);
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
if (((AdapterContextMenuInfo) menuInfo).position > 2) {
toBeProcessUser = adapter.getItem(((AdapterContextMenuInfo) menuInfo).position);
toBeProcessUsername = toBeProcessUser.getUsername();
getActivity().getMenuInflater().inflate(R.menu.context_contact_list, menu);
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
if (item.getItemId() == R.id.delete_contact) {
try {
// 刪除此聯系人
deleteContact(toBeProcessUser);
// 刪除相關的邀請消息
InviteMessgeDao dao = new InviteMessgeDao(getActivity());
dao.deleteMessage(toBeProcessUser.getUsername());
} catch (Exception e) {
e.printStackTrace();
}
return true;
}else if(item.getItemId() == R.id.add_to_blacklist){
moveToBlacklist(toBeProcessUsername);
return true;
}
return super.onContextItemSelected(item);
}
/**
* 當該Fragment對象改變了隱藏狀態(由isHidden()方法返回)時,系統會調用這種方法。
* Fragment初始是不隱藏的,僅僅要Fragment對象改變了它的顯示狀態。就會調用該方法。
* 參數hidden 假設該Fragment對象如今是隱藏的,則該參數是true。否則是false。
*/
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
this.hidden = hidden;
if (!hidden) {
refresh();
}
}
@Override
public void onResume() {
super.onResume();
if (!hidden) {
refresh();
}
}
/**
* 刪除聯系人
*
* @param toDeleteUser
*/
public void deleteContact(final User tobeDeleteUser) {
String st1 = getResources().getString(R.string.deleting);
final String st2 = getResources().getString(R.string.Delete_failed);
final ProgressDialog pd = new ProgressDialog(getActivity());
pd.setMessage(st1);
pd.setCanceledOnTouchOutside(false);
pd.show();
new Thread(new Runnable() {
public void run() {
try {
EMContactManager.getInstance().deleteContact(tobeDeleteUser.getUsername());
// 刪除db和內存中此用戶的數據
UserDao dao = new UserDao(getActivity());
dao.deleteContact(tobeDeleteUser.getUsername());
DemoApplication.getInstance().getContactList().remove(tobeDeleteUser.getUsername());
getActivity().runOnUiThread(new Runnable() {
public void run() {
pd.dismiss();
adapter.remove(tobeDeleteUser);
adapter.notifyDataSetChanged();
}
});
} catch (final Exception e) {
getActivity().runOnUiThread(new Runnable() {
public void run() {
pd.dismiss();
Toast.makeText(getActivity(), st2 + e.getMessage(), 1).show();
}
});
}
}
}).start();
}
/**
* 把user移入到黑名單
*/
private void moveToBlacklist(final String username){
final ProgressDialog pd = new ProgressDialog(getActivity());
String st1 = getResources().getString(R.string.Is_moved_into_blacklist);
final String st2 = getResources().getString(R.string.Move_into_blacklist_success);
final String st3 = getResources().getString(R.string.Move_into_blacklist_failure);
pd.setMessage(st1);
pd.setCanceledOnTouchOutside(false);
pd.show();
new Thread(new Runnable() {
public void run() {
try {
//加入到黑名單
EMContactManager.getInstance().addUserToBlackList(username,false);
getActivity().runOnUiThread(new Runnable() {
public void run() {
pd.dismiss();
Toast.makeText(getActivity(), st2, 0).show();
refresh();
}
});
} catch (EaseMobException e) {
e.printStackTrace();
getActivity().runOnUiThread(new Runnable() {
public void run() {
pd.dismiss();
Toast.makeText(getActivity(), st3, 0).show();
}
});
}
}
}).start();
}
// 刷新ui
public void refresh() {
try {
// 可能會在子線程中調到這方法
getActivity().runOnUiThread(new Runnable() {
public void run() {
getContactList();
adapter.notifyDataSetChanged();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
if (contactSyncListener != null) {
HXSDKHelper.getInstance().removeSyncContactListener(contactSyncListener);
contactSyncListener = null;
}
if(blackListSyncListener != null){
HXSDKHelper.getInstance().removeSyncBlackListListener(blackListSyncListener);
}
super.onDestroy();
}
public void showProgressBar(boolean show) {
if (progressBar != null) {
if (show) {
progressBar.setVisibility(View.VISIBLE);
} else {
progressBar.setVisibility(View.GONE);
}
}
}
/**
* 獲取聯系人列表。並過濾掉黑名單和排序
*/
private void getContactList() {
contactList.clear();
//獲取本地好友列表
Map<String, User> users = DemoApplication.getInstance().getContactList();
Iterator<Entry<String, User>> iterator = users.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, User> entry = iterator.next();
if (!entry.getKey().equals(Constant.NEW_FRIENDS_USERNAME)
&& !entry.getKey().equals(Constant.GROUP_USERNAME)
&& !entry.getKey().equals(Constant.CHAT_ROOM)
&& !blackList.contains(entry.getKey())){
EMLog.i(TAG, "獲取聯系人="+entry.getValue());
contactList.add(entry.getValue());
}
}
// 排序
Collections.sort(contactList, new Comparator<User>() {
@Override
public int compare(User lhs, User rhs) {
return lhs.getUsername().compareTo(rhs.getUsername());
}
});
// 加入"群聊"和"聊天室"
if(users.get(Constant.CHAT_ROOM) != null)
contactList.add(0, users.get(Constant.CHAT_ROOM));
if(users.get(Constant.GROUP_USERNAME) != null)
contactList.add(0, users.get(Constant.GROUP_USERNAME));
// 把"申請與通知"加入到首位
if(users.get(Constant.NEW_FRIENDS_USERNAME) != null)
contactList.add(0, users.get(Constant.NEW_FRIENDS_USERNAME));
}
void hideSoftKeyboard() {
if (getActivity().getWindow().getAttributes().softInputMode !=
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
if (getActivity().getCurrentFocus() != null)
inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(((MainActivity)getActivity()).isConflict){
outState.putBoolean("isConflict", true);
}else if(((MainActivity)getActivity()).getCurrentAccountRemoved()){
outState.putBoolean(Constant.ACCOUNT_REMOVED, true);
}
}
}
上面聯系人類中的註冊的監聽器使用的就是觀察者模式,先看HXSDKHelper.java中的部分代碼
public void addSyncGroupListener(HXSyncListener listener) {
if (listener == null) {
return;
}
if (!syncGroupsListeners.contains(listener)) {
syncGroupsListeners.add(listener);
}
}
public void removeSyncGroupListener(HXSyncListener listener) {
if (listener == null) {
return;
}
if (syncGroupsListeners.contains(listener)) {
syncGroupsListeners.remove(listener);
}
}
public void addSyncContactListener(HXSyncListener listener) {
if (listener == null) {
return;
}
if (!syncContactsListeners.contains(listener)) {
syncContactsListeners.add(listener);
}
}
public void removeSyncContactListener(HXSyncListener listener) {
if (listener == null) {
return;
}
if (syncContactsListeners.contains(listener)) {
syncContactsListeners.remove(listener);
}
}
public void addSyncBlackListListener(HXSyncListener listener) {
if (listener == null) {
return;
}
if (!syncBlackListListeners.contains(listener)) {
syncBlackListListeners.add(listener);
}
}
public void removeSyncBlackListListener(HXSyncListener listener) {
if (listener == null) {
return;
}
if (syncBlackListListeners.contains(listener)) {
syncBlackListListeners.remove(listener);
}
}
public void noitifyGroupSyncListeners(boolean success){
for (HXSyncListener listener : syncGroupsListeners) {
listener.onSyncSucess(success);
}
}
public void notifyContactsSyncListener(boolean success){
for (HXSyncListener listener : syncContactsListeners) {
listener.onSyncSucess(success);
}
}
public void notifyBlackListSyncListener(boolean success){
for (HXSyncListener listener : syncBlackListListeners) {
listener.onSyncSucess(success);
}
}
這部分代碼控制著觀察者,加入、刪除、通知每一個觀察者,當群組、好友、黑名單 通過環信server同步到client之後,notify每一個觀察者,然後觀察者接收到之後,刷新UI。這裏就是觀察者模式的經典應用!
!
!
聯系人列表看懂之後,其它的群組界面和回話歷史界面就不多說了。
3 聊天界面ChatActivity.java
這個類比較龐大,由於demo裏面把單聊和群聊、聊天室都集成到這一個界面中完畢,代碼非常龐大。可是不影響終於的集成,直接集成該類就能夠實現功能。
不多說。
附上界面:
圖一 回話歷史界面
圖二 通訊錄界面好友
圖三 設置界面
圖四 聊天界面
最後附上源代碼下載
其它的就沒有什麽特別須要指出的地方了,大家假設有什麽問題或者疑問。都能夠留言交流!
【握手】!
2016年5月17日更新
環信官方站點已經公布IM3.0版本號。
眼下開發的一個app採用的就是IM3.0版本號。
總體界面沒發生大的變化,功能也都一樣。可是在官方給的demo代碼上優化非常多。方便非常多。只是得大概看懂裏面的代碼。假設是高手的話,半天就應該能集成好環信的即時通信功能。
本文給出的下載鏈接,是IM2.0版本號。所以假設想要使用IM3.0的版本號的。須要到官網下載。
對於新手來說,環信官網給出的demo是能夠直接使用的。人家給出的是完整的app代碼。新手就疑惑,不知道該怎樣入手集成即時通信功能?
事實上非常easy!
首先,把環信官網給出的依賴包和動態庫加入到自己的project中。
眼下官網給出的依賴包和動態庫分為包括語音視頻通話功能的和不包括語音視頻通話功能的。
大家依據自己的APP的功能加入。
然後,把demo裏面的聊天界面直接拷貝到自己的功能裏面。此時復制進去以後。會出現大量的錯誤!由於聊天界面關聯了非常多demo中的其它類,所以,要把其它類拷貝到自己的project中。
記得不要忘記布局文件、資源圖片文件、字符串等等資源文件。 建議:在自己的project中。新建一個包專門放環信的類。
由於你要復制的類非常多。大概有二三十個!
最後,向即時通信代碼填充數據。主要有幾部分:
1)application類中環信helper類完畢初始化操作。
2)登錄app界面做好登錄環信server操作。須要登錄環信的登錄名和password。這裏的環信登錄與登錄app
不同。APP登錄是應用server的用戶。用戶名和password在應用server。
而登錄環信是環信的登錄名和password。
須要先註冊到環信server才行。註冊操作能夠在應用server提前做好。APP登錄應用server的時候順帶著
登錄環信server就可以。
3)獲取好友信息。這裏要分為好友信息的維護是應用server維護還是環信幫助你維護。
這個我就不多說
了。
環信官網有說明。
4)本地維護好友列表和聊天信息裏列表。聊天信息列表在環信中已經不讓開發人員編輯和改變了。
該功能
已經集成在了依賴的環信的包中了。
好友列表在demo中給出了簡單的數據表。
開發人員能夠自己依據APP
須要開發和擴展。
5)退出APP。退出APP時務必調用helper類的logout方法。
這樣以後,先前登錄的用戶就從APP上退
出了環信的server。開發人員要註意。我這裏說的退出時指APP用戶手動退出。不是用戶按手機返回button或
者返回主界面button導致APP退出。而是APP中的退出button,當前登錄用戶退出APP。假設是用戶按返回按
鈕或回主界面button,返回到手機桌面的,不是必需調用helper類的logout方法。
先說這麽多。大家還有什麽問題,大家留言交流~~
android-使用環信SDK開發即時通信功能及源代碼下載