ios 接入xmpp XMPPFramework XEP-0198: Stream Management

demo https://github.com/gwh111/testxmpp

xmpp介绍

中文官方http://wiki.jabbercn.org/%E9%A6%96%E9%A1%B5

ios库下载https://github.com/robbiehanson/XMPPFramework

重连问题https://www.jianshu.com/p/d9de0267c52a

推荐使用pod

pod 'XMPPFramework', '~> 3.7.0'
导入
import XMPPFramework      // swift
@import XMPPFramework;   //objective-c


Module 'XMPPFramework' not found

The “Swift Language Version” (SWIFT_VERSION) build setting must be set to a supported value for targets which use Swift. This setting can be set in the build settings editor.
解决办法:在pod工程中的kissxml buildsetting 搜索swift 选择kissxml 的swift版本


之后报错  Use of '@import' when modules are disabled
的话将target中的build setting 设置为enable modules 为YES 


XEP-0198: Stream Management

是xmpp的流管理协议  https://xmpp.org/extensions/xep-0198.html
开启流管理后可以保证连接断开重连是同一个流,可有效防止数据丢失

1、Client enables stream management
在建立验证之后客户端发起流的开启
客户端发起
对应的xmpp封装的方法是
[_xmppStreamManagement enableStreamManagementWithResumption:YES maxTimeout:10];

2、Server enables stream management
服务端验证流管理开启 发回给客户端

3、Server enables stream management with session resumption
    一个元素必须具备一个”h“属性。
    元素没有已定义属性。
定义:确认一条之前收到的ack元素,节是被服务器处理后再发送出去的。对于服务端的处理,我们是指服务端接管一条或多条节(如,直接处理节,将节传给本地的一个实体,比如相同服务器下的另一个客户端,或者将节发送给其他服务器的远程实体);一个节在确认被服务端处理之前,发送方都要对节负责(例如,如果没有被服务端确认处理,客户端要重发这个节或者生成一个错误)。
       收到一个元素的回执并不意味着新的节已经传送给对方,只有收到一个
元素的回执,并且包含“h”属性已经增长了,才说明这个新的节已经被处理过。
      “h”值在流管理中被启动或被请求启动时,是从零开始的。当第一个节被处理的时候,“h”值增加为1,并随着接下来新的节被处理,“h”值不断增加。在一些极端情况下,在流管理对话中被处理的节的数量,超出了无符号整型数所表示的最大数(2的32次方)XML Schema Part 2  [10],“h”值应该被置为0,而不是2的32次方。
       注意:任何给定的流,都有两个“h”值,一个被客户端用于跟踪节是否被服务端处理,另一个被服务端用于跟踪节是否被处理自客户端。当客户端向服务端发送时,客户端初始化它的“h”值为零,同样服务端发送给客户端时,也初始化它的“h”值为零(服务端会立即回复,同时设置它的计数器为零)。初始化后,客户端根据处理的节的数目不断增加“h”值,服务端也相应不断增加“h”值。

在开启流管理之后,服务端和客户端可以通过acks来相互传递消息
它的元素包括
The element has no defined attributes.

举个例子


对于元素的监听可以通过
- (void)xmppStream:(XMPPStream *)sender didSendCustomElement:(NSXMLElement *)element{
    NSLog(@"didSendCustomElement%@",element);
}
- (void)xmppStream:(XMPPStream *)sender didReceiveCustomElement:(NSXMLElement *)element{
    NSLog(@"didReceiveCustomElement%@",element);
}
这两个方法实现


参考https://blog.csdn.net/yuedong56/article/details/38120101

XEP-0198: Stream Management

h文件

#import 

@interface XMPPHelper : NSObject

//@property(nonatomic,assign) BOOL isConnecting;

+ (instancetype)getInstance;

- (BOOL)initWithUserName:(NSString *)userName andPassword:(NSString *)password andHostName:(NSString *)hostName andDomain:(NSString*)domain andHostPort:(UInt16)hostPort andInfoDic:(NSDictionary *)infoDic;

- (BOOL)connect;

- (void)disconnect;

- (BOOL)isConnected;

@end

初始化参数说明

userName 用户名

password 密码

hostName 主机名 如10.5.190.1

domain 域名 如qpmjcore-98-1/smack

hostPort 端口号 如5222

如果回调不到 xmppStreamDidConnect
把servicename中的@去掉 


类说明

@property(nonatomic,retain) XMPPJID *jid;
@property(nonatomic,retain) XMPPStream *xmppStream;
@property(nonatomic,retain) XMPPStreamManagement *xmppStreamManagement;
@property(nonatomic,retain) XMPPStreamManagementMemoryStorage *storage;
@property(nonatomic,retain) XMPPReconnect *xmppReconnect;  

XMPPJID 根据初始化数据构造的发送地址

XMPPStream 输入输出流

XMPPStreamManagement 输入输出流的管理

XMPPStreamManagementMemoryStorage 数据永久存储

XMPPReconnect 重连模块


接收消息和发送消息通过

- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message{
    NSString *messageBody = [[message elementForName:@"body"] stringValue];
//    [ShareCallback xmppPushMsg:messageBody];
//    int su=[_xmppStream supportsStreamManagement];
//    [self sendMessage:@"aaa" to:_jid];
//
//    NSXMLElement *enable = [NSXMLElement elementWithName:@"r" xmlns:@"urn:xmpp:sm:3"];
//    [[self xmppStream] sendElement:enable];
}
- (void)sendMessage:(NSString *)message to:(XMPPJID *)jid
{
    XMPPMessage* newMessage = [[XMPPMessage alloc] initWithType:@"chat" to:jid];
    [newMessage addBody:message]; //消息内容
    [_xmppStream sendElement:newMessage];
}

- (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message{
    
}


在建立连接,验证通过后开启流管理enableStreamManagementWithResumption

这里有一个XEP-0198协议 https://xmpp.org/extensions/xep-0198.html

If YES, the resume attribute will be included. E.g.

在客户端就是通过发送一个element来开启,开启后在每接收到一定消息后会通过上面提到的Acks /r和/a的标签来验证消息

可以通过

- (void)xmppStream:(XMPPStream *)sender didSendCustomElement:(NSXMLElement *)element{
    NSLog(@"didSendCustomElement%@",element);
}
- (void)xmppStream:(XMPPStream *)sender didReceiveCustomElement:(NSXMLElement *)element{
    NSLog(@"didReceiveCustomElement%@",element);
}

来查看/r和/a的标签

demo https://github.com/gwh111/testxmpp


更新:

xmpp断线重连模块

//接入断线重连模块
    _xmppReconnect = [[XMPPReconnect alloc] init];
    _xmppReconnect.reconnectTimerInterval=5;
    _xmppReconnect.reconnectDelay=0;
    [_xmppReconnect setAutoReconnect:YES];
    [_xmppReconnect activate:self.xmppStream];
    [_xmppReconnect addDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
#pragma mark - XMPPReconnectDelegate
- (void)xmppReconnect:(XMPPReconnect *)sender didDetectAccidentalDisconnect:(SCNetworkConnectionFlags)connectionFlags {
    NSLog(@"xmpp意外断开连接。");
    [ShareCallback xmppCallback:@"disconnect"];
    [self disconnect];
}
- (BOOL)xmppReconnect:(XMPPReconnect *)sender shouldAttemptAutoReconnect:(SCNetworkConnectionFlags)connectionFlags {
    return YES;
}
xmpp顶号 在另一台设备登录
- (void)xmppStream:(XMPPStream *)sender didReceiveError:(id)error
{
    NSLog(@"收到错误消息%@",error);
    if ([error isKindOfClass:[DDXMLElement class]]) {
        DDXMLElement *er=error;
        if ([er.description containsString:@"conflict"]) {
            [ShareCallback xmppCallback:@"resign"];
            [self disconnect];
            return;
        }
    }
    [ShareCallback xmppCallback:@"fail"];
    //
    
//    [ShareCallback xmppPushError:error];
}
xmpp的ping
XMPPAutoPing *xmppAutoPing =  [[XMPPAutoPing alloc] init];
    xmppAutoPing.pingInterval = 10.0;
    [xmppAutoPing activate:_xmppStream];
    [xmppAutoPing addDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
#pragma mark- XMPPAutoPingDelegate
- (void)xmppAutoPingDidReceivePong:(XMPPAutoPing *)sender{
    
}
- (void)xmppAutoPingDidTimeout:(XMPPAutoPing *)sender {
    [ShareCallback xmppCallback:@"fail"];
    [self disconnect];
}


你可能感兴趣的:(ios学习之路,ios学习相关,ios学习笔记,Objective-C)