Android學習筆記--基於XMPP的即時通訊


一、常見即時通訊實現

socket

openfire+asmack

環信

信鴿

融雲

 

二、XMPP優勢

1. 開放性

XMPP協議是自由、開放、公開的,並且易於了解。而且在客戶端、服務器、組件、源碼庫等方面,都已經各自有多種實現。

 

2.跨平台

客戶端只要基於XMPP協議,不管是什么平台(包括不同的移動終端)都可以互聯互通。

三、XMPP協議簡介  

The Extensible Messaging and Presence Protocol (可擴展通訊和表示協議) XMPP 以 Jabber 協議為基礎,而 Jabber 是即時通訊中常用的開放式協議。

 

數據格式

XML是XMPP系統架構的核心。它能表述幾乎任何一種結構化數據。特別是XMPP利用XML數據流進行客戶端一服務器端、服務器端一服務器端的通信。XML數據流一般是由客戶端發起至服務端,XML數據流的有效時間直接與用戶的在線會話有效時間相關聯。

 

XMPP 的特點是將復雜性從客戶端轉移到服務器端。這使得客戶端編寫變得非常容易,更新系統功能也同樣變得容易。

XMPP中定義了三個角色:XMPP客戶端、XMPP服務器、網關。

客戶端:通過 TCP 套接字與XMPP 服務器進行通信

服務器:同時承擔了客戶端信息記錄、連接管理和信息的路由功能

網關:承擔着與異構即時通信系統的互聯互通(異構系統可以包括SMS(短信),MSN,ICQ等)

 

五、XMPP協議的地址格式(標志)

每個客戶端需要擁有一個地址標識用於定位,XMPP 中稱之為 JID (Jabber ID)。地址標識的格式如下

[ node "@" ] domain [ "/" resource ]

例如:

charley@gmail.com/spark

 

格式與 Email 地址格式類似,但增添了 resource 項(非必需的)。上述例子可以解釋為:在 gmail.com 服務器注冊的 charley用戶,且使用 spark客戶端軟件登錄。資源(resource )只用來識別屬於用戶的位置或設備等,一個用戶可以同時以多種資源與同一個XMPP服務器連接(說白了就是用於支持同一賬號的多客戶端登錄)。

 

六、協議消息格式

XMPP協議包括3個頂層XML元素:Message、Presence和IQ。

Message用來表示傳輸的消息,當用戶發送一條消息時。就會在流的上下文中插入一個Message元素,中間有用戶發送的相關信息;

Presence用來表示用戶的狀態。當用戶改變自己的狀態時。就會在數據流的上下文中插入一個Presence元素,用來表示用戶現在的狀態;

IQ用來表示一種請求,響應機制,從一個實體發送請求,另外一個實體接受請求並響應。

 

XMPP特點

1.客戶端通過TCP/IP協議連接到服務器,然后通過XML傳輸數據。

2.XMPP的核心部分就是一個在網絡上分片斷發送XML的流協議。這個流協議是XMPP的即時通訊指令的傳遞基礎,也是一個非常重要的可以被進一步利用的網絡基礎協議。所以可以說,XMPP用TCP傳的是XML流。

 

理論一大堆。。。。接下來貼代碼

