XMPPFramework iOS开发(三)XMPP工具类

XMPPFramework iOS开发(三)XMPP工具类

一、注册登录的步骤

为了方便登录、注册功能的编写,以及为了代码的可读性考虑,新建XMPPTool类,把XMPP框架的使用写成一个工具类。其中注册、注销、登录都会和服务器进行通信,它们的实现步骤如下。

登录的步骤分为4步:
1. 初始化XMPPStream (与服务器交互的核心类)
2. 连接服务器
3. 发送密码
4. 发送在线消息(默认登录成功是不在线的)

注册的步骤分为3步:
1. 初始化XMPPStream
2. 连接服务器
3. 注册(发送注册密码)

注销的步骤分2步:
1. 发送离线消息
2. 断开连接

因此,根据以上对功能的分析,可以得出XMPP的工具类需要有的方法如下:
1. 首先,需要些6个私有方法,完成初始化XMPPStream、连接服务器、发送密码、发送在线消息、发送离线消息、断开连接的功能;
2. 之后,需要有3个公共方法,完成注册、登录、注销的功能,方便之后需要用到时随时调用;
3. 最后,需要实现XMPP的5个代理方法,分别是连接成功、登录成功、登录失败、注册成功、注册失败。

属性方面,因为要告诉用户连接服务器、登录、注册的结果,这个结果返回的方式最好用block;因为注册、登录操作都需要连接服务器,因此应该设置一个BOOL型变量,判断当前操作是登录还是注册;还有域名、端口等属性就不一一细讲了。

二、方法的声明

2.1 定义单例的方法

新建头文件Singleton

// .h
#define singleton_interface(class) + (instancetype)shared##class;

// .m
#define singleton_implementation(class) \ static class *_instance; \ \ + (id)allocWithZone:(struct _NSZone *)zone \ { \     static dispatch_once_t onceToken; \     dispatch_once(&onceToken, ^{ \         _instance = [super allocWithZone:zone]; \     }); \ \     return _instance; \ } \ \ + (instancetype)shared##class \ { \     if (_instance == nil) { \         _instance = [[class alloc] init]; \     } \ \     return _instance; \ }

其实不是很懂上面这个头文件的写法,只知道导入该文件之后,单例模式的编写就变得很简单,下面会用到。

2.2 WCXMPPTool.h

注册、登录都需要连接服务器,且连接时都需要发送一个JID,JID可以认为是用户的帐号,因此在XMPPTool中需要定义一个属性,来判断当前操作是注册还是登录。同时,需要定义用户注册、登录的公共方法,并返回结果,返回结果的方法应使用block。且XMPPTool应该是单例的,这里定义单例的方法是使用上面那个类。

typedef enum{
    XMPPResultTypeLoginSuccess,
    XMPPResultTypeLoginFailure,
    XMPPResultTypeRegisterSuccess,
    XMPPResultTypeRegisterFailure
}XMPPResultType;

typedef void (^XMPPResultBlock)(XMPPResultType);


@interface WCXMPPTool : NSObject

singleton_interface(WCXMPPTool) //单例


//与服务器交互的核心类
@property (nonatomic, strong, readonly) XMPPStream *xmppStream;

/** * 判断执行的登录还是注册操作, YES为注册, NO为登录 */
@property (nonatomic, assign, getter=isRegisterOperation) BOOL registerOperation;

/** * 用户登录 */
- (void)xmppLogin:(XMPPResultBlock)resultBlock;

/** * 用户注销 */
- (void)xmppLogout;

/** * 用户注册 */
- (void)xmppRegister:(XMPPResultBlock)resultBlock;

/** * 服务器域名 */
@property (nonatomic, copy, readonly) NSString *domain;

/** * 服务器IP */
@property (nonatomic, copy, readonly) NSString *host;


@property (nonatomic, assign) int port;

@end

2.3 私有方法

@interface WCXMPPTool () <XMPPStreamDelegate>
{
    //结果回调block
    XMPPResultBlock _resultBlock;   
}

/** * 1.初始化服务器 */
- (void)setupStream;

/** * 2.连接服务器 */
- (void)connectToHost;

/** * 3.发送密码 */
- (void)sendPwdToHost;

/** * 4.发送在线信息 */
- (void)sendOnline;


/** * 5.发送离线消息 */
- (void)sendOffLine;

/** * 6.断开连接 */
- (void)disconnectFromHost;

@end

@implementation WCXMPPTool

singleton_implementation(WCXMPPTool)

三、私有方法

3.1 初始化XMPPStream

