Habber - IOS XMPP 客户端 教程 (二)应用XMPP&代理&全局变量

来源:互联网 发布:word2010 mac 破解版 编辑:程序博客网 时间:2024/06/06 17:10

底层始于XMPP

首先构筑底层,底层为上层服务,也就是我们对XMPP框架提供接口编程的应用。

我是在AppDelegate中写的,可是为什么要在AppDelegate中写?
Nice question! Cuz the demo which the author gave was written in AppDelegate.

好吧,开个玩笑,不过按照我的理解,创建在AppDelegate中原因只是app的生命周期内,我们也只需要创建一个单例,一个xmppStream,然后进行接收传递等数据都靠这同一个流。

事实上完全可以在别的地方写,但是引用起来可能差强人意了,因为还是要引用同一个XMPPStream,怎样获取是个问题。

先看一下AppDelegate.h文件:

////  AppDelegate.h//  Habber////  Created by Sunny on 12/15/15.//  Copyright © 2015 Nine. All rights reserved.//#import <UIKit/UIKit.h>#import <XMPP.h>#import "Statics.h"#import "HabberMessageDelegate.h"#import "HabberChatDelegate.h"@interface AppDelegate : UIResponder <UIApplicationDelegate, XMPPStreamDelegate> {    //是否连接状态    BOOL isOpen;}@property (strong, nonatomic) UIWindow *window;//用于传输xmpp协议数据的封装流。@property (nonatomic, readonly) XMPPStream *xmppStream;//密码@property (nonatomic, strong) NSString *password;@property (nonatomic, strong) id<HabberChatDelegate> chatDelegate;@property (nonatomic, strong) id<HabberMessageDelegate> messageDelegate;//XMPPStream的初始化- (void)setupStream;//连接功能- (BOOL)connect;- (void)disconnect;//控制上下线- (void)goOnline;- (void)goOffline;@end

可以看到它的主要功能就是这些了,继承XMPPStreamDelegate与服务器进行交互,并返回状态,剩下的交给代理(HabberChatDelegate、HabberMessageDelegate)去做。

这里isOpen这个在我给的代码中不用写也可以运行,本来想用来控制服务器是否连接状态的,不过程序中没有用上。但是应该有一个对服务器判断的,减少不必要的开销和消除bug

接下来看看AppDelegate.m中做了什么:

////  AppDelegate.m//  Habber////  Created by Sunny on 12/15/15.//  Copyright © 2015 Nine. All rights reserved.//#import "AppDelegate.h"@interface AppDelegate ()@property (strong, nonatomic) UIImageView *splashView;@end@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    //设置界面显示等,标题栏颜色,状态栏颜色,字体大小等    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];    [[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed:36.0/255 green:36.0/255 blue:36.0/255 alpha:0.9]];    [[UINavigationBar appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor whiteColor]}];    [[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];    [[UIBarButtonItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIFont boldSystemFontOfSize:13], NSFontAttributeName, nil] forState:UIControlStateNormal];    //程序打开自动连接服务器    [self connect];    [NSThread sleepForTimeInterval:1.5];    return YES;}- (void)applicationWillResignActive:(UIApplication *)application {}- (void)applicationDidEnterBackground:(UIApplication *)application {}- (void)applicationWillEnterForeground:(UIApplication *)application {}- (void)applicationDidBecomeActive:(UIApplication *)application {}- (void)applicationWillTerminate:(UIApplication *)application {    [self disconnect];}//XMPPStream初始化- (void)setupStream {    _xmppStream = [XMPPStream new];    //设置线程//    [_xmppStream addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)];    //像上面这样,放到其它线程中,那么代理和通知修改界面的时候就会出现问题,至于放到主线程中来,反正它里面集成的多线程操作可以应付消息传递了。    [_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];}//发送连接服务器请求- (BOOL)connect {    [self setupStream];    //从本地取得用户名密码和服务器地址    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];    NSString *userId = [defaults stringForKey:USERID];    NSString *pass = [defaults stringForKey:PASS];    NSString *server = [defaults stringForKey:SERVER];    //已经连接就不用再连接了    if ([_xmppStream isConnected]) {        return YES;    }    //没有用户名密码我也不去连接    if (userId == nil || pass == nil) {        return NO;    }    //设置用户    [_xmppStream setMyJID:[XMPPJID jidWithString:userId]];    //密码    _password = pass;    //设置服务器    [_xmppStream setHostName:server];    //连接服务器    NSError *error = nil;    if (![_xmppStream connectWithTimeout:5.0 error:&error]) {        return NO;    }    [_chatDelegate didConnect];    return YES;}- (void)disconnect {    [self goOffline];    [_xmppStream disconnect];    [_chatDelegate didDisconnect];}- (void)acceptFriendRequest {}//控制上下线- (void)goOnline {    //发送在线状态    XMPPPresence *presence = [XMPPPresence presence];    [[self xmppStream] sendElement:presence];}- (void)goOffline {    //发送下线状态    XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];    [[self xmppStream] sendElement:presence];}#pragma mark - XMPPStreamDelegate实现- (void)xmppStreamDidConnect:(XMPPStream *)sender {    isOpen = YES;    NSError *error = nil;    //验证密码    [[self xmppStream] authenticateWithPassword:_password error:&error];}- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error {    [[NSNotificationCenter defaultCenter] postNotificationName:@"authenticateFail" object:nil];}- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {    [self goOnline];    [[NSNotificationCenter defaultCenter] postNotificationName:@"hasAuthenticated" object:nil];}- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error {    isOpen = NO;    [[NSNotificationCenter defaultCenter] postNotificationName:@"connectServerFailed" object:nil];}//收到消息后把消息传递给代理- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {    //封装好的 文字 + 发送人    NSString *msg = [[message elementForName:@"body"] stringValue];    NSString *img = [[message elementForName:@"image"] stringValue];    if (!img) {        img = @"";    }    NSString *voice = [[message elementForName:@"voice"] stringValue];    NSString *voiceTime = [[[message elementForName:@"voice"] attributeForName:@"voiceTime"] stringValue];    if (!voice) {        voice = @"";        voiceTime = @"";    }    NSString *from = [[message attributeForName:@"from"] stringValue];    NSMutableDictionary *dict = [NSMutableDictionary dictionary];    [dict setObject:msg forKey:@"msg"];    [dict setObject:img forKey:@"photo"];    [dict setObject:voice forKey:@"voice"];    [dict setObject:voiceTime forKey:@"voiceTime"];    [dict setObject:from forKey:@"sender"];    [_messageDelegate newMessageReceived:dict];}//收到好友状态- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {    //取得好友状态    NSString *presenceType = [presence type];    //我的id    NSString *userId = [[sender myJID] user];    //对方状态(用user也就相当于强制类型转换成NSString)    NSString *presenceFromUser = [[presence from] user];    //如果在列表中把“我”过滤掉    if (![presenceFromUser isEqualToString:userId]) {        if ([presenceType isEqualToString:@"available"]) {            [_chatDelegate newBuddyOnline:[NSString stringWithFormat:@"%@@%@", presenceFromUser, @"thinkdifferent.local"]];        }        if ([presenceType isEqualToString:@"unavailable"]) {            [_chatDelegate buddyWentOffline:[NSString stringWithFormat:@"%@@%@", presenceFromUser, @"thinkdifferent.local"]];        }        //收到好友请求        if ([presenceType isEqualToString:@"subscribe"]) {            [_chatDelegate receivedFriendRequest:[NSString stringWithFormat:@"%@@%@", presenceFromUser, @"thinkdifferent.local"]];        }    }}@end

注释中已经写的很详细了,根据服务器传回的消息进行发送消息通知,而设置的代理则用于传输接收到的传递回来的xml数据解析后封装成的字典。

如果对通知机制与代理机制不太熟悉请恶补一下这方面的内容,真的是非常好用!不禁要感叹只有当自己去做程序的时候才能明白其真正的作用。

两个代理

HabberChatDelegate

#import <Foundation/Foundation.h>@protocol HabberChatDelegate <NSObject>//传递上线人的名字- (void)newBuddyOnline:(NSString *)buddyName;//传递下线人的名字- (void)buddyWentOffline:(NSString *)buddyName;//发送与服务器断开连接的信息- (void)didDisconnect;//发送与服务器连接的信息- (void)didConnect;//传送好友申请信息- (void)receivedFriendRequest:(NSString *)presenceFrom;@end

HabberMessageDelegate

#import <Foundation/Foundation.h>@protocol HabberMessageDelegate <NSObject>//就只负责聊天数据的传送- (void)newMessageReceived:(NSDictionary *)messageContent;@end

Model的设置

Statics.h

#import <Foundation/Foundation.h>//这里有三个,专门用于当做存储userDefaults的键值使用static NSString *USERID = @"userId";static NSString *PASS= @"pass";static NSString *SERVER = @"server";@interface Statics : NSObject//获得当前时间+ (NSString *)getCurrentTime;@end

Statics.m

#import "Statics.h"@implementation Statics+ (NSString *)getCurrentTime {    NSDate *nowUTC = [NSDate date];    NSDateFormatter *dateFormatter = [NSDateFormatter new];    [dateFormatter setTimeZone:[NSTimeZone localTimeZone]];    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];    [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];    return [dateFormatter stringFromDate:nowUTC];}@end

其实关于这个静态方法+ (NSString *)getCurrentTime,作用是获得系统时间显示在聊天cell上的,但是由于已经用了UUChatTableView这个框架,这个方法放在这里没什么意义了,仅供参考。

0 0
原创粉丝点击