一、常見即時通訊實現
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
可能說的不是很清楚,但是代碼里面都有