XmppManager.java
  1 package com.example.xmppdemo.fengzhuang;
  2 
  3 import android.util.Log;
  4 
  5 
  6 
  7 import org.jivesoftware.smack.Chat;
  8 import org.jivesoftware.smack.ChatManager;
  9 import org.jivesoftware.smack.ChatManagerListener;
 10 import org.jivesoftware.smack.ConnectionConfiguration;
 11 import org.jivesoftware.smack.MessageListener;
 12 import org.jivesoftware.smack.PacketCollector;
 13 import org.jivesoftware.smack.Roster;
 14 import org.jivesoftware.smack.RosterEntry;
 15 import org.jivesoftware.smack.SmackConfiguration;
 16 import org.jivesoftware.smack.XMPPConnection;
 17 import org.jivesoftware.smack.XMPPException;
 18 import org.jivesoftware.smack.filter.AndFilter;
 19 import org.jivesoftware.smack.filter.PacketFilter;
 20 import org.jivesoftware.smack.filter.PacketIDFilter;
 21 import org.jivesoftware.smack.filter.PacketTypeFilter;
 22 import org.jivesoftware.smack.packet.IQ;
 23 import org.jivesoftware.smack.packet.Message;
 24 import org.jivesoftware.smack.packet.Presence;
 25 import org.jivesoftware.smack.packet.Registration;
 26 import org.jivesoftware.smack.provider.PrivacyProvider;
 27 import org.jivesoftware.smack.provider.ProviderManager;
 28 import org.jivesoftware.smackx.Form;
 29 import org.jivesoftware.smackx.GroupChatInvitation;
 30 import org.jivesoftware.smackx.PrivateDataManager;
 31 import org.jivesoftware.smackx.ReportedData;
 32 import org.jivesoftware.smackx.bytestreams.socks5.provider.BytestreamsProvider;
 33 import org.jivesoftware.smackx.packet.ChatStateExtension;
 34 import org.jivesoftware.smackx.packet.LastActivity;
 35 import org.jivesoftware.smackx.packet.OfflineMessageInfo;
 36 import org.jivesoftware.smackx.packet.OfflineMessageRequest;
 37 import org.jivesoftware.smackx.packet.SharedGroupsInfo;
 38 import org.jivesoftware.smackx.packet.VCard;
 39 import org.jivesoftware.smackx.provider.AdHocCommandDataProvider;
 40 import org.jivesoftware.smackx.provider.DataFormProvider;
 41 import org.jivesoftware.smackx.provider.DelayInformationProvider;
 42 import org.jivesoftware.smackx.provider.DiscoverInfoProvider;
 43 import org.jivesoftware.smackx.provider.DiscoverItemsProvider;
 44 import org.jivesoftware.smackx.provider.MUCAdminProvider;
 45 import org.jivesoftware.smackx.provider.MUCOwnerProvider;
 46 import org.jivesoftware.smackx.provider.MUCUserProvider;
 47 import org.jivesoftware.smackx.provider.MessageEventProvider;
 48 import org.jivesoftware.smackx.provider.MultipleAddressesProvider;
 49 import org.jivesoftware.smackx.provider.RosterExchangeProvider;
 50 import org.jivesoftware.smackx.provider.StreamInitiationProvider;
 51 import org.jivesoftware.smackx.provider.VCardProvider;
 52 import org.jivesoftware.smackx.provider.XHTMLExtensionProvider;
 53 import org.jivesoftware.smackx.search.UserSearch;
 54 import org.jivesoftware.smackx.search.UserSearchManager;
 55 
 56 import java.util.ArrayList;
 57 import java.util.Collection;
 58 import java.util.Collections;
 59 import java.util.Iterator;
 60 import java.util.List;
 61 
 62 /**
 63  * Created by Kelvin on 2016/12/12.
 64  */
 65 
 66 public class XmppManager {
 67 
 68     private static XmppManager xmppManager; //XmppManager的實例
 69 
 70     private XmppManager(){} //私有化構造器
 71 
 72     public static XmppManager getInstance(){
 73         if (xmppManager == null){
 74             synchronized (XmppManager.class){
 75                 if (xmppManager == null){
 76                     xmppManager = new XmppManager();
 77                 }
 78             }
 79         }
 80         return xmppManager;
 81     }
 82 
 83     //XmppConnection 連接對象
 84     private XMPPConnection xmppConnection;
 85 
 86     //將其翻譯成中文為"花名冊",用來表示一個用戶的所有好友清單以及申請加好友的用戶清單,
 87     // 為了便於管理,Roster中的用戶分組進行管理。
 88     private Roster roster;
 89 
 90     //用於接收消息的接口
 91     private XmppManagerCallback xmppManagerCallback;
 92 
 93     //Debug標簽
 94     private final String TAG="XmppManager";
 95 
 96     /**
 97      * 打開網絡連接
 98      */
 99     private void openConnection(){
100 
101         //連接對象為空或者還沒有認證的時候(isAuthenticated()方法返回值是boolean類型,意思是是否認證)
102         if (xmppConnection == null || !xmppConnection.isAuthenticated()){
103             try {
104                 //配置連接,(參數一:服務器ip地址,參數二:端口號,參數三:服務器名字)
105                 ConnectionConfiguration configuration = new ConnectionConfiguration(Constant.SERVER_HOST,
106                         Constant.SERVER_PORT,Constant.SERVER_NAME);
107 
108                 //Xmpp是否可以自動重連(客戶端掉線時是否可以重新連接)
109                 configuration.setReconnectionAllowed(true);
110 
111                 //設置安全模式
112                 configuration.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
113                 //特別補充,在設置configuaration的時候對認證的設置,代碼如下:
114                 //這個屬性默認值是true,設置時得需要與服務器那邊統一,如果不一致,就算用戶注冊成功后,
115                 // 登錄時也會返回 server-unavailable(503)錯誤,我們用的是ejabberd服務器,默認設置SASL認證開啟,
116                 // 所以開始我設置為false,怎么都無法登錄,最后注釋這句代碼,成功登錄:)
117                 //相當於一個權限
118                 configuration.setSASLAuthenticationEnabled(false);
119                 // 狀態設為離線,為了取離線消息
120                 configuration.setSendPresence(true);
121                 // 配置各種Provider,如果不配置,則會無法解析數據
122                 configureConnection(ProviderManager.getInstance());
123                 xmppConnection = new XMPPConnection(configuration);
124                 //打開連接
125                 xmppConnection.connect();
126             } catch (XMPPException e) {
127                 e.printStackTrace();
128             }
129         }
130     }
131 
132     /**
133      * 配置連接
134      * @param pm
135      */
136     public void configureConnection(ProviderManager pm) {
137         // Private Data Storage
138         pm.addIQProvider("query", "jabber:iq:private", new PrivateDataManager.PrivateDataIQProvider());
139         // Time
140         try {
141             pm.addIQProvider("query", "jabber:iq:time", Class.forName("org.jivesoftware.smackx.packet.Time"));
142         } catch (ClassNotFoundException e) {
143             Log.w("TestClient", "Can't load class for org.jivesoftware.smackx.packet.Time");
144         }
145 
146         // Roster Exchange
147         pm.addExtensionProvider("x", "jabber:x:roster", new RosterExchangeProvider());
148         // Message Events
149         pm.addExtensionProvider("x", "jabber:x:event", new MessageEventProvider());
150         // Chat State
151         pm.addExtensionProvider("active", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
152         pm.addExtensionProvider("composing", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
153         pm.addExtensionProvider("paused", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
154         pm.addExtensionProvider("inactive", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
155         pm.addExtensionProvider("gone", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
156         // XHTML
157         pm.addExtensionProvider("html", "http://jabber.org/protocol/xhtml-im", new XHTMLExtensionProvider());
158         // Group Chat Invitations
159         pm.addExtensionProvider("x", "jabber:x:conference", new GroupChatInvitation.Provider());
160         // Service Discovery # Items
161         pm.addIQProvider("query", "http://jabber.org/protocol/disco#items", new DiscoverItemsProvider());
162         // Service Discovery # Info
163         pm.addIQProvider("query", "http://jabber.org/protocol/disco#info", new DiscoverInfoProvider());
164         // Data Forms
165         pm.addExtensionProvider("x", "jabber:x:data", new DataFormProvider());
166         // MUC User
167         pm.addExtensionProvider("x", "http://jabber.org/protocol/muc#user", new MUCUserProvider());
168         // MUC Admin
169         pm.addIQProvider("query", "http://jabber.org/protocol/muc#admin", new MUCAdminProvider());
170         // MUC Owner
171         pm.addIQProvider("query", "http://jabber.org/protocol/muc#owner", new MUCOwnerProvider());
172         // Delayed Delivery
173         pm.addExtensionProvider("x", "jabber:x:delay", new DelayInformationProvider());
174         // Version
175         try {
176             pm.addIQProvider("query", "jabber:iq:version", Class.forName("org.jivesoftware.smackx.packet.Version"));
177         } catch (ClassNotFoundException e) {
178             // Not sure what's happening here.
179         }
180         // VCard
181         pm.addIQProvider("vCard", "vcard-temp", new VCardProvider());
182         // Offline Message Requests
183         pm.addIQProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageRequest.Provider());
184         // Offline Message Indicator
185         pm.addExtensionProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageInfo.Provider());
186         // Last Activity
187         pm.addIQProvider("query", "jabber:iq:last", new LastActivity.Provider());
188         // User Search
189         pm.addIQProvider("query", "jabber:iq:search", new UserSearch.Provider());
190         // SharedGroupsInfo
191         pm.addIQProvider("sharedgroup", "http://www.jivesoftware.org/protocol/sharedgroup",
192                 new SharedGroupsInfo.Provider());
193         // JEP-33: Extended Stanza Addressing
194         pm.addExtensionProvider("addresses", "http://jabber.org/protocol/address", new MultipleAddressesProvider());
195         // FileTransfer
196         pm.addIQProvider("si", "http://jabber.org/protocol/si", new StreamInitiationProvider());
197         pm.addIQProvider("query", "http://jabber.org/protocol/bytestreams", new BytestreamsProvider());
198         // Privacy
199         pm.addIQProvider("query", "jabber:iq:privacy", new PrivacyProvider());
200         pm.addIQProvider("command", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider());
201         pm.addExtensionProvider("malformed-action", "http://jabber.org/protocol/commands",
202                 new AdHocCommandDataProvider.MalformedActionError());
203         pm.addExtensionProvider("bad-locale", "http://jabber.org/protocol/commands",
204                 new AdHocCommandDataProvider.BadLocaleError());
205         pm.addExtensionProvider("bad-payload", "http://jabber.org/protocol/commands",
206                 new AdHocCommandDataProvider.BadPayloadError());
207         pm.addExtensionProvider("bad-sessionid", "http://jabber.org/protocol/commands",
208                 new AdHocCommandDataProvider.BadSessionIDError());
209         pm.addExtensionProvider("session-expired", "http://jabber.org/protocol/commands",
210                 new AdHocCommandDataProvider.SessionExpiredError());
211     }
212 
213     /**
214      * 獲取鏈接
215      * @return
216      */
217     public XMPPConnection getConnection(){
218         if (xmppConnection == null){
219             openConnection();
220         }
221         return  xmppConnection;
222     }
223 
224     /**
225      * 關閉鏈接
226      */
227     public void colseConnection(){
228         if (xmppConnection != null && xmppConnection.isConnected()){
229             xmppConnection.disconnect();
230             xmppConnection = null;
231         }
232     }
233 
234     /**
235      * 登陸的方法
236      * @param account  賬號
237      * @param psw  密碼
238      * @return
239      */
240     public boolean login(String account,String psw){
241 
242         //判斷連接是否存在
243         if (getConnection() == null){
244             return false;
245         }
246 
247         if (!getConnection().isAuthenticated() && getConnection().isConnected()){
248             try {
249                 //登陸
250                 getConnection().login(account,psw);
251                 //登陸之后更改用戶狀態
252                 Presence presence = new Presence(Presence.Type.available);
253                 //設置用戶在線
254                 presence.setMode(Presence.Mode.available);
255                 //向服務器發送狀態
256                 getConnection().sendPacket(presence);
257                 //接收消息監聽
258                 ChatManager chatManager = getConnection().getChatManager();
259                 chatManager.addChatListener(chatManagerListener);
260                 return true;
261             } catch (XMPPException e) {
262                 e.printStackTrace();
263                 return false;
264             }
265         }
266         return false;
267     }
268 
269     /**
270      * 聊天管理監聽器
271      */
272     private ChatManagerListener chatManagerListener = new ChatManagerListener(){
273 
274         @Override
275         public void chatCreated(Chat chat, boolean b) {
276             chat.addMessageListener(new MessageListener() {
277                 @Override
278                 public void processMessage(Chat chat, Message message) {
279                     //當消息內容為空時,直接反悔
280                     if (TVUtil.isEmpty(message.getBody())){
281                         return;
282                     }
283                     //當消息內容不可空時,通過接口回調的把消息內容傳出去
284                     if (xmppManagerCallback != null){
285                         xmppManagerCallback.receiveMsg(message);
286                     }
287                 }
288             });
289         }
290     };
291 
292     /**
293      * 注冊用戶
294      * 表示的是Info/Query(信息與查詢),它為XMPP通信提供請求與響應機制。它與HTTP
295      * 協議的基本工作原理非常相似,允許獲取和設置查詢,與HTTP 的GET 和POST 動作類似。
296      * @return
297      */
298     public IQ registered(String account, String psw){
299 
300         if (getConnection() == null){
301             return null;
302         }
303 
304         //設置注冊所需要的信息
305         Registration registration = new Registration();
306         registration.setType(IQ.Type.SET);
307         registration.setTo(getConnection().getServiceName());
308         registration.setUsername(account);
309         registration.setPassword(psw);
310 
311         //PacketFilter:包過濾類,過濾一些不用的包
312         PacketFilter filter = new AndFilter(new PacketIDFilter(registration.getPacketID()), new PacketTypeFilter(IQ.class));
313         PacketCollector collector = getConnection().createPacketCollector(filter);
314         // 向服務器端,發送注冊Packet包,注意其中Registration是Packet的子類
315         getConnection().sendPacket(registration);
316         IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
317         collector.cancel(); //停止請求result
318         return result;
319     }
320 
321     /**
322      * 退出登陸
323      */
324     public void outLogin(){
325         if (getConnection() == null){
326             return;
327         }
328 
329         //設置退出狀態
330         Presence presence = new Presence(Presence.Type.unavailable);
331         //發送請求
332         getConnection().sendPacket(presence);
333         //關閉連接
334         colseConnection();
335     }
336 
337     /**
338      * 獲取用戶信息
339      * @param user
340      * @return
341      */
342     public VCard getUserInfo(String user){
343         VCard vCard = null;
344         try {
345             vCard = new VCard();
346             // 加入這句代碼,解決No VCard for
347             ProviderManager.getInstance().addIQProvider("vCard", "vcard-temp", new VCardProvider());
348             if (user == null){
349                 vCard.load(getConnection());
350             }else{
351                 vCard.load(getConnection(), user + "@" + Constant.SERVER_NAME);
352             }
353         } catch (XMPPException e) {
354             e.printStackTrace();
355         }
356         return vCard;
357     }
358 
359     /**
360      * 獲取xmpp好友列表
361      * 注意:這里的User是在Xmpp包下的User
362      */
363     public List<User> getFriendList() {
364         // Roster:花名冊
365         if (roster == null) {
366             roster = getConnection().getRoster();
367         }
368         List<User> userList = new ArrayList<User>();
369         Collection<RosterEntry> entries = roster.getEntries();
370         for(RosterEntry entry : entries){
371             userList.add(new User(getUsername(entry.getUser()),entry.getType()));
372         }
373         Collections.sort(userList,new PingyinComparator());
374         return userList;
375     }
376 
377     /**
378      * 通過jid獲得username
379      * @param fullUsername
380      * @return
381      */
382     public static String getUsername(String fullUsername){
383         return fullUsername.split("@")[0];
384     }
385 
386     /**
387      * 搜索用戶
388      * @param userName
389      * @return
390      * @throws XMPPException
391      */
392     public List<String> searchUser(String userName) {
393         if (getConnection() == null){
394             return null;
395         }
396         List<String> userList = new ArrayList<>();
397         try {
398             UserSearchManager search = new UserSearchManager(getConnection());
399             Form searchForm = search.getSearchForm("search."+ getConnection().getServiceName());
400             Form answerForm = searchForm.createAnswerForm();
401             answerForm.setAnswer("Username", true);
402             answerForm.setAnswer("search", userName.trim());
403             ReportedData data = search.getSearchResults(answerForm,"search." + xmppConnection.getServiceName());
404             Iterator<ReportedData.Row> it = data.getRows();
405             ReportedData.Row row = null;
406             while (it.hasNext()) {
407                 row = it.next();
408                 userList.add(row.getValues("Username").next().toString());
409             }
410         } catch (XMPPException e) {
411             e.printStackTrace();
412         }
413         return userList;
414     }
415 
416     /**
417      * 添加好友(無分組)
418      * @param userName
419      * @return
420      */
421     public boolean addFriend(String userName) {
422         if (getConnection() == null)
423             return false;
424         try {
425             getConnection().getRoster().createEntry(getFullUsername(userName), getFullUsername(userName), null);
426             return true;
427         } catch (Exception e) {
428             e.printStackTrace();
429             return false;
430         }
431     }
432 
433     /**
434      * 通過username獲得jid
435      * @param username
436      * @return
437      */
438     public static String getFullUsername(String username){
439         return username + "@" + Constant.SERVER_NAME;
440     }
441 
442     /**
443      * 創建聊天
444      * @param toUser
445      * @return
446      */
447     public Chat createChat(String toUser){
448         ChatManager chatManager = getConnection().getChatManager();
449         Chat newchat = chatManager.createChat(toUser + "@"+ Constant.SERVER_NAME, null);
450         return newchat;
451     }
452 
453     /**
454      * 發送文本消息
455      * @param message
456      */
457     public void sendMsg(Chat chat, String message) {
458         try {
459             chat.sendMessage(message);
460         } catch (Exception e) {
461             e.printStackTrace();
462         }
463     }
464 
465     /**
466      * 接口回調
467      */
468     public interface XmppManagerCallback {
469         //接收消息回調函數
470         void receiveMsg(Message message);
471     }
472 
473     /**
474      * 設置接口的方法
475      * @param xmppManagerCallback 接口對象
476      */
477     public void setXmppManagerCallback(XmppManagerCallback xmppManagerCallback) {
478         this.xmppManagerCallback = xmppManagerCallback;
479     }
480 }

這里面封裝了所有的方法

 

ChatMsg.java
 1 package com.example.xmppdemo.fengzhuang;
 2 import android.os.Parcel;
 3 import android.os.Parcelable;
 4 
 5 /**
 6  * 
 7  * 描述(請用一句話描述這個內容)
 8  */
 9 
10 public class ChatMsg implements Parcelable {
11 
12     private String sender; // 發送者
13     private String body; // 發送的消息
14 
15     public String getSender() {
16         return sender;
17     }
18 
19     public void setSender(String sender) {
20         this.sender = sender;
21     }
22 
23     public String getBody() {
24         return body;
25     }
26 
27     public void setBody(String body) {
28         this.body = body;
29     }
30 
31     public static final Creator<ChatMsg> CREATOR = new Creator<ChatMsg>() {
32         @Override
33         public ChatMsg createFromParcel(Parcel in) {
34             ChatMsg chatMsg = new ChatMsg();
35             chatMsg.sender = in.readString();
36             chatMsg.body = in.readString();
37             return chatMsg;
38         }
39 
40         @Override
41         public ChatMsg[] newArray(int size) {
42             return null;
43         }
44     };
45 
46     @Override
47     public int describeContents() {
48         return 0;
49     }
50 
51     @Override
52     public void writeToParcel(Parcel parcel, int i) {
53         parcel.writeString(sender);
54         parcel.writeString(body);
55     }
56 }

還有一個

ChatService.java
  1 package com.example.xmppdemo.service;
  2 
  3 import android.app.Activity;
  4 import android.app.Notification;
  5 import android.app.NotificationManager;
  6 import android.app.PendingIntent;
  7 import android.app.Service;
  8 import android.content.BroadcastReceiver;
  9 import android.content.Context;
 10 import android.content.Intent;
 11 import android.content.IntentFilter;
 12 import android.os.IBinder;
 13 import android.support.annotation.Nullable;
 14 
 15 
 16 import com.example.xmppdemo.ChatActivity;
 17 import com.example.xmppdemo.R;
 18 import com.example.xmppdemo.fengzhuang.ChatMsg;
 19 import com.example.xmppdemo.fengzhuang.Constant;
 20 import com.example.xmppdemo.fengzhuang.XmppManager;
 21 
 22 import org.jivesoftware.smack.XMPPException;
 23 import org.jivesoftware.smack.packet.Message;
 24 import org.jivesoftware.smackx.OfflineMessageManager;
 25 
 26 import java.util.ArrayList;
 27 import java.util.Iterator;
 28 
 29 /**
 30  31  * 描述(請用一句話描述這個內容)
 32  */
 33 public class ChatService extends Service implements XmppManager.XmppManagerCallback {
 34 
 35     //接收到的消息集合,包括兩種消息: 1,不在對話框界面的消息 2,離線消息
 36     private ArrayList<ChatMsg> messageList = new ArrayList<>();
 37     private MesageBroadcastReceiver mesageReceiver;
 38 
 39     @Override
 40     public void onCreate() {
 41         XmppManager.getInstance().setXmppManagerCallback(this);
 42         //注冊消息接收廣播
 43         IntentFilter filter = new IntentFilter(Constant.INTENT_ACTION_MESSAGE_RECEIVE);
 44         mesageReceiver = new MesageBroadcastReceiver();
 45         registerReceiver(mesageReceiver, filter);
 46     }
 47 
 48     @Nullable
 49     @Override
 50     public IBinder onBind(Intent intent) {
 51         return null;
 52     }
 53 
 54     @Override
 55     public void receiveMsg(Message message) {
 56         ChatMsg chatMsg = new ChatMsg();
 57 
 58         chatMsg.setSender(message.getFrom());
 59         chatMsg.setBody(message.getBody());
 60         sendReceiverMsgBroadCast(chatMsg);
 61     }
 62     /**
 63      * 發送廣播的方法
 64      * @param
 65      */
 66     private void sendReceiverMsgBroadCast(ChatMsg chatMsg){
 67         Intent intent = new Intent();
 68         intent.setAction(Constant.INTENT_ACTION_MESSAGE_RECEIVE);
 69         intent.putExtra("message", chatMsg);
 70         /**
 71          * MesageBroadcastReceiver指定為最后的接受者,Activity.RESULT_CANCELED指定初始的結果碼,
 72          * 如果ChatActivity中的廣播接收者處理了這條廣播,則結果碼會在ChatActivity中被更改為Activity.RESULT_OK,
 73          * 反之,ChatActivity中的廣播接收者沒有處理,則結果碼仍然為Activity.RESULT_CANCELED
 74          */
 75         sendOrderedBroadcast(intent,null,mesageReceiver,null, Activity.RESULT_CANCELED,null,null);
 76     }
 77     /**
 78      * 消息廣播
 79      */
 80     private class MesageBroadcastReceiver extends BroadcastReceiver{
 81 
 82         @Override
 83         public void onReceive(Context context, Intent intent) {
 84             ChatMsg chatMsg = intent.getParcelableExtra("message");
 85             int resultCode = getResultCode();
 86             if (isOrderedBroadcast()){  //判斷是否有下一個廣播,true為是 false為無
 87 
 88                 if (resultCode != Activity.RESULT_OK){
 89                     showMsgNotice(chatMsg);
 90                 }
 91             }
 92         }
 93     }
 94 
 95     /**
 96      * 顯示消息通知
 97      * @param chatMsg 消息類
 98      */
 99     private void showMsgNotice(ChatMsg chatMsg){
100         messageList.add(chatMsg);  //把消息實體加入到集合中
101         //獲取通知服務
102         NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
103         //取消所有
104         nm.cancelAll();
105         //創建消息
106        /* Notification notification = new Notification(R.drawable.ic_launcher
107                 ,"您有"+messageList.size()+"條新消息", System.currentTimeMillis());
108         notification.flags = Notification.FLAG_AUTO_CANCEL;
109         notification.sound= Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.ms);
110         Intent intent = new Intent(this, ChatActivity.class);
111         intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
112         intent.putExtra("from", "notification");
113         intent.putParcelableArrayListExtra("messageList", messageList);
114         PendingIntent contentIntent = PendingIntent.getActivity(this, R.string.app_name, intent, PendingIntent.FLAG_UPDATE_CURRENT);
115         notification.setLatestEventInfo(this, chatMsg.getSender().split("@")[0], chatMsg.getBody(), contentIntent);
116         nm.notify(0, notification);*/
117 
118         Notification.Builder builder = new Notification.Builder(this);
119         builder.setContentText("微信通知"); //設置通知的標題
120         builder.setSmallIcon(R.drawable.search_icon); //設置通知的小圖標
121         builder.setContentText("您有"+messageList.size()+"條新消息"); //寫入通知內容
122 //        builder.setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.ms));
123         Intent intent = new Intent(this, ChatActivity.class);
124         intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
125         intent.putExtra("from", "notification");
126         intent.putParcelableArrayListExtra("messageList", messageList);
127         PendingIntent contentIntent = PendingIntent.getActivity(this, R.string.app_name, intent, PendingIntent.FLAG_UPDATE_CURRENT);
128         builder.setContentIntent(contentIntent);
129         //獲得通知
130         Notification notification = builder.getNotification();
131         nm.notify(0, notification);
132     }
133 
134     /**
135      * 獲取離線消息
136      */
137     public void getOfflineMessage() {
138         OfflineMessageManager offlineMessageManager = new OfflineMessageManager(XmppManager.getInstance().getConnection());
139         try {
140             Iterator<Message> it = offlineMessageManager.getMessages();
141             while (it.hasNext()) {
142                 Message message = it.next();
143                 ChatMsg chatMsg = new ChatMsg();
144                 chatMsg.setSender(message.getFrom());
145                 chatMsg.setBody(message.getBody());
146                 sendReceiverMsgBroadCast(chatMsg);
147             }
148             offlineMessageManager.deleteMessages();
149         } catch (XMPPException e) {
150             e.printStackTrace();
151         }
152     }
153 
154     @Override
155     public void onDestroy() {
156         super.onDestroy();
157         XmppManager.getInstance().colseConnection();
158         unregisterReceiver(mesageReceiver);
159     }
160 }

基本重要的就這么多,代碼附上,

鏈接:http://pan.baidu.com/s/1hs1Dg3M 密碼:s57b

可能說的不是很清楚,但是代碼里面都有

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM