XMPPFramework核心類介紹


XMPPFramework結構

在進入下一步之前,先給大家講講XMPPFramework的目錄結構,以便新手們更容易讀懂文章。我們來看看下圖:

雖然這里有很多個目錄,但是我們在開發中基本只關心Core和Extensions這兩個目錄下的類。各個目錄主要用來干嘛的?

  • Authentication:這一看名字就知道與授權驗證相關的。
  • Categories:主要是一些擴展,尤其是NSXMLElement+XMPP擴展是必備的。
  • Core:這里是XMPP的核心文件目錄,我們最主要的目光還是要放在這個目錄上。
  • Extensions:這個目錄是XMPP的擴展,用於擴展各種協議和各種獨立的功能,其下每個子目錄都是對應的一個單獨的子功能。我們最常用到的功能有Reconnect、Roster、CoreDataStorage等。
  • Utilities:都是輔助類,我們開發者不用關心這里。
  • Vendor:這個目錄是XMPP所引用的第三方類庫,如CocoaAsyncSocket、KissXML等,我們也不用關心這里。

閱讀到此,對XMPPFramework的結構有所了解了吧!

概念知識

登錄需要到賬號,而所謂的賬號其實就是用戶唯一標識符(JID),在XMPP中使用XMPPJID類來表示。那么,用戶唯一標識(JID)有什么組成?

JID一般由三部分構成:用戶名,域名和資源名,格式為user@domain/resource,例如: test@example.com /Anthony。對應於XMPPJID類中的三個屬性user、domain、resource。 

如果沒有設置主機名(HOST),則使用JID的域名(domain)作為主機名,而端口號是可選的,默認是5222,一般也沒有必要改動它。

XMPPStream類

我們要與服務器連接,就必須通過XMPPStream類了,它提供了很多的API和屬性設置,通過socket來實現的。我們看到Verdor目錄了嗎,包含了CocoaAsyncSocket這個非常有名的socket編程庫。XMPPStream類還遵守並實現了GCDAsyncSocketDelegate代理,用於客戶端與服務器交互。

 
@interface XMPPStream : NSObject <GCDAsyncSocketDelegate>   

當我們創建XMPPStream對象后,我們需要設置代理,才能回調我們的代理方法,這個是支持multicast delegate,也就是說對於一個XMPPStream對象,可以設置多個代理對象,其中協議是XMPPStreamDelegate:

 
- (void)addDelegate:(id)delegatedelegateQueue:(dispatch_queue_t)delegateQueue;   

而當我們不希望某個XMPPStream對象繼續接收到代理回調時,我們通過這樣的方式來移除代理:

 
- (void)removeDelegate:(id)delegatedelegateQueue:(dispatch_queue_t)delegateQueue; - (void)removeDelegate:(id)delegate;   

接下來,我們要設置主機和端口,通過設置這兩個屬性:

 
/** * The server's hostname that should be used to make the TCP connection. * 注釋太長,簡單說就是主機。這個屬性是可選設置的,如果沒有設置主機,默認會使用domain */ @property (readwrite, copy) NSString *hostName;   /** * The port the xmpp server is running on. * If you do not explicitly set the port, the default port will be used. * If you set the port to zero, the default port will be used. * * The default port is 5222. **/ @property (readwrite, assign) UInt16 hostPort;   

XMPPStream有XMPPJID類對象作為屬性,標識用戶,因為我們后續很多操作都需要到myJID:

 
@property (readwrite, copy) XMPPJID *myJID;   

而管理用戶在線狀態的就交由XMPPPresence類了,它同樣被作為XMPPStream的屬性,組合到XMPPStream中,后續很多關於用戶的操作是需要到處理用戶狀態的:

 
/** * Represents the last sent presence element concerning the presence of myJID on the server. * In other words, it represents the presence as others see us. * * This excludes presence elements sent concerning subscriptions, MUC rooms, etc. * * @see resendMyPresence **/ @property (strong, readonly) XMPPPresence *myPresence;   

XMPPStreamDelegate

