百度推送之Im

轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:【張鴻洋的博客】

一直在仿微信界面,今天終於有幸利用百度雲推送仿一仿微信聊天了~~~

首先特別感謝:weidi1989分享的Android之基於百度雲推送IM ,大家可以直接下載;省了很多事哈,本例中也使用了weidi的部分代碼,凡是@author way的就是weidi1989的代碼~~

1、效果圖


核心功能也就上面的兩張圖了~~~我拿着手機和模擬器聊天,同時感謝羣裏的兄弟姐妹幫忙測試(好友列表中)。

2、原理

下面通過幾個問題來說明下實現的原理:

1、如何實現給某個用戶發送消息呢?

其實就是利用百度雲提供的REST API,直接通過發送Http請求的形式給某個用戶推送一條消息;

網址:http://developer.baidu.com/wiki/index.php?title=docs/cplat/push/api/list

實例:

push_msg
功能
推送消息,該接口可用於推送單個人、一羣人、所有人以及固定設備的使用場景。
HTTP請求方式
POST
URL
http[s]://channel.api.duapp.com/rest/2.0/channel/channel

....

2、的確可以實現給某個用戶或者一羣用戶推送消息,那麼用戶的暱稱神馬的咋獲取的呢,我印象中百度雲中沒法存這樣的數據?

嗯,其實用了一個比較巧妙的方式;在用戶首次安裝軟件的時候,會要求用戶填寫註冊信息,也就是暱稱等;當用戶填寫完畢時,點擊登錄的時候:

1、發送一條比較特殊的消息,比如這個消息攜帶一個hello的字段,廣播給所有用戶;

2、其他用戶在收到消息時,首先判斷hello這個字段是否有值,有值則說明新用戶加入,把該新用戶存入本地數據庫,然後更新用戶列表;

3、其他用戶給這個新用戶回一條消息,附帶一個特殊字段,比如welcome,當新用戶收到攜帶welcome字段的消息時,表明這是對新用戶hello的答覆,然後將已存在用戶添加到該新用戶的用戶列表。

基本原理就這樣了,大家甚至可以利用上述的原理添加一些刪除好友的功能;比如當用戶點擊刪除好友,則發送一條特殊消息給被刪除的對象,然後對方收到該消息,也將發送發刪除。

相信大家在瞭解原理之後,這個例子瞬間從高大尚變成矮矬窮了,這尼瑪,so easy,誰不會啊~~~


3、核心代碼解析

由於代碼量還是相當大的,也不想拆成幾篇博客,所以準備將核心代碼進行講解下,其他的大家自己看源碼~

關於這個例子的主界面,可以參考: 高仿微信5.2.1主界面架構 包含消息通知

關於百度雲推送的入門,可以參考:Android推送 百度雲推送 入門篇

好了,最主要就是收到百度雲推送的Receiver

1、onBind

首先是用戶第一次登錄時候綁定的回調

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2.     public void onBind(final Context context, int errorCode, String appid,  
  3.             String userId, String channelId, String requestId)  
  4.     {  
  5.         String responseString = "onBind errorCode=" + errorCode + " appid="  
  6.                 + appid + " userId=" + userId + " channelId=" + channelId  
  7.                 + " requestId=" + requestId;  
  8.         Log.e(TAG, responseString);  
  9.   
  10.         if (errorCode == 0)  
  11.         {  
  12.             SharePreferenceUtil util = PushApplication.getInstance()  
  13.                     .getSpUtil();  
  14.             util.setAppId(appid);  
  15.             util.setChannelId(channelId);  
  16.             util.setUserId(userId);  
  17.               
  18.         } else  
  19.         // 如果網絡正常,則重試  
  20.         {  
  21.             if (NetUtil.isNetConnected(context))  
  22.             {  
  23.   
  24.                 T.showLong(context, "啓動失敗,正在重試...");  
  25.                 new Handler().postDelayed(new Runnable()  
  26.                 {  
  27.                     @Override  
  28.                     public void run()  
  29.                     {  
  30.                         PushManager.startWork(context,  
  31.                                 PushConstants.LOGIN_TYPE_API_KEY,  
  32.                                 PushApplication.API_KEY);  
  33.                     }  
  34.                 }, 2000);// 兩秒後重新開始驗證  
  35.             } else  
  36.             {  
  37.                 T.showLong(context, R.string.net_error_tip);  
  38.             }  
  39.         }  
  40.         // 回調函數  
  41.         for (int i = 0; i < bindListeners.size(); i++)  
  42.             bindListeners.get(i).onBind(userId, errorCode);  
  43.     }  
初次綁定的時候,如果綁定成功則使用SharedPreferences存儲userId,channelId等數據

然後回調:bindListeners.get(i).onBind(userId, errorCode);給所有註冊該事件的發出通知