#pragma mark 私有方法
- (void)setupStream
{
    _xmppStream = [[XMPPStream alloc] init];
    //所有代理方法都在子线程中执行
    [_xmppStream addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
}

3.2 连接服务器

- (void)connectToHost
{
    if (!_xmppStream) {
        [self setupStream];
    }

    //设置用户登录的JID,resource为用户登录客户端的设备类型
    XMPPJID *myJid = nil;
    WCUser *user = [WCUser shareUser];
    if (self.isRegisterOperation) {
        NSString *registerAccount = [WCUser shareUser].registerAccount;
        myJid = [XMPPJID jidWithUser:registerAccount domain:user.domain resource:@"iphone"];
    }else {
        NSString *loginAccount = [WCUser shareUser].loginAccount;
        myJid = [XMPPJID jidWithUser:loginAccount domain:user.domain resource:@"iphone"];
    }

    _xmppStream.myJID = myJid;

    //设置主机地址
    _xmppStream.hostName = user.host;
    //设置主机端口号,可以不设置,默认为5222
    _xmppStream.hostPort = user.port;

    //发起连接,缺少必要参数就会连接失败(比如没有JID)
    NSError *error = nil;
    [_xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&error];
    if (!error) {
        ZHLog(@"连接成功");
    }else {
        ZHLog(@"连接失败,%@",error);
    }
}

3.3 发送密码

- (void)sendPwdToHost
{
    NSError *error = nil;
    NSString *loginPwd = [WCUser shareUser].loginPwd;
    [_xmppStream authenticateWithPassword:loginPwd error:&error];
    if (!error) {
        ZHLog(@"登录成功");
    }else {
        ZHLog(@"登录失败,%@", error);
    }
}

3.4 发送在线消息

- (void)sendOnline { XMPPPresence *presence = [XMPPPresence presence]; ZHLog(@"%@",presence); [_xmppStream sendElement:presence]; }

3.5 发送离线消息

- (void)sendOffLine
{
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
    [_xmppStream sendElement:presence];
}

3.6 断开连接

- (void)disconnectFromHost {
    [_xmppStream disconnect];
}

四、XMPP的代理方法

4.1 连接成功

- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
    ZHLog(@"%s",__func__);

    if (self.isRegisterOperation) {
        //注册
        NSError *error = nil;
        NSString *registerPwd = [WCUser shareUser].registerPwd;
        [_xmppStream registerWithPassword:registerPwd error:&error];
        if (error) {
            ZHLog(@"error:%@", error);
        }
    }else {
        [self sendPwdToHost];
    }
}

4.2 登录成功

- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
    [self sendOnline];

    if (_resultBlock) {
        _resultBlock(XMPPResultTypeLoginSuccess);

        //实现登录功能的时候,登录成功之后需要销毁登录控制器
        //因此block回掉成功的信息后,把block设置nil,不让登录控制器继续持有block,可以让登录控制器自动销毁
        //_resultBlock = nil;
    }
}

4.3 登录失败

- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error { ZHLog(@"error: %@",error); if (_resultBlock) { _resultBlock(XMPPResultTypeLoginFailure); } }

4.4 注册成功

- (void)xmppStreamDidRegister:(XMPPStream *)sender { if (_resultBlock) { _resultBlock(XMPPResultTypeRegisterSuccess); } }

4.5 注册失败

- (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error { if (_resultBlock) { _resultBlock(XMPPResultTypeRegisterFailure); } }

五、公共方法

5.1 用户登录

- (void)xmppLogin:(XMPPResultBlock)resultBlock
{
    //把以前的登录断开,不然如果先输错密码登录失败,之后再登录不管密码是对是错,都会登录失败
    //因为连接服务器和发送密码有先后顺序,之前即使输错了密码,实际上还是成功了连接了服务器
    //不把它断开,会报错——试图连接一个已存在的链接
    [_xmppStream disconnect];

    _resultBlock = resultBlock;

    [self connectToHost];
}

5.2 用户注销

- (void)xmppLogout
{
    [self sendOffLine];
    [self disconnectFromHost];
}

5.3 用户注册

- (void)xmppRegister:(XMPPResultBlock)resultBlock { [_xmppStream disconnect]; _resultBlock = resultBlock; [self connectToHost]; }

六、WeChat-Prefix.pch

可以看到,上面的代码中,打印消息的时候用的是ZHLog,而不是NSLog,是因为在pch文件中定义了自己的打印消息的方法:

/** * 自定义Log */
#ifdef DEBUG
//#define ZHLog(...) NSLog(__VA_ARGS__)
#define ZHLog(...) NSLog(@"%s\n %@\n\n", __func__, [NSString stringWithFormat:__VA_ARGS__]);
#else
#define ZHLog(...)
#endif


#endif

七、AppDelegate

判断用户之前是否登录成功,如果登录成功,则不需重复登录,直接跳转到Main.storyboard的功能应该在AppDelegate中编写。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.

    //判断用户是否登录
    if ([WCUser shareUser].isLogin) {
        id mainVc = [[UIStoryboard storyboardWithName:@"Main" bundle:nil]  instantiateInitialViewController];
        self.window.rootViewController = mainVc;

        [[WCXMPPTool sharedWCXMPPTool] xmppLogin:nil];
    }

    return YES;
}

八、小结

以上。

你可能感兴趣的:(ios,工具类,XMPP)