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

風靈使發表於2018-11-12

一、常見即時通訊實現

socket

openfire+asmack

環信

信鴿

融雲

二、XMPP優勢

1. 開放性

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

2.跨平臺

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

三、XMPP協議簡介

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

四、資料格式

XMLXMPP系統架構的核心。它能表述幾乎任何一種結構化資料。特別是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的即時通訊指令的傳遞基礎,也是一個非常重要的可以被進一步利用的網路基礎協議。所以可以說,XMPPTCP傳的是XML流。

理論一大堆。。。。接下來貼程式碼

XmppManager.java

 package com.example.xmppdemo.fengzhuang;
 
 import android.util.Log;
 
 
 
 import org.jivesoftware.smack.Chat;
 import org.jivesoftware.smack.ChatManager;
 import org.jivesoftware.smack.ChatManagerListener;
 import org.jivesoftware.smack.ConnectionConfiguration;
 import org.jivesoftware.smack.MessageListener;
 import org.jivesoftware.smack.PacketCollector;
 import org.jivesoftware.smack.Roster;
 import org.jivesoftware.smack.RosterEntry;
 import org.jivesoftware.smack.SmackConfiguration;
 import org.jivesoftware.smack.XMPPConnection;
 import org.jivesoftware.smack.XMPPException;
 import org.jivesoftware.smack.filter.AndFilter;
 import org.jivesoftware.smack.filter.PacketFilter;
 import org.jivesoftware.smack.filter.PacketIDFilter;
 import org.jivesoftware.smack.filter.PacketTypeFilter;
 import org.jivesoftware.smack.packet.IQ;
 import org.jivesoftware.smack.packet.Message;
 import org.jivesoftware.smack.packet.Presence;
 import org.jivesoftware.smack.packet.Registration;
 import org.jivesoftware.smack.provider.PrivacyProvider;
 import org.jivesoftware.smack.provider.ProviderManager;
 import org.jivesoftware.smackx.Form;
 import org.jivesoftware.smackx.GroupChatInvitation;
 import org.jivesoftware.smackx.PrivateDataManager;
 import org.jivesoftware.smackx.ReportedData;
 import org.jivesoftware.smackx.bytestreams.socks5.provider.BytestreamsProvider;
 import org.jivesoftware.smackx.packet.ChatStateExtension;
 import org.jivesoftware.smackx.packet.LastActivity;
 import org.jivesoftware.smackx.packet.OfflineMessageInfo;
 import org.jivesoftware.smackx.packet.OfflineMessageRequest;
 import org.jivesoftware.smackx.packet.SharedGroupsInfo;
 import org.jivesoftware.smackx.packet.VCard;
 import org.jivesoftware.smackx.provider.AdHocCommandDataProvider;
 import org.jivesoftware.smackx.provider.DataFormProvider;
 import org.jivesoftware.smackx.provider.DelayInformationProvider;
 import org.jivesoftware.smackx.provider.DiscoverInfoProvider;
 import org.jivesoftware.smackx.provider.DiscoverItemsProvider;
 import org.jivesoftware.smackx.provider.MUCAdminProvider;
 import org.jivesoftware.smackx.provider.MUCOwnerProvider;
 import org.jivesoftware.smackx.provider.MUCUserProvider;
 import org.jivesoftware.smackx.provider.MessageEventProvider;
 import org.jivesoftware.smackx.provider.MultipleAddressesProvider;
 import org.jivesoftware.smackx.provider.RosterExchangeProvider;
 import org.jivesoftware.smackx.provider.StreamInitiationProvider;
 import org.jivesoftware.smackx.provider.VCardProvider;
 import org.jivesoftware.smackx.provider.XHTMLExtensionProvider;
 import org.jivesoftware.smackx.search.UserSearch;
 import org.jivesoftware.smackx.search.UserSearchManager;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
 /**
  * Created by Kelvin on 2016/12/12.
  */
 
 public class XmppManager {
 
     private static XmppManager xmppManager; //XmppManager的例項
 
     private XmppManager(){} //私有化構造器
 
     public static XmppManager getInstance(){
         if (xmppManager == null){
             synchronized (XmppManager.class){
                 if (xmppManager == null){
                     xmppManager = new XmppManager();
                 }
             }
         }
         return xmppManager;
     }
 
     //XmppConnection 連線物件
     private XMPPConnection xmppConnection;
 
     //將其翻譯成中文為"花名冊",用來表示一個使用者的所有好友清單以及申請加好友的使用者清單,
     // 為了便於管理,Roster中的使用者分組進行管理。
     private Roster roster;
 
     //用於接收訊息的介面
     private XmppManagerCallback xmppManagerCallback;
 
     //Debug標籤
     private final String TAG="XmppManager";
 
     /**
      * 開啟網路連線
      */
     private void openConnection(){
 
         //連線物件為空或者還沒有認證的時候(isAuthenticated()方法返回值是boolean型別,意思是是否認證)
         if (xmppConnection == null || !xmppConnection.isAuthenticated()){
             try {
                 //配置連線,(引數一:伺服器ip地址,引數二:埠號,引數三:伺服器名字)
                 ConnectionConfiguration configuration = new ConnectionConfiguration(Constant.SERVER_HOST,
                         Constant.SERVER_PORT,Constant.SERVER_NAME);
 
                 //Xmpp是否可以自動重連(客戶端掉線時是否可以重新連線)
                 configuration.setReconnectionAllowed(true);
 
                 //設定安全模式
                 configuration.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
                 //特別補充,在設定configuaration的時候對認證的設定,程式碼如下:
                 //這個屬性預設值是true,設定時得需要與伺服器那邊統一,如果不一致,就算使用者註冊成功後,
                 // 登入時也會返回 server-unavailable(503)錯誤,我們用的是ejabberd伺服器,預設設定SASL認證開啟,
                 // 所以開始我設定為false,怎麼都無法登入,最後註釋這句程式碼,成功登入:)
                 //相當於一個許可權
                 configuration.setSASLAuthenticationEnabled(false);
                 // 狀態設為離線,為了取離線訊息
                 configuration.setSendPresence(true);
                 // 配置各種Provider,如果不配置,則會無法解析資料
                 configureConnection(ProviderManager.getInstance());
                 xmppConnection = new XMPPConnection(configuration);
                 //開啟連線
                 xmppConnection.connect();
             } catch (XMPPException e) {
                 e.printStackTrace();
             }
         }
     }
 
     /**
      * 配置連線
      * @param pm
      */
     public void configureConnection(ProviderManager pm) {
         // Private Data Storage
         pm.addIQProvider("query", "jabber:iq:private", new PrivateDataManager.PrivateDataIQProvider());
         // Time
         try {
             pm.addIQProvider("query", "jabber:iq:time", Class.forName("org.jivesoftware.smackx.packet.Time"));
         } catch (ClassNotFoundException e) {
             Log.w("TestClient", "Can't load class for org.jivesoftware.smackx.packet.Time");
         }
 
         // Roster Exchange
         pm.addExtensionProvider("x", "jabber:x:roster", new RosterExchangeProvider());
         // Message Events
         pm.addExtensionProvider("x", "jabber:x:event", new MessageEventProvider());
         // Chat State
         pm.addExtensionProvider("active", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
         pm.addExtensionProvider("composing", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
         pm.addExtensionProvider("paused", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
         pm.addExtensionProvider("inactive", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
         pm.addExtensionProvider("gone", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
         // XHTML
         pm.addExtensionProvider("html", "http://jabber.org/protocol/xhtml-im", new XHTMLExtensionProvider());
         // Group Chat Invitations
         pm.addExtensionProvider("x", "jabber:x:conference", new GroupChatInvitation.Provider());
         // Service Discovery # Items
         pm.addIQProvider("query", "http://jabber.org/protocol/disco#items", new DiscoverItemsProvider());
         // Service Discovery # Info
         pm.addIQProvider("query", "http://jabber.org/protocol/disco#info", new DiscoverInfoProvider());
         // Data Forms
         pm.addExtensionProvider("x", "jabber:x:data", new DataFormProvider());
         // MUC User
         pm.addExtensionProvider("x", "http://jabber.org/protocol/muc#user", new MUCUserProvider());
         // MUC Admin
         pm.addIQProvider("query", "http://jabber.org/protocol/muc#admin", new MUCAdminProvider());
         // MUC Owner
         pm.addIQProvider("query", "http://jabber.org/protocol/muc#owner", new MUCOwnerProvider());
         // Delayed Delivery
         pm.addExtensionProvider("x", "jabber:x:delay", new DelayInformationProvider());
         // Version
         try {
             pm.addIQProvider("query", "jabber:iq:version", Class.forName("org.jivesoftware.smackx.packet.Version"));
         } catch (ClassNotFoundException e) {
             // Not sure what's happening here.
         }
         // VCard
         pm.addIQProvider("vCard", "vcard-temp", new VCardProvider());
         // Offline Message Requests
         pm.addIQProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageRequest.Provider());
         // Offline Message Indicator
         pm.addExtensionProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageInfo.Provider());
         // Last Activity
         pm.addIQProvider("query", "jabber:iq:last", new LastActivity.Provider());
         // User Search
         pm.addIQProvider("query", "jabber:iq:search", new UserSearch.Provider());
         // SharedGroupsInfo
         pm.addIQProvider("sharedgroup", "http://www.jivesoftware.org/protocol/sharedgroup",
                 new SharedGroupsInfo.Provider());
         // JEP-33: Extended Stanza Addressing
         pm.addExtensionProvider("addresses", "http://jabber.org/protocol/address", new MultipleAddressesProvider());
         // FileTransfer
         pm.addIQProvider("si", "http://jabber.org/protocol/si", new StreamInitiationProvider());
         pm.addIQProvider("query", "http://jabber.org/protocol/bytestreams", new BytestreamsProvider());
         // Privacy
         pm.addIQProvider("query", "jabber:iq:privacy", new PrivacyProvider());
         pm.addIQProvider("command", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider());
         pm.addExtensionProvider("malformed-action", "http://jabber.org/protocol/commands",
                 new AdHocCommandDataProvider.MalformedActionError());
         pm.addExtensionProvider("bad-locale", "http://jabber.org/protocol/commands",
                 new AdHocCommandDataProvider.BadLocaleError());
         pm.addExtensionProvider("bad-payload", "http://jabber.org/protocol/commands",
                 new AdHocCommandDataProvider.BadPayloadError());
         pm.addExtensionProvider("bad-sessionid", "http://jabber.org/protocol/commands",
                 new AdHocCommandDataProvider.BadSessionIDError());
         pm.addExtensionProvider("session-expired", "http://jabber.org/protocol/commands",
                 new AdHocCommandDataProvider.SessionExpiredError());
     }
 
     /**
      * 獲取連結
      * @return
      */
     public XMPPConnection getConnection(){
         if (xmppConnection == null){
             openConnection();
         }
         return  xmppConnection;
     }
 
     /**
      * 關閉連結
      */
     public void colseConnection(){
         if (xmppConnection != null && xmppConnection.isConnected()){
             xmppConnection.disconnect();
             xmppConnection = null;
         }
     }
 
     /**
      * 登陸的方法
      * @param account  賬號
      * @param psw  密碼
      * @return
      */
     public boolean login(String account,String psw){
 
         //判斷連線是否存在
         if (getConnection() == null){
             return false;
         }
 
         if (!getConnection().isAuthenticated() && getConnection().isConnected()){
             try {
                 //登陸
                 getConnection().login(account,psw);
                 //登陸之後更改使用者狀態
                 Presence presence = new Presence(Presence.Type.available);
                 //設定使用者線上
                 presence.setMode(Presence.Mode.available);
                 //向伺服器傳送狀態
                 getConnection().sendPacket(presence);
                 //接收訊息監聽
                 ChatManager chatManager = getConnection().getChatManager();
                 chatManager.addChatListener(chatManagerListener);
                 return true;
             } catch (XMPPException e) {
                 e.printStackTrace();
                 return false;
             }
         }
         return false;
     }
 
     /**
      * 聊天管理監聽器
      */
     private ChatManagerListener chatManagerListener = new ChatManagerListener(){
 
         @Override
         public void chatCreated(Chat chat, boolean b) {
             chat.addMessageListener(new MessageListener() {
                 @Override
                 public void processMessage(Chat chat, Message message) {
                     //當訊息內容為空時,直接反悔
                     if (TVUtil.isEmpty(message.getBody())){
                         return;
                     }
                     //當訊息內容不可空時,通過介面回撥的把訊息內容傳出去
                     if (xmppManagerCallback != null){
                         xmppManagerCallback.receiveMsg(message);
                     }
                 }
             });
         }
     };
 
     /**
      * 註冊使用者
      * 表示的是Info/Query(資訊與查詢),它為XMPP通訊提供請求與響應機制。它與HTTP
      * 協議的基本工作原理非常相似,允許獲取和設定查詢,與HTTP 的GET 和POST 動作類似。
      * @return
      */
     public IQ registered(String account, String psw){
 
         if (getConnection() == null){
             return null;
         }
 
         //設定註冊所需要的資訊
         Registration registration = new Registration();
         registration.setType(IQ.Type.SET);
         registration.setTo(getConnection().getServiceName());
         registration.setUsername(account);
         registration.setPassword(psw);
 
         //PacketFilter:包過濾類,過濾一些不用的包
         PacketFilter filter = new AndFilter(new PacketIDFilter(registration.getPacketID()), new PacketTypeFilter(IQ.class));
         PacketCollector collector = getConnection().createPacketCollector(filter);
         // 向伺服器端,傳送註冊Packet包,注意其中Registration是Packet的子類
         getConnection().sendPacket(registration);
         IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
         collector.cancel(); //停止請求result
         return result;
     }
 
     /**
      * 退出登陸
      */
     public void outLogin(){
         if (getConnection() == null){
             return;
         }
 
         //設定退出狀態
         Presence presence = new Presence(Presence.Type.unavailable);
         //傳送請求
         getConnection().sendPacket(presence);
         //關閉連線
         colseConnection();
     }
 
     /**
      * 獲取使用者資訊
      * @param user
      * @return
      */
     public VCard getUserInfo(String user){
         VCard vCard = null;
         try {
             vCard = new VCard();
             // 加入這句程式碼,解決No VCard for
             ProviderManager.getInstance().addIQProvider("vCard", "vcard-temp", new VCardProvider());
             if (user == null){
                 vCard.load(getConnection());
             }else{
                 vCard.load(getConnection(), user + "@" + Constant.SERVER_NAME);
             }
         } catch (XMPPException e) {
             e.printStackTrace();
         }
         return vCard;
     }
 
     /**
      * 獲取xmpp好友列表
      * 注意:這裡的User是在Xmpp包下的User
      */
     public List<User> getFriendList() {
         // Roster:花名冊
         if (roster == null) {
             roster = getConnection().getRoster();
         }
         List<User> userList = new ArrayList<User>();
         Collection<RosterEntry> entries = roster.getEntries();
         for(RosterEntry entry : entries){
             userList.add(new User(getUsername(entry.getUser()),entry.getType()));
         }
         Collections.sort(userList,new PingyinComparator());
         return userList;
     }
 
     /**
      * 通過jid獲得username
      * @param fullUsername
      * @return
      */
     public static String getUsername(String fullUsername){
         return fullUsername.split("@")[0];
     }
 
     /**
      * 搜尋使用者
      * @param userName
      * @return
      * @throws XMPPException
      */
     public List<String> searchUser(String userName) {
         if (getConnection() == null){
             return null;
         }
         List<String> userList = new ArrayList<>();
         try {
             UserSearchManager search = new UserSearchManager(getConnection());
             Form searchForm = search.getSearchForm("search."+ getConnection().getServiceName());
             Form answerForm = searchForm.createAnswerForm();
             answerForm.setAnswer("Username", true);
             answerForm.setAnswer("search", userName.trim());
             ReportedData data = search.getSearchResults(answerForm,"search." + xmppConnection.getServiceName());
             Iterator<ReportedData.Row> it = data.getRows();
             ReportedData.Row row = null;
             while (it.hasNext()) {
                 row = it.next();
                 userList.add(row.getValues("Username").next().toString());
             }
         } catch (XMPPException e) {
             e.printStackTrace();
         }
         return userList;
     }
 
     /**
      * 新增好友(無分組)
      * @param userName
      * @return
      */
     public boolean addFriend(String userName) {
         if (getConnection() == null)
             return false;
         try {
             getConnection().getRoster().createEntry(getFullUsername(userName), getFullUsername(userName), null);
             return true;
         } catch (Exception e) {
             e.printStackTrace();
             return false;
         }
     }
 
     /**
      * 通過username獲得jid
      * @param username
      * @return
      */
     public static String getFullUsername(String username){
         return username + "@" + Constant.SERVER_NAME;
     }
 
     /**
      * 建立聊天
      * @param toUser
      * @return
      */
     public Chat createChat(String toUser){
         ChatManager chatManager = getConnection().getChatManager();
         Chat newchat = chatManager.createChat(toUser + "@"+ Constant.SERVER_NAME, null);
         return newchat;
     }
 
     /**
      * 傳送文字訊息
      * @param message
      */
     public void sendMsg(Chat chat, String message) {
         try {
             chat.sendMessage(message);
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
 
     /**
      * 介面回撥
      */
     public interface XmppManagerCallback {
         //接收訊息回撥函式
         void receiveMsg(Message message);
     }
 
     /**
      * 設定介面的方法
      * @param xmppManagerCallback 介面物件
      */
     public void setXmppManagerCallback(XmppManagerCallback xmppManagerCallback) {
         this.xmppManagerCallback = xmppManagerCallback;
     }
 }

這裡面封裝了所有的方法

ChatMsg.java

 package com.example.xmppdemo.fengzhuang;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 /**
  * 
  * 描述(請用一句話描述這個內容)
  */
 
 public class ChatMsg implements Parcelable {
 
     private String sender; // 傳送者
     private String body; // 傳送的訊息
 
     public String getSender() {
         return sender;
     }
 
     public void setSender(String sender) {
         this.sender = sender;
     }
 
     public String getBody() {
         return body;
     }
 
     public void setBody(String body) {
         this.body = body;
     }
 
     public static final Creator<ChatMsg> CREATOR = new Creator<ChatMsg>() {
         @Override
         public ChatMsg createFromParcel(Parcel in) {
             ChatMsg chatMsg = new ChatMsg();
             chatMsg.sender = in.readString();
             chatMsg.body = in.readString();
             return chatMsg;
         }
 
         @Override
         public ChatMsg[] newArray(int size) {
             return null;
         }
     };
 
     @Override
     public int describeContents() {
         return 0;
     }
 
     @Override
     public void writeToParcel(Parcel parcel, int i) {
         parcel.writeString(sender);
         parcel.writeString(body);
     }
 }

還有一個

ChatService.java

package com.example.xmppdemo.service;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.support.annotation.Nullable;


import com.example.xmppdemo.ChatActivity;
import com.example.xmppdemo.R;
import com.example.xmppdemo.fengzhuang.ChatMsg;
import com.example.xmppdemo.fengzhuang.Constant;
import com.example.xmppdemo.fengzhuang.XmppManager;

import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.OfflineMessageManager;

import java.util.ArrayList;
import java.util.Iterator;

/**
 31  * 描述(請用一句話描述這個內容)
 */
public class ChatService extends Service implements XmppManager.XmppManagerCallback {

    //接收到的訊息集合,包括兩種訊息: 1,不在對話方塊介面的訊息 2,離線訊息
    private ArrayList<ChatMsg> messageList = new ArrayList<>();
    private MesageBroadcastReceiver mesageReceiver;

    @Override
    public void onCreate() {
        XmppManager.getInstance().setXmppManagerCallback(this);
        //註冊訊息接收廣播
        IntentFilter filter = new IntentFilter(Constant.INTENT_ACTION_MESSAGE_RECEIVE);
        mesageReceiver = new MesageBroadcastReceiver();
        registerReceiver(mesageReceiver, filter);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void receiveMsg(Message message) {
        ChatMsg chatMsg = new ChatMsg();

        chatMsg.setSender(message.getFrom());
        chatMsg.setBody(message.getBody());
        sendReceiverMsgBroadCast(chatMsg);
    }
    /**
     * 傳送廣播的方法
     * @param
     */
    private void sendReceiverMsgBroadCast(ChatMsg chatMsg){
        Intent intent = new Intent();
        intent.setAction(Constant.INTENT_ACTION_MESSAGE_RECEIVE);
        intent.putExtra("message", chatMsg);
        /**
         * MesageBroadcastReceiver指定為最後的接受者,Activity.RESULT_CANCELED指定初始的結果碼,
         * 如果ChatActivity中的廣播接收者處理了這條廣播,則結果碼會在ChatActivity中被更改為Activity.RESULT_OK,
         * 反之,ChatActivity中的廣播接收者沒有處理,則結果碼仍然為Activity.RESULT_CANCELED
         */
        sendOrderedBroadcast(intent,null,mesageReceiver,null, Activity.RESULT_CANCELED,null,null);
    }
    /**
     * 訊息廣播
     */
    private class MesageBroadcastReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            ChatMsg chatMsg = intent.getParcelableExtra("message");
            int resultCode = getResultCode();
            if (isOrderedBroadcast()){  //判斷是否有下一個廣播,true為是 false為無

                if (resultCode != Activity.RESULT_OK){
                    showMsgNotice(chatMsg);
                }
            }
        }
    }

    /**
     * 顯示訊息通知
     * @param chatMsg 訊息類
     */
    private void showMsgNotice(ChatMsg chatMsg){
        messageList.add(chatMsg);  //把訊息實體加入到集合中
        //獲取通知服務
        NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        //取消所有
        nm.cancelAll();
        //建立訊息
       /* Notification notification = new Notification(R.drawable.ic_launcher
                ,"您有"+messageList.size()+"條新訊息", System.currentTimeMillis());
        notification.flags = Notification.FLAG_AUTO_CANCEL;
        notification.sound= Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.ms);
        Intent intent = new Intent(this, ChatActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra("from", "notification");
        intent.putParcelableArrayListExtra("messageList", messageList);
        PendingIntent contentIntent = PendingIntent.getActivity(this, R.string.app_name, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        notification.setLatestEventInfo(this, chatMsg.getSender().split("@")[0], chatMsg.getBody(), contentIntent);
        nm.notify(0, notification);*/

        Notification.Builder builder = new Notification.Builder(this);
        builder.setContentText("微信通知"); //設定通知的標題
        builder.setSmallIcon(R.drawable.search_icon); //設定通知的小圖示
        builder.setContentText("您有"+messageList.size()+"條新訊息"); //寫入通知內容
//        builder.setSound(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.ms));
        Intent intent = new Intent(this, ChatActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra("from", "notification");
        intent.putParcelableArrayListExtra("messageList", messageList);
        PendingIntent contentIntent = PendingIntent.getActivity(this, R.string.app_name, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(contentIntent);
        //獲得通知
        Notification notification = builder.getNotification();
        nm.notify(0, notification);
    }

    /**
     * 獲取離線訊息
     */
    public void getOfflineMessage() {
        OfflineMessageManager offlineMessageManager = new OfflineMessageManager(XmppManager.getInstance().getConnection());
        try {
            Iterator<Message> it = offlineMessageManager.getMessages();
            while (it.hasNext()) {
                Message message = it.next();
                ChatMsg chatMsg = new ChatMsg();
                chatMsg.setSender(message.getFrom());
                chatMsg.setBody(message.getBody());
                sendReceiverMsgBroadCast(chatMsg);
            }
            offlineMessageManager.deleteMessages();
        } catch (XMPPException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        XmppManager.getInstance().colseConnection();
        unregisterReceiver(mesageReceiver);
    }
}

基本重要的就這麼多,程式碼附上,

連結:http://pan.baidu.com/s/1hs1Dg3M 密碼:s57b

可能說的不是很清楚,但是程式碼裡面都有

能看到的程式碼不是自己的,自己寫出來的才是自己的

相關文章