下面看listener.onBind

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. /** 
  2.      * 收到通知 
  3.      */  
  4.     @Override  
  5.     public void onBind(String userId, int errorCode)  
  6.     {  
  7.         Log.e("TAG""Login Activity onBind ");  
  8.         if (errorCode == 0)  
  9.         {  
  10.             Log.e("TAG""Login Activity onBind success ");  
  11.             // 如果綁定賬號成功,由於第一次運行,給同一tag的人推送一條新人消息  
  12.             User u = new User(mSpUtil.getUserId(), mSpUtil.getChannelId(),  
  13.                     mSpUtil.getNick(), mSpUtil.getHeadIcon(), 0);  
  14.             mUserDB.addUser(u);// 把自己添加到數據庫  
  15.             Message firstSendMsg = new Message(System.currentTimeMillis(), "");  
  16.             firstSendMsg.setHello("hello");  
  17.             task = new SendMsgAsyncTask(mGson.toJson(firstSendMsg), "");  
  18.             task.setOnSendScuessListener(new OnSendScuessListener()  
  19.             {  
  20.                 @Override  
  21.                 public void sendScuess()  
  22.                 {  
  23.                     if (mLoadingDialog != null && mLoadingDialog.isVisible())  
  24.                         mLoadingDialog.dismiss();  
  25.                     mHandler.removeCallbacks(mConnTimeoutCallback);  
  26.                     finish();  
  27.                     Intent intent = new Intent(LoginActivity.this,  
  28.                             MainActivity.class);  
  29.                     startActivity(intent);  
  30.                 }  
  31.             });  
  32.             task.send();  
  33.         }  
  34.     }  
首先將自己保存到本地數據庫,然後發送一個Message給所有的用戶,設置一個特殊字段hello;也就是上述的原理分析中的部分~


2、onMessage

收到百度雲推送的Receiver中的onMessage

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2.     public void onMessage(Context context, String message,  
  3.             String customContentString)  
  4.     {  
  5.         String messageString = "收到消息 message=\"" + message  
  6.                 + "\" customContentString=" + customContentString;  
  7.         Log.e(TAG, messageString);  
  8.         Message receivedMsg = PushApplication.getInstance().getGson()  
  9.                 .fromJson(message, Message.class);  
  10.         // 對接收到的消息進行處理  
  11.         parseMessage(receivedMsg);  
  12.   
  13.     }  
  14.   
  15.     /** 
  16.      * 消息:1、攜帶hello,表示新人加入,應該自動回覆一個world 消息; 2、普通消息; 
  17.      *  
  18.      * @param msg 
  19.      */  
  20.     private void parseMessage(Message msg)  
  21.     {  
  22.         String userId = msg.getUserId();  
  23.         // 自己的消息  
  24.         if (userId  
  25.                 .equals(PushApplication.getInstance().getSpUtil().getUserId()))  
  26.             return;  
  27.         if (checkHasNewFriend(msg) || checkAutoResponse(msg))  
  28.             return;  
  29.         // 普通消息  
  30.         UserDB userDB = PushApplication.getInstance().getUserDB();  
  31.         User user = userDB.selectInfo(userId);  
  32.         // 漏網之魚  
  33.         if (user == null)  
  34.         {  
  35.             user = new User(userId, msg.getChannelId(), msg.getNickname(), 00);  
  36.             userDB.addUser(user);  
  37.             // 通知監聽的面板  
  38.             for (onNewFriendListener listener : friendListeners)  
  39.                 listener.onNewFriend(user);  
  40.         }  
  41.         if (msgListeners.size() > 0)  
  42.         {// 有監聽的時候,傳遞下去  
  43.             for (int i = 0; i < msgListeners.size(); i++)  
  44.                 msgListeners.get(i).onNewMessage(msg);  
  45.         } else  
  46.         // 當前沒有任何監聽,即處理後臺狀態  
  47.         {  
  48.             // 將新來的消息進行存儲  
  49.             ChatMessage chatMessage = new ChatMessage(msg.getMessage(), true,  
  50.                     userId, msg.getHeadIcon(), msg.getNickname(), false,  
  51.                     TimeUtil.getTime(msg.getTimeSamp()));  
  52.             PushApplication.getInstance().getMessageDB()  
  53.                     .add(userId, chatMessage);  
  54.             showNotify(msg);  
  55.         }  
  56.     }  
  57.   
  58.     /** 
  59.      * 檢測是否是自動回覆 
  60.      *  
  61.      * @param msg 
  62.      */  
  63.     private boolean checkAutoResponse(Message msg)  
  64.     {  
  65.         String world = msg.getWorld();  
  66.         String userId = msg.getUserId();  
  67.         if (!TextUtils.isEmpty(world))  
  68.         {  
  69.             User u = new User(userId, msg.getChannelId(), msg.getNickname(),  
  70.                     msg.getHeadIcon(), 0);  
  71.             PushApplication.getInstance().getUserDB().addUser(u);// 存入或更新好友  
  72.             // 通知監聽的面板  
  73.             for (onNewFriendListener listener : friendListeners)  
  74.                 listener.onNewFriend(u);  
  75.   
  76.             return true;  
  77.         }  
  78.         return false;  
  79.     }  
  80.   
  81.     /** 
  82.      * 檢測是否是新人加入 
  83.      *  
  84.      * @param msg 
  85.      */  
  86.     private boolean checkHasNewFriend(Message msg)  
  87.     {  
  88.         String userId = msg.getUserId();  
  89.         String hello = msg.getHello();  
  90.         // 新人發送的消息  
  91.         if (!TextUtils.isEmpty(hello))  
  92.         {  
  93.             Log.e("checkHasNewFriend", msg.getUserId());  
  94.             // 新人  
  95.             User u = new User(userId, msg.getChannelId(), msg.getNickname(),  
  96.                     msg.getHeadIcon(), 0);  
  97.             PushApplication.getInstance().getUserDB().addUser(u);// 存入或更新好友  
  98.             T.showShort(PushApplication.getInstance(), u.getNick() + "加入");  
  99.   
  100.             // 給新人回覆一個應答  
  101.             Message message = new Message(System.currentTimeMillis(), "");  
  102.             message.setWorld("world");  
  103.             new SendMsgAsyncTask(PushApplication.getInstance().getGson()  
  104.                     .toJson(message), userId);  
  105.             // 通知監聽的面板  
  106.             for (onNewFriendListener listener : friendListeners)  
  107.                 listener.onNewFriend(u);  
  108.   
  109.             return true;  
  110.         }  
  111.   
  112.         return false;  
  113.     }  

當收到一個新的消息:

1、首先判斷是不是自己發的,是,忽略;

2、判斷是否攜帶hello字段,代表新人加入,攜帶,則保存到好友列表,且回覆一個攜帶welcome字段的消息;

3、判斷是否包含welcome字段,包含,存入好友列表

4、不是1、2、3則肯定是普通消息,將消息保存到本地數據庫,然後爲所有設置消息監聽的發送回調即可~


MainTabFriends.java用戶列表中收到新消息的回調:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. /** 
  2.      * 收到新消息時 
  3.      */  
  4.     @Override  
  5.     public void onNewMessage(Message message)  
  6.     {  
  7.         // 如果是自己發送的,則直接返回  
  8.         if (message.getUserId() == mSpUtils.getUserId())  
  9.             return;  
  10.         // 如果該用戶已經有未讀消息,更新未讀消息的個數,並通知更新未讀消息接口,最後notifyDataSetChanged  
  11.         String userId = message.getUserId();  
  12.         if (mUserMessages.containsKey(userId))  
  13.         {  
  14.             mUserMessages.put(userId, mUserMessages.get(userId) + 1);  
  15.         } else  
  16.         {  
  17.             mUserMessages.put(userId, 1);  
  18.         }  
  19.         mUnReadedMsgs++;  
  20.         notifyUnReadedMsg();  
  21.         // 將新來的消息進行存儲  
  22.         ChatMessage chatMessage = new ChatMessage(message.getMessage(), true,  
  23.                 userId, message.getHeadIcon(), message.getNickname(), false,  
  24.                 TimeUtil.getTime(message.getTimeSamp()));  
  25.         mApplication.getMessageDB().add(userId, chatMessage);  
  26.         // 通知listview數據改變  
  27.         mAdapter.notifyDataSetChanged();  
  28.     }  

1、如果是自己發的不做任何處理

2、如果當前消息發送用戶已有未讀消息,則更新該用戶未讀消息個數(用戶Item上顯示未讀消息通知數),更新所有未讀消息總和(朋友Tab上顯示未讀消息總和),然後存儲該消息

3、刷新界面


ChattingActivity.java聊天界面的新消息回調

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. @Override  
  2.     public void onNewMessage(Message message)  
  3.     {  
  4.   
  5.         // 獲得回覆的消息  
  6.         if (mFromUser.getUserId().equals(message.getUserId()))  
  7.         {  
  8.             ChatMessage chatMessage = new ChatMessage();  
  9.             chatMessage.setComing(true);  
  10.             chatMessage.setDate(new Date(message.getTimeSamp()));  
  11.             chatMessage.setMessage(message.getMessage());  
  12.             chatMessage.setUserId(message.getUserId());  
  13.             chatMessage.setNickname(message.getNickname());  
  14.             chatMessage.setReaded(true);  
  15.             mDatas.add(chatMessage);  
  16.             mAdapter.notifyDataSetChanged();  
  17.             mChatMessagesListView.setSelection(mDatas.size() - 1);  
  18.             // 存入數據庫,當前聊天記錄  
  19.             mApplication.getMessageDB().add(mFromUser.getUserId(), chatMessage);  
  20.         }  
  21.     }  

首先判斷是否是正在聊天的用戶發的消息,如果是,直接存入數據庫,刷新聊天界面;



好了,細節也不展開描述了,大家自己看源碼,bug肯定有,發現bug可以直接留言,方便其他學習的童鞋,也方便我了,多謝~~~~~~~~~~~~~~

ps:最近狀態不好,我要去喝脈動~~~~


源碼點擊下載  大家可以先安裝壓縮文件裏面的apk測試下,這樣就可以發現別的夥伴了~~~


源碼點擊下載 補充了一下那個BadgeView的項目~~~


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章