這個協議是非常關鍵的,我們的很多主要操作都集中在這個協議的代理回調上。它分為好幾種類型的代理API,比如授權的、注冊的、安全的等:

 
@protocol XMPPStreamDelegate
@optional // 將要與服務器連接是回調 - (void)xmppStreamWillConnect:(XMPPStream *)sender;   // 當tcp socket已經與遠程主機連接上時會回調此代理方法 // 若App要求在后台運行,需要設置XMPPStream's enableBackgroundingOnSocket屬性 - (void)xmppStream:(XMPPStream *)sendersocketDidConnect:(GCDAsyncSocket *)socket;   // 當TCP與服務器建立連接后會回調此代理方法 - (void)xmppStreamDidStartNegotiation:(XMPPStream *)sender;   // TLS傳輸層協議在將要驗證安全設置時會回調 // 參數settings會被傳到startTLS // 此方法可以不實現的,若選擇實現它,可以可以在 // 若服務端使用自簽名的證書,需要在settings中添加GCDAsyncSocketManuallyEvaluateTrust=YES // - (void)xmppStream:(XMPPStream *)senderwillSecureWithSettings:(NSMutableDictionary *)settings;   // 上面的方法執行后,下一步就會執行這個代理回調 // 用於在TCP握手時手動驗證是否受信任 - (void)xmppStream:(XMPPStream *)senderdidReceiveTrust:(SecTrustRef)trust                                       completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler;   // 當stream通過了SSL/TLS的安全驗證時,會回調此代理方法 - (void)xmppStreamDidSecure:(XMPPStream *)sender;   // 當XML流已經完全打開時(也就是與服務器的連接完成時)會回調此代理方法。此時可以安全地與服務器通信了。 - (void)xmppStreamDidConnect:(XMPPStream *)sender;   // 注冊新用戶成功時的回調 - (void)xmppStreamDidRegister:(XMPPStream *)sender;   // 注冊新用戶失敗時的回調 - (void)xmppStream:(XMPPStream *)senderdidNotRegister:(NSXMLElement *)error;   // 授權通過時的回調,也就是登錄成功的回調 - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender;   // 授權失敗時的回調,也就是登錄失敗時的回調 - (void)xmppStream:(XMPPStream *)senderdidNotAuthenticate:(NSXMLElement *)error;   // 將要綁定JID resource時的回調,這是授權程序的標准部分,當驗證JID用戶名通過時,下一步就驗證resource。若使用標准綁定處理,return nil或者不要實現此方法 - (id <XMPPCustomBinding>)xmppStreamWillBind:(XMPPStream *)sender;   // 如果服務器出現resouce沖突而導致不允許resource選擇時,會回調此代理方法。返回指定的resource或者返回nil讓服務器自動幫助我們來選擇。一般不用實現它。 - (NSString *)xmppStream:(XMPPStream *)senderalternativeResourceForConflictingResource:(NSString *)conflictingResource;   // 將要發送IQ(消息查詢)時的回調 - (XMPPIQ *)xmppStream:(XMPPStream *)senderwillReceiveIQ:(XMPPIQ *)iq; // 將要接收到消息時的回調 - (XMPPMessage *)xmppStream:(XMPPStream *)senderwillReceiveMessage:(XMPPMessage *)message; // 將要接收到用戶在線狀態時的回調 - (XMPPPresence *)xmppStream:(XMPPStream *)senderwillReceivePresence:(XMPPPresence *)presence;   /** * This method is called if any of the xmppStream:willReceiveX: methods filter the incoming stanza. * * It may be useful for some extensions to know that something was received, * even if it was filtered for some reason. **/ // 當xmppStream:willReceiveX:(也就是前面這三個API回調后),過濾了stanza,會回調此代理方法。 // 通過實現此代理方法,可以知道被過濾的原因,有一定的幫助。 - (void)xmppStreamDidFilterStanza:(XMPPStream *)sender;   // 在接收了IQ(消息查詢后)會回調此代理方法 - (BOOL)xmppStream:(XMPPStream *)senderdidReceiveIQ:(XMPPIQ *)iq; // 在接收了消息后會回調此代理方法 - (void)xmppStream:(XMPPStream *)senderdidReceiveMessage:(XMPPMessage *)message; // 在接收了用戶在線狀態消息后會回調此代理方法 - (void)xmppStream:(XMPPStream *)senderdidReceivePresence:(XMPPPresence *)presence;   // 在接收IQ/messag、presence出錯時,會回調此代理方法 - (void)xmppStream:(XMPPStream *)senderdidReceiveError:(NSXMLElement *)error;   // 將要發送IQ(消息查詢時)時會回調此代理方法 - (XMPPIQ *)xmppStream:(XMPPStream *)senderwillSendIQ:(XMPPIQ *)iq; // 在將要發送消息時,會回調此代理方法 - (XMPPMessage *)xmppStream:(XMPPStream *)senderwillSendMessage:(XMPPMessage *)message; // 在將要發送用戶在線狀態信息時,會回調此方法 - (XMPPPresence *)xmppStream:(XMPPStream *)senderwillSendPresence:(XMPPPresence *)presence;   // 在發送IQ(消息查詢)成功后會回調此代理方法 - (void)xmppStream:(XMPPStream *)senderdidSendIQ:(XMPPIQ *)iq; // 在發送消息成功后,會回調此代理方法 - (void)xmppStream:(XMPPStream *)senderdidSendMessage:(XMPPMessage *)message; // 在發送用戶在線狀態信息成功后,會回調此方法 - (void)xmppStream:(XMPPStream *)senderdidSendPresence:(XMPPPresence *)presence;   // 在發送IQ(消息查詢)失敗后會回調此代理方法 - (void)xmppStream:(XMPPStream *)senderdidFailToSendIQ:(XMPPIQ *)iqerror:(NSError *)error; // 在發送消息失敗后,會回調此代理方法 - (void)xmppStream:(XMPPStream *)senderdidFailToSendMessage:(XMPPMessage *)messageerror:(NSError *)error; // 在發送用戶在線狀態失敗信息后,會回調此方法 - (void)xmppStream:(XMPPStream *)senderdidFailToSendPresence:(XMPPPresence *)presenceerror:(NSError *)error;   // 當修改了JID信息時,會回調此代理方法 - (void)xmppStreamDidChangeMyJID:(XMPPStream *)xmppStream;   // 當Stream被告知與服務器斷開連接時會回調此代理方法 - (void)xmppStreamWasToldToDisconnect:(XMPPStream *)sender;   // 當發送了</stream:stream>節點時,會回調此代理方法 - (void)xmppStreamDidSendClosingStreamStanza:(XMPPStream *)sender;   // 連接超時時會回調此代理方法 - (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender;   // 當與服務器斷開連接后,會回調此代理方法 - (void)xmppStreamDidDisconnect:(XMPPStream *)senderwithError:(NSError *)error;   // p2p類型相關的 - (void)xmppStream:(XMPPStream *)senderdidReceiveP2PFeatures:(NSXMLElement *)streamFeatures; - (void)xmppStream:(XMPPStream *)senderwillSendP2PFeatures:(NSXMLElement *)streamFeatures;     - (void)xmppStream:(XMPPStream *)senderdidRegisterModule:(id)module; - (void)xmppStream:(XMPPStream *)senderwillUnregisterModule:(id)module;   // 當發送非XMPP元素節點時,會回調此代理方法。也就是說,如果發送的element不是 // <iq>, <message> 或者 <presence>,那么就會回調此代理方法 - (void)xmppStream:(XMPPStream *)senderdidSendCustomElement:(NSXMLElement *)element; // 當接收到非XMPP元素節點時,會回調此代理方法。也就是說,如果接收的element不是 // <iq>, <message> 或者 <presence>,那么就會回調此代理方法 - (void)xmppStream:(XMPPStream *)senderdidReceiveCustomElement:(NSXMLElement *)element;   

到此,也就理解了XMPPStream五五六六了吧!!!

XMPPIQ

消息查詢(IQ)就是通過此類來處理的了。XMPP給我們提供了IQ方便創建的類,用於快速生成XML數據。若頭文件聲明如下:

 
@interfaceXMPPIQ: XMPPElement
 
// 生成iq
+ (XMPPIQ *)iq; + (XMPPIQ *)iqWithType:(NSString *)type; + (XMPPIQ *)iqWithType:(NSString *)typeto:(XMPPJID *)jid; + (XMPPIQ *)iqWithType:(NSString *)typeto:(XMPPJID *)jidelementID:(NSString *)eid; + (XMPPIQ *)iqWithType:(NSString *)typeto:(XMPPJID *)jidelementID:(NSString *)eidchild:(NSXMLElement *)childElement; + (XMPPIQ *)iqWithType:(NSString *)typeelementID:(NSString *)eid; + (XMPPIQ *)iqWithType:(NSString *)typeelementID:(NSString *)eidchild:(NSXMLElement *)childElement; + (XMPPIQ *)iqWithType:(NSString *)typechild:(NSXMLElement *)childElement;   - (id)init; - (id)initWithType:(NSString *)type; - (id)initWithType:(NSString *)typeto:(XMPPJID *)jid; - (id)initWithType:(NSString *)typeto:(XMPPJID *)jidelementID:(NSString *)eid; - (id)initWithType:(NSString *)typeto:(XMPPJID *)jidelementID:(NSString *)eidchild:(NSXMLElement *)childElement; - (id)initWithType:(NSString *)typeelementID:(NSString *)eid; - (id)initWithType:(NSString *)typeelementID:(NSString *)eidchild:(NSXMLElement *)childElement; - (id)initWithType:(NSString *)typechild:(NSXMLElement *)childElement;   // IQ類型,看下面的說明 - (NSString *)type;   // 判斷type類型 - (BOOL)isGetIQ; - (BOOL)isSetIQ; - (BOOL)isResultIQ; - (BOOL)isErrorIQ;   // 當type為get或者set時,這個API是很有用的,用於指定是否要求有響應 - (BOOL)requiresResponse;   - (NSXMLElement *)childElement; - (NSXMLElement *)childErrorElement;   @end   

IQ是一種請求/響應機制,從一個實體從發送請求,另外一個實體接受請求並進行響應。例如,client在stream的上下文中插入一個元素,向Server請求得到自己的好友列表,Server返回一個,里面是請求的結果。

<type></type>有以下類別(可選設置如:<type>get</type>):

  • get :獲取當前域值。類似於http get方法。
  • set :設置或替換get查詢的值。類似於http put方法。
  • result :說明成功的響應了先前的查詢。類似於http狀態碼200。
  • error: 查詢和響應中出現的錯誤。

下面是一個IQ例子:

 
<iqfrom="huangyibiao@welcome.com/ios"  
    id="xxxxxxx"     to="biaoge@welcome.com/ios"       type="get">   <queryxmlns="jabber:iq:roster"/> </iq>   

XMPPPresence

這個類代表節點,我們通過此類提供的方法來生成XML數據。它代表用戶在線狀態,它的頭文件內容很少的:

 
@interfaceXMPPPresence: XMPPElement
 
// Converts an NSXMLElement to an XMPPPresence element in place (no memory allocations or copying)
+ (XMPPPresence *)presenceFromElement:(NSXMLElement *)element;   + (XMPPPresence *)presence; + (XMPPPresence *)presenceWithType:(NSString *)type; // type:用戶在線狀態,看下面的講解 // to:接收方的JID + (XMPPPresence *)presenceWithType:(NSString *)typeto:(XMPPJID *)to;   - (id)init; - (id)initWithType:(NSString *)type;   // type:用戶在線狀態,看下面的講解 // to:接收方的JID - (id)initWithType:(NSString *)typeto:(XMPPJID *)to;   - (NSString *)type;   - (NSString *)show; - (NSString *)status;   - (int)priority;   - (int)intShow;   - (BOOL)isErrorPresence;   @end   

presence用來表明用戶的狀態,如:online、away、dnd(請勿打擾)等。當改變自己的狀態時,就會在stream的上下文中插入一個Presence元素,來表明自身的狀態。要想接受presence消息,必須經過一個叫做presence subscription的授權過程。

<type></type>有以下類別(可選設置如:<type>subscribe</type>):

  • subscribe:訂閱其他用戶的狀態
  • probe:請求獲取其他用戶的狀態
  • unavailable:不可用,離線(offline)狀態

<show></show>節點有以下類別,如<show>dnd</show>:

  • chat:聊天中
  • away:暫時離開
  • xa:eXtend Away,長時間離開
  • dnd:勿打擾

<status></status>節點

這個節點表示狀態信息,內容比較自由,幾乎可以是所有類型的內容。常用來表示用戶當前心情,活動,聽的歌曲,看的視頻,所在的聊天室,訪問的網頁,玩的游戲等等。

<priority></priority>節點

范圍-128~127。高優先級的resource能接受發送到bare JID的消息,低優先級的resource不能。優先級為負數的resource不能收到發送到bare JID的消息。

發送一個用戶在線狀態的例子:

 
<presencefrom="alice@wonderland.lit/pda">   <show>dnd</show>   <status>瀏覽器搜索:標哥的技術博客,或者直接訪問www.henishuo.com</status> </presence>   

XMPPMessage

XMPPMessage是XMPP框架給我們提供的,方便用於生成XML消息的數據,其頭文件如下:

 
@interfaceXMPPMessage: XMPPElement
 
+ (XMPPMessage *)messageFromElement:(NSXMLElement *)element;   + (XMPPMessage *)message; + (XMPPMessage *)messageWithType:(NSString *)type; + (XMPPMessage *)messageWithType:(NSString *)typeto:(XMPPJID *)to; + (XMPPMessage *)messageWithType:(NSString *)typeto:(XMPPJID *)jidelementID:(NSString *)eid; + (XMPPMessage *)messageWithType:(NSString *)typeto:(XMPPJID *)jidelementID:(NSString *)eidchild:(NSXMLElement *)childElement; + (XMPPMessage *)messageWithType:(NSString *)typeelementID:(NSString *)eid; + (XMPPMessage *)messageWithType:(NSString *)typeelementID:(NSString *)eidchild:(NSXMLElement *)childElement; + (XMPPMessage *)messageWithType:(NSString *)typechild:(NSXMLElement *)childElement;   - (id)init; - (id)initWithType:(NSString *)type; - (id)initWithType:(NSString *)typeto:(XMPPJID *)to; - (id)initWithType:(NSString *)typeto:(XMPPJID *)jidelementID:(NSString *)eid; - (id)initWithType:(NSString *)typeto:(XMPPJID *)jidelementID:(NSString *)eidchild:(NSXMLElement *)childElement; - (id)initWithType:(NSString *)typeelementID:(NSString *)eid; - (id)initWithType:(NSString *)typeelementID:(NSString *)eidchild:(NSXMLElement *)childElement; - (id)initWithType:(NSString *)typechild:(NSXMLElement *)childElement;   - (NSString *)type; - (NSString *)subject; - (NSString *)body; - (NSString *)bodyForLanguage:(NSString *)language; - (NSString *)thread;   - (void)addSubject:(NSString *)subject; - (void)addBody:(NSString *)body; - (void)addBody:(NSString *)bodywithLanguage:(NSString *)language; - (void)addThread:(NSString *)thread;   - (BOOL)isChatMessage; - (BOOL)isChatMessageWithBody; - (BOOL)isErrorMessage; - (BOOL)isMessageWithBody;   - (NSError *)errorMessage;   @end   

message是一種基本 推送 消息方法,它不要求響應。主要用於IM、groupChat、alert和notification之類的應用中。 

<type></type>有以下類別(可選設置如:<type> chat</type>):

  • normal:類似於email,主要特點是不要求響應;
  • chat:類似於qq里的好友即時聊天,主要特點是實時通訊;
  • groupchat:類似於聊天室里的群聊;
  • headline:用於發送alert和notification;
  • error:如果發送message出錯,發現錯誤的實體會用這個類別來通知發送者出錯了;

<body></body>節點

所要發送的內容就放在body節點下

消息節點的例子:

 
<messageto="lily@jabber.org/contact" type="chat">     <body>您好?您的博客名是叫標哥的技術博客嗎?地址是http://www.henishuo.com嗎?</body> </message>   

 


免責聲明!

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



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