1. 程式人生 > >Androidpn裡的Xmpp的理解(訊息推送)

Androidpn裡的Xmpp的理解(訊息推送)

XMPP(可擴充套件通訊和表示協議)是基於可擴充套件標記語言(XML)的協議,它用於即時訊息(IM)以及線上探測。這個協議可能最終允許因特網使用者向因特網上的其他任何人傳送即時訊息。用xmpp來實現android的push功能,感覺有點大材小用了,xmpp本身是一種即時通訊協議。

  xmpp是一種用於即時通訊的協議,使用過程有點類似於我們使用QQ的過程,其使用過程分為三步:

  1. 連線伺服器,就好像開啟QQ軟體,看程式碼:

  1. if(!mXmppManager.isConnected()) {  
  2.     ConnectionConfiguration config = new ConnectionConfiguration(mHost, mPort);  
  3.     config.setSecurityMode(SecurityMode.required);  
  4.     config.setSASLAuthenticationEnabled(false);  
  5.     config.setCompressionEnabled(false);  
  6.     XMPPConnection connection = new XMPPConnection(config);  
  7.     mXmppManager.setConnection(connection);  
  8.     try {  
  9.         connection.connect();  
  10.         Log.i(LOGTAG, "XMPP connected successfully"
    );  
  11.         /** 
  12.          * 這個就是對於通訊的xml文字進行解析的解析器,再把資訊轉換成IQ,這個相當於QQ的聊天資訊 
  13.          * 如果要用這個協議,其IQ的子類和IQProvider要進行重寫 
  14.          */
  15.         ProviderManager.getInstance().addIQProvider("notification",  
  16.                 "androidpn:iq:notification",  
  17.                 new NotificationIQProvider());  
  18.     } catch
     (XMPPException e) {  
  19.         Log.d(LOGTAG, "the connection is error ... ");  
  20.     }  
  21.     mXmppManager.runTask();  
  22. else {  
  23.     Log.i(LOGTAG, "XMPP connected already");  
  24.     mXmppManager.runTask();  
  25. }  

這一步主要是連線伺服器,還有設定一些連線的引數,還有設定連線的解析器。

  2. 如果沒有使用者,註冊新的帳號和密碼

  1. if(!mXmppManager.isRegistered()){  
  2.     final String newUsername = newRandomUUID();  
  3.     final String newPassword = newRandomUUID();  
  4.     Registration registration = new Registration();  
  5.     PacketFilter packetFilter = new AndFilter(new PacketIDFilter(  
  6.             registration.getPacketID()), new PacketTypeFilter(  
  7.             IQ.class));  
  8.     PacketListener packetListener = new PacketListener() {  
  9.         @Override
  10.         publicvoid processPacket(Packet packet) {  
  11.             // 伺服器回覆客戶端
  12.             if(packet instanceof IQ) {  
  13.                 IQ response = (IQ) packet;  
  14.                 if(response.getType() == IQ.Type.ERROR) { // 註冊失敗
  15.                     if (!response.getError().toString().contains(  
  16.                             "409")) {  
  17.                         Log.e(LOGTAG,"Unknown error while registering XMPP account! " + response.getError().getCondition());  
  18.                     }  
  19.                 } elseif(response.getType() == IQ.Type.RESULT) { // 註冊成功
  20.                     mXmppManager.setUsername(newUsername);  
  21.                     mXmppManager.setPassword(newPassword);  
  22.                     // 把使用者名稱和密碼都儲存到磁碟
  23.                     Editor editor = mSharedPrefs.edit();  
  24.                     editor.putString(Contants.XMPP_USERNAME, newUsername);  
  25.                     editor.putString(Contants.XMPP_PASSWORD, newPassword);  
  26.                     editor.commit();  
  27.                     mXmppManager.runTask();  
  28.                 }  
  29.             }  
  30.         }  
  31.     };  
  32.     // 給註冊的Packet設定Listener,因為只有等到正真註冊成功後,我們才可以交流
  33.     mConnection.addPacketListener(packetListener, packetFilter);  
  34.     registration.setType(IQ.Type.SET);  
  35.     registration.addAttribute("username", newUsername);  
  36.     registration.addAttribute("password", newPassword);  
  37.     // 向伺服器端,傳送註冊Packet包,注意其中Registration是Packet的子類
  38.     mConnection.sendPacket(registration);  
  39. else { // 已經註冊過了
  40.     mXmppManager.runTask();  
  41. }  

只要連線了伺服器了,客戶端就可以向伺服器端傳送訊息,傳送是以Packet(資料包)來進行傳送的,這個類有很多的子類,註冊的子類為Registration。

 還有要注意的是,上面的addPacketListener方法不是給所有傳送的資料包設定listener,而只是針對這次的註冊Packet。

  3. 用註冊的帳號和密碼進行登陸(像用QQ號帳進行登陸一樣)

  1. // 判斷是否已經登陸過了,是否是在登陸狀態
  2. if(!mXmppManager.isAuthenticated()) {  
  3.     try {  
  4.         mConnection.login(mUsername, mPassword, "AndroidpnClient");  
  5.         // 設定XmppConnection的監聽器
  6.         if(mXmppManager.getConnectionListener() != null) {  
  7.             mConnection.addConnectionListener(mXmppManager.getConnectionListener());  
  8.         }  
  9.         // 設定伺服器端推送的監聽器
  10.         PacketFilter packetFilter = new PacketTypeFilter(NotificationIQ.class);  
  11.         PacketListener packetListener = mXmppManager.getNotificationPacketListener();  
  12.         mConnection.addPacketListener(packetListener, packetFilter);  
  13.         mXmppManager.runTask();  
  14.     } catch (XMPPException e) {  
  15.         // 登陸失敗,應該重試 
  16.         String INVALID_CREDENTIALS_ERROR_CODE = "401";  
  17.         String errorMessage = e.getMessage();  
  18.         // 如果只是因為沒有註冊,則進行重新註冊
  19.         if (errorMessage != null && errorMessage.contains(INVALID_CREDENTIALS_ERROR_CODE)) {  
  20.             mXmppManager.reregisterAccount();   
  21.             return;  
  22.         }  
  23.         mXmppManager.startReconnectionThread();  
  24.     } catch (Exception e) { // 有可能mConnection都為空
  25.         Log.e(LOGTAG, "LoginTask.run()... other error");  
  26.         Log.e(LOGTAG, "Failed to login to xmpp server. Caused by: " + e.getMessage());  
  27.         mXmppManager.startReconnectionThread(); // 啟動重連執行緒
  28.     }  
  29. else {  
  30.     mXmppManager.runTask();  
  31. }  

這裡設定了連線的監聽器mConnection.addConnectionListener(),連線過程中有可以連線突然中斷,連接出錯等等問題,要進行監聽。

  設定伺服器推送資訊的Listener,接收到資訊後,顯示給使用者。
  如果出錯的原因是401(無效的使用者名稱和密碼,則應該進行重新註冊,再連線)

對於伺服器push過來的資訊進行處理,是在PacketListener類裡面,這個接口裡,只要實現一個方法processPacket(Packet packet),從傳過來的Packet(資料包)裡獲取自己需要的資料:

  1. publicvoid processPacket(Packet packet) {  
  2.     if(packet instanceof NotificationIQ) {  
  3.         NotificationIQ notification = (NotificationIQ) packet;  
  4.         if(notification.getChildElementXML().contains("androidpn:iq:notification")) {  
  5.             String notificationId = notification.getId();  
  6.             String notificationApiKey = notification.getApiKey();  
  7.             String notificationTitle = notification.getTitle();  
  8.             String notificationMessage = notification.getMessage();  
  9.             String notificationUri = notification.getUri();  
  10.             Intent intent = new Intent(Contants.ACTION_SHOW_NOTIFICATION);  
  11.             intent.putExtra(Contants.NOTIFICATION_ID, notificationId);  
  12.             intent.putExtra(Contants.NOTIFICATION_API_KEY,notificationApiKey);  
  13.             intent.putExtra(Contants.NOTIFICATION_TITLE,notificationTitle);  
  14.             intent.putExtra(Contants.NOTIFICATION_MESSAGE, notificationMessage);  
  15.             intent.putExtra(Contants.NOTIFICATION_URI, notificationUri);  
  16.             mXmppManager.getContext().sendBroadcast(intent);  
  17.         }  
  18.     }  
  19. }