BAT 批处理程序 2017-06-16
用户登录流程.png
[blockquote]
实现用户登录的步骤如下:
[/blockquote]
#import <Foundation/Foundation.h> @interface JPLoginTool : NSObject /** * 保存登录信息到沙盒 */ +(void)saveLoginInfoWithAccount:(NSString *)account pwd:(NSString *)pwd domain:(NSString *)domain; /** * 获取沙盒的帐号 * */ +(NSString *)account; /** * 获取沙盒的密码 * */ +(NSString *)password; /** * 获取沙盒的域名 * */ +(NSString *)domain; /** * 从沙盒清除所有的用户登录信息 */ +(void)removeAllLoginInfo; /** * 获取用户登录状态 * */ +(BOOL)isLogin; /** * 设置用户登录状态 */ +(void)setLogin:(BOOL)login; @end
#import "JPLoginTool.h" #define kAccountKey @"account" #define kPasswordKey @"passsword" #define kDomainKey @"domain" #define kIsLoginKey @"isLogin" @implementation JPLoginTool +(void)saveLoginInfoWithAccount:(NSString *)account pwd:(NSString *)pwd domain:(NSString *)domain{ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:account forKey:kAccountKey]; [defaults setObject:pwd forKey:kPasswordKey]; [defaults setObject:domain forKey:kDomainKey]; //同步沙盒 [defaults synchronize]; } /** * 获取沙盒的帐号 * */ +(NSString *)account{ return [[NSUserDefaults standardUserDefaults] objectForKey:kAccountKey]; } /** * 获取沙盒的密码 * */ +(NSString *)password{ return [[NSUserDefaults standardUserDefaults] objectForKey:kPasswordKey]; } /** * 获取沙盒的域名 * */ +(NSString *)domain{ return [[NSUserDefaults standardUserDefaults] objectForKey:kDomainKey]; } /** * 从沙盒清除所有的用户登录信息 * */ +(void)removeAllLoginInfo{ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults removeObjectForKey:kAccountKey]; [defaults removeObjectForKey:kPasswordKey]; [defaults removeObjectForKey:kDomainKey]; [defaults synchronize]; } /** * 获取用户登录状态 * */ +(BOOL)isLogin{ return [[NSUserDefaults standardUserDefaults] boolForKey:kIsLoginKey]; } /** * 设置用户登录状态 */ +(void)setLogin:(BOOL)login{ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setBool:login forKey:kIsLoginKey]; [defaults synchronize]; } @end
1、首先,我们布局登录界面,提供登录按钮,当我们点击登录按钮时就进行登录操作,因为XMPPFrame的相关操作都建议写在AppDelegate文件中,所以我们需要在AppDelegate.h文件中提供接口给用户,而至于那些连接到服务器以及授权等操作都写在AppDelegate.m中不用暴露给用户。
#pragma mark 用户登录 -(void)xmppUserLogin;2、但是,当我们点击登录,在控制器的登录方法中,拿到应用程序的代理,然后调用应用代理的xmppUserLogin方法,此时不仅要执行登录操作,而且应用代理必须要告诉我们是否登录成功,因为登录操作是封装到AppDelegate中的 - > 这就要实现两者之间的通信了。
// 在应用代理头文件中 // 1. 定义block typedef enum { XMPPResultTypeLogining,//正在登录中 XMPPResultTypeLoginSuccess,//登录成功 XMPPResultTypeLoginFailure,//登录失败 XMPPResultTypeNetError,//网络不给力 XMPPResultTypeUnknowDomain,//域名不存在 XMPPResultTypeConnectionRefused//服务器拒绝连接 } XMPPResultType; typedef void (^XMPPResultBlock)(XMPPResultType resultType);//xmpp请求结果的block // 2.提供为外界登录接口 #pragma mark 用户登录 -(void)xmppUserLogin:(XMPPResultBlock)resultBlock;
#pragma 用户注销 -(void)xmppUserLogout;
//登录状态改变 #define kLoginStateChangeNotification @"LoginStateChangeNotification"
#import <UIKit/UIKit.h> #define kIsLoginKey @"isLogin" //登录状态改变 #define kLoginStateChangeNotification @"LoginStateChangeNotification" #define xmppDelegate ((JPAppDelegate *)[UIApplication sharedApplication].delegate) typedef enum { XMPPResultTypeLogining,//正在登录中 XMPPResultTypeLoginSuccess,//登录成功 XMPPResultTypeLoginFailure,//登录失败 XMPPResultTypeNetError,//网络不给力 XMPPResultTypeUnknowDomain,//域名不存在 XMPPResultTypeConnectionRefused//服务器拒绝连接 }XMPPResultType; typedef void (^XMPPResultBlock)(XMPPResultType resultType);//xmpp请求结果的block @interface JPAppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; #pragma mark 用户登录 -(void)xmppUserLogin:(XMPPResultBlock)resultBlock; #pragma 用户注销 -(void)xmppUserLogout; @end
7.进入登录页面时,自动显示上一次登录数据
注意:
#import "JPAppDelegate.h" #import "JPLoginTool.h" #define kMainStoryboardName @"Main" #define kLoginStoryboardName @"Login" @interface JPAppDelegate()<XMPPStreamDelegate>{ XMPPResultBlock _resultBlock; } //初始化xmppStream -(void)setupXmppStream; //连接主机 -(void)connectToHost; //从主机断开连接 -(void)disconnectFromHost; //授权(也就发送帐号和密码) -(void)userAuth; //用户上线(通知其他好友,你已经在线) -(void)goOnline; //用户用户离线 -(void)goOffline; @end @implementation JPAppDelegate //官方建议,把用户授权写在appdelegate /** * 0.初始化xmppStream * 1.连接主机 * 2.从主机断开连接 * 3.授权(也就发送帐号和密码) * 4.用户上线(通知其他好友,你已经在线) * 5.用户用户离线 */ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //NSLog(@"%s %d",__func__,__LINE__); //设置日志输出方式(输出到控制器) [DDLog addLogger:[DDTTYLogger sharedInstance]]; //设置颜色 [[DDTTYLogger sharedInstance] setColorsEnabled:YES]; //设置自己的日志颜色 [[DDTTYLogger sharedInstance] setForegroundColor:[UIColor blueColor] backgroundColor:nil forFlag:LOG_LEVEL_INFO]; // 初始化xmppStream [self setupXmppStream]; return YES; } #pragma 失去焦点 - (void)applicationWillResignActive:(UIApplication *)application { //从主机断开连接 //[self disconnectFromHost]; //获取登录状态 if([JPLoginTool isLogin]){ //NSLog(@"登录过"); //如果是登录 断开连接 [self disconnectFromHost]; }; } #pragma mark 获取焦点 - (void)applicationDidBecomeActive:(UIApplication *)application { //[self connectToHost]; //获取登录状态 如果登录过,直接跳到主页面 然后自动登录 if([JPLoginTool isLogin]){ NSLog(@"登录过"); //直接跳到主页 [self showStoryboardWithName:kMainStoryboardName]; //自动登录 [self connectToHost]; }; } #pragma mark - xmppSteam代理 #pragma mark 连接成功 -(void)xmppStreamDidConnect:(XMPPStream *)sender{ JPLogInfo(@"与主机连接成功"); //JPLogInfo(@"登录"); //发送登录密码验证 [self userAuth]; } #pragma mark 连接失败 -(void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error{ //如果error为空,代理正常断开 JPLogInfo(@"连接失败 %@",error); //有error 并且block有值 通知登录控制器 if (error && _resultBlock) { //域名或者主机不存 if (error.code == 8) { _resultBlock(XMPPResultTypeUnknowDomain); }else if(error.code == 61){ _resultBlock(XMPPResultTypeConnectionRefused); } else{ _resultBlock(XMPPResultTypeNetError); } } // 清除用户偏好设置 if (error) { [JPLoginTool removeAllLoginInfo]; } } #pragma mark 用户授权成功 -(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{ // 子线程 NSLog(@"%@",[NSThread currentThread]); JPLogInfo(@"用户授权成功"); // 把"登录状态"通知"聊天历史控制器" // 登录成功 [self postLoginNotification:XMPPResultTypeLoginSuccess]; // 1.通知用户上线 [self goOnline]; // 2.如果用户登录成功 沙盒里保存一个登录状态 [JPLoginTool setLogin:YES]; //在主线程更新UI [self showStoryboardWithName:kMainStoryboardName]; } #pragma mark 用户授权失败 -(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{ JPLogInfo(@"用户授权失败%@",error); //把"登录状态"通知"聊天历史控制器" //登录失败 [self postLoginNotification:XMPPResultTypeLoginFailure]; //清除用户偏好设置 [JPLoginTool removeAllLoginInfo]; //通知登录控制器 if (_resultBlock) { _resultBlock(XMPPResultTypeLoginFailure); } // dispatch_async(dispatch_get_main_queue(), ^{ // // }); } #pragma mark -私有方法 #pragma mark 初始化xmppStrem对象 -(void)setupXmppStream{ NSAssert(_xmppStream == nil, @"xmppStream对象初始化多次"); //1.创建xmppStrem对象 _xmppStream = [[XMPPStream alloc] init]; //2.添加代表 [_xmppStream addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; } -(void)connectToHost{ JPLogInfo(@"开始连接到主机"); //把"登录状态"通知"聊天历史控制器" //登录中 [self postLoginNotification:XMPPResultTypeLogining]; //从沙盒里获取数据 NSString *account = [JPLoginTool account]; NSString *domain = [JPLoginTool domain]; //1.设置账号 _xmppStream.myJID = [XMPPJID jidWithUser:account domain:domain resource:nil]; //2.设置主机 _xmppStream.hostName = domain; //3.设置主机端口 //默认端口就5222 _xmppStream.hostPort = 5222; //连接到主机 NSError *err = nil; [_xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&err]; if (err) { JPLogInfo(@"%@ ",err); } } #pragma mark 从主机断连接 -(void)disconnectFromHost{ // 1.通知用户下线 [self goOffline]; // 2.断开连接 [_xmppStream disconnect]; } #pragma mark 用户授权 -(void)userAuth{ JPLogInfo(@"用户开始授权"); NSError *error = nil; //发送密码到服务器 [_xmppStream authenticateWithPassword:[JPLoginTool password] error:&error]; if (error) { JPLogInfo(@"%@",error); } } #pragma mark 用户上线 -(void)goOnline{ JPLogInfo(@"通知用户在线"); XMPPPresence *presence = [XMPPPresence presence]; [_xmppStream sendElement:presence]; } #pragma mark 用户下线 -(void)goOffline{ JPLogInfo(@"通知用户下线"); XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"]; [_xmppStream sendElement:presence]; } #pragma mark 显示storyboard的第一个控制器 // 比如用户登录成功后,设置主窗口的根控制器为tabVC,然后,选中的tabVC的第三个子控制器, // 然后退出到后台,当用户再次进入到前台时,并不需要重新设置窗口的根控制器此时。 // 那什么时候需要设置呢-> 当主窗口的根控制器不是tabVC才需要重新设置窗口的根控制器 -(void)showStoryboardWithName:(NSString *)name{ dispatch_async(dispatch_get_main_queue(), ^{ // 3.显示主界面 // 3.1获取sotryboard对象 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:name bundle:nil]; //3.2获取windows的旧的根控制器 UIViewController *oldVc = self.window.rootViewController; JPLogWarn(@"旧的控制器 %@",oldVc); //3.3获取要切换storyboard里面的第一个控制器 UIViewController *newVc = [storyboard instantiateInitialViewController]; JPLogWarn(@"要切换的控制器 %@",newVc); //如果旧的控制器类型和新的控制器类型不一样,才须要切换UIWindow的根控制器 if (![oldVc isKindOfClass:[newVc class]]) { //38 self.window.rootViewController = newVc; } }); } #pragma mark -公共方法 #pragma mark 用户登录 -(void)xmppUserLogin:(XMPPResultBlock)resultBlock{ //block负值 _resultBlock = resultBlock; JPLogInfo(@"用户登录被调用"); //如果当前socket存在连接,应该断开 // if (_xmppStream.isConnected) { // [_xmppStream disconnect]; // } [_xmppStream disconnect]; [self connectToHost]; } #pragma mark 用户注销 -(void)xmppUserLogout{ //1.设置登录状态为NO [JPLoginTool setLogin:NO]; //2.断开连接 [self disconnectFromHost]; //3.返回到登录页面 [self showStoryboardWithName:@"Login"]; } #pragma mark 登录状态通知 -(void)postLoginNotification:(XMPPResultType)resultType{ //把"登录状态"通知"聊天历史控制器" //登录成功 dispatch_async(dispatch_get_main_queue(), ^{ NSDictionary *userInfo = @{@"LoginState": @(resultType)}; [[NSNotificationCenter defaultCenter] postNotificationName:kLoginStateChangeNotification object:nil userInfo:userInfo]; }); }
- (IBAction)login { //1.把你登录信息保存到沙盒里 NSString *account = self.accountField.text; NSString *password = self.passwordFiled.text; NSString *domain = self.domainField.text; [JPLoginTool saveLoginInfoWithAccount:account pwd:password domain:domain]; //隐藏keyboard [self.view endEditing:YES]; //提醒正在登录 UIView *showView = self.view; [MBProgressHUD showMessage:@"正在登录......" toView:showView]; xmppDelegate.userRegister = NO;//代表登录 //2.调用appdelegate里的xmmpUserLogin方法 //JPAppDelegate *delegate = [UIApplication sharedApplication].delegate; [xmppDelegate xmppUserLogin:^(XMPPResultType resultType) { //隐藏正在登录 //因为这个block是被appdelegate里面xmppStream的代理调用,而xmppStream代理被调用是在子线线程中的,所在更新UI放在主线程 dispatch_async(dispatch_get_main_queue(), ^{ [MBProgressHUD hideHUDForView:showView]; switch (resultType) { case XMPPResultTypeLoginFailure: [MBProgressHUD showError:@"用户名或者密码错误"]; break; case XMPPResultTypeNetError: [MBProgressHUD showError:@"网络不给力"]; break; case XMPPResultTypeConnectionRefused: [MBProgressHUD showError:@"服务器拒绝连接,可能服务没有开启"]; break; case XMPPResultTypeUnknowDomain: JPLogInfo(@"域名不存在或者错误"); [MBProgressHUD showError:@"域名不存在或者错误"]; break; default: break; } }); }]; }
原文链接:http://www.jianshu.com/p/a16d3d70dd86
参考链接:http://blog.csdn.net/cerastes/article/details/33713967
http://blog.csdn.net/liuhongwei123888/article/details/6840262
http://www.jianshu.com/p/a22406c40c8b
源码地址:https://github.com/robbiehanson/XMPPFramework,目前需要使用 Git (sourcTree) 才能download到源码。