XMPP之ios即时通讯客户端开发-配置XMPP基本信息之工程代码(五)

登录功能完成以后包含以下代码文件:

AppDelegate.h

AppDelegate.m

LoginViewController.h

LoginViewController.m

LoginUser.h

LoginUser.m

以下看代码:

//
//  AppDelegate.h
//  XMPP即时通讯
//
//  Created by Mac on 15/7/15.
//  Copyright (c) 2015年 聂小波. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "XMPPFramework.h"

#define xmppDelegate (AppDelegate *)[[UIApplication sharedApplication] delegate]

typedef void(^CompletionBlock)();

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

#pragma mark - XMPP属性及方法
/**
 *  全局的XMPPStream,只读属性
 */
@property (strong, nonatomic, readonly) XMPPStream *xmppStream;
/**
 *  全局的xmppvCard模块,只读属性
 */
@property (strong, nonatomic, readonly) XMPPvCardTempModule *xmppvCardModule;
/**
 *  全局的XMPPvCardAvatar模块,只读属性
 */
@property (strong, nonatomic, readonly) XMPPvCardAvatarModule *xmppvCardAvatarModule;
/**
 *  全局的xmppRoster模块,只读属性
 */
@property (strong, nonatomic, readonly) XMPPRoster *xmppRoster;
/**
 *  全局的XMPPRosterCoreDataStorage模块,只读属性
 */
@property (strong, nonatomic, readonly) XMPPRosterCoreDataStorage *xmppRosterStorage;

/**
 *  消息存档(归档)模块,只读属性
 */
@property (strong, nonatomic, readonly) XMPPMessageArchiving *xmppMessageArchiving;
@property (strong, nonatomic, readonly) XMPPMessageArchivingCoreDataStorage *xmppMessageArchivingCoreDataStorage;

/**
 *  传输文件socket数组
 */
@property (strong, nonatomic) NSMutableArray *socketList;

/**
 *  是否注册用户标示
 */
@property (assign, nonatomic) BOOL isRegisterUser;

/**
 *  连接到服务器
 *
 *  注释:用户信息保存在系统偏好中
 *
 *  @param completion 连接正确的块代码
 *  @param faild      连接错误的块代码
 */
- (void)connectWithCompletion:(CompletionBlock)completion failed:(CompletionBlock)faild;

/**
 *  注销用户登录
 */
- (void)logout;

@end
//
//  AppDelegate.m
//  XMPP即时通讯
//
//  Created by Mac on 15/7/15.
//  Copyright (c) 2015年 聂小波. All rights reserved.
//

#import "AppDelegate.h"
#import "LoginUser.h"
#import "NSString+Helper.h"
#import "NSData+XMPP.h"

#define kNotificationUserLogonState @"NotificationUserLogon"

@interface AppDelegate() <XMPPStreamDelegate, XMPPRosterDelegate, TURNSocketDelegate>
{
    CompletionBlock             _completionBlock;       // 成功的块代码
    CompletionBlock             _faildBlock;            // 失败的块代码

    XMPPReconnect               *_xmppReconnect;        // XMPP重新连接XMPPStream
    XMPPvCardCoreDataStorage    *_xmppvCardStorage;     // 电子名片的数据存储模块

    XMPPCapabilities            *_xmppCapabilities;     // 实体扩展模块
    XMPPCapabilitiesCoreDataStorage *_xmppCapabilitiesCoreDataStorage; // 数据存储模块
}

// 设置XMPPStream
- (void)setupStream;
// 销毁XMPPStream并注销已注册的扩展模块
- (void)teardownStream;
// 通知服务器器用户上线
- (void)goOnline;
// 通知服务器器用户下线
- (void)goOffline;
// 连接到服务器
- (void)connect;
// 与服务器断开连接
- (void)disconnect;

@end

@implementation AppDelegate

#pragma mark 根据用户登录状态加载对应的Storyboard显示
- (void)showStoryboardWithLogonState:(BOOL)isUserLogon
{
    UIStoryboard *storyboard = nil;

    if (isUserLogon) {
        // 显示Main.storyboard
        storyboard = [UIStoryboard storyboardWithName:@"LoginViewController" bundle:nil];
    } else {
        // 显示Login.sotryboard
        storyboard = [UIStoryboard storyboardWithName:@"LoginViewController" bundle:nil];
    }

    // 在主线程队列负责切换Storyboard,而不影响后台代理的数据处理
    dispatch_async(dispatch_get_main_queue(), ^{
        // 如果在项目属性中,没有指定主界面(启动的Storyboard,self.window不会被实例化)
        // 把Storyboard的初始视图控制器设置为window的rootViewController
        [self.window setRootViewController:storyboard.instantiateInitialViewController];

        if (!self.window.isKeyWindow) {
            [self.window makeKeyAndVisible];
        }
    });
}

#pragma mark - AppDelegate方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // 1. 实例化window
//    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

    // 2. 设置XMPPStream
    [self setupStream];

    // 3. 实例化socket数组
    _socketList = [NSMutableArray array];

    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    [self disconnect];
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // 应用程序被激活后,直接连接,使用系统偏好中的保存的用户记录登录
    // 从而实现自动登录的效果!
    [self connect];
}

- (void)dealloc
{
    // 释放XMPP相关对象及扩展模块
    [self teardownStream];
}

#pragma mark - XMPP相关方法
// 设置XMPPStream
- (void)setupStream
{
    // 0. 方法被调用时,要求_xmppStream必须为nil,否则通过断言提示程序员,并终止程序运行!
//    NSAssert(_xmppStream == nil, @"XMPPStream被多次实例化!");

    // 1. 实例化XMPPSteam
    _xmppStream = [[XMPPStream alloc] init];
//    _xmppStream.hostName = @"127.0.0.1";
//////    mysql://localhost:3306/openfire
//    _xmppStream.hostPort = 5222;
//
//////    NSString *[email protected]"admin";
//    _xmppStream.myJID = [XMPPJID jidWithString:[NSString stringWithFormat:@"[email protected]"]];

    // 让XMPP在真机运行时支持后台,在模拟器上是不支持后台服务运行的
#if !TARGET_IPHONE_SIMULATOR
    {
        // 允许XMPPStream在真机运行时,支持后台网络通讯!
        [_xmppStream setEnableBackgroundingOnSocket:YES];
    }
#endif

    // 2. 扩展模块
    // 2.1 重新连接模块
    _xmppReconnect = [[XMPPReconnect alloc] init];
    // 2.2 电子名片模块
    _xmppvCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
    _xmppvCardModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:_xmppvCardStorage];
    _xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:_xmppvCardModule];

    // 2.4 花名册模块
    _xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
    _xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:_xmppRosterStorage];
    // 设置自动接收好友订阅请求
    [_xmppRoster setAutoAcceptKnownPresenceSubscriptionRequests:YES];
    // 自动从服务器更新好友记录,例如:好友自己更改了名片
    [_xmppRoster setAutoFetchRoster:YES];

    // 2.5 实体扩展模块
    _xmppCapabilitiesCoreDataStorage = [[XMPPCapabilitiesCoreDataStorage alloc] init];
    _xmppCapabilities = [[XMPPCapabilities alloc] initWithCapabilitiesStorage:_xmppCapabilitiesCoreDataStorage];

    // 2.6 消息归档模块
    _xmppMessageArchivingCoreDataStorage = [[XMPPMessageArchivingCoreDataStorage alloc] init];
    _xmppMessageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:_xmppMessageArchivingCoreDataStorage];

    // 3. 将重新连接模块添加到XMPPStream
    [_xmppReconnect activate:_xmppStream];
    [_xmppvCardModule activate:_xmppStream];
    [_xmppvCardAvatarModule activate:_xmppStream];
    [_xmppRoster activate:_xmppStream];
    [_xmppCapabilities activate:_xmppStream];
    [_xmppMessageArchiving activate:_xmppStream];

    // 4. 添加代理
    // 由于所有网络请求都是做基于网络的数据处理,这些数据处理工作与界面UI无关。
    // 因此可以让代理方法在其他线城中运行,从而提高程序的运行性能,避免出现应用程序阻塞的情况
    [_xmppStream addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
    [_xmppRoster addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
}

// 销毁XMPPStream并注销已注册的扩展模块
- (void)teardownStream
{
    // 1. 删除代理
    [_xmppStream removeDelegate:self];
    [_xmppRoster removeDelegate:self];

    // 2. 取消激活在setupStream方法中激活的扩展模块
    [_xmppReconnect deactivate];
    [_xmppvCardModule deactivate];
    [_xmppvCardAvatarModule deactivate];
    [_xmppRoster deactivate];
    [_xmppCapabilities deactivate];
    [_xmppMessageArchiving deactivate];

    // 3. 断开XMPPStream的连接
    [_xmppStream disconnect];

    // 4. 内存清理
    _xmppStream = nil;
    _xmppReconnect = nil;
    _xmppvCardModule = nil;
    _xmppvCardAvatarModule = nil;
    _xmppvCardStorage = nil;
    _xmppRoster = nil;
    _xmppRosterStorage = nil;
    _xmppCapabilities = nil;
    _xmppCapabilitiesCoreDataStorage = nil;
    _xmppMessageArchiving = nil;
    _xmppMessageArchivingCoreDataStorage = nil;
}

// 通知服务器器用户上线
- (void)goOnline
{
    // 1. 实例化一个”展现“,上线的报告,默认类型为:available
    XMPPPresence *presence = [XMPPPresence presence];
    // 2. 发送Presence给服务器
    // 服务器知道“我”上线后,只需要通知我的好友,而无需通知我,因此,此方法没有回调
    [_xmppStream sendElement:presence];
}

// 通知服务器器用户下线
- (void)goOffline
{
    // 1. 实例化一个”展现“,下线的报告
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
    // 2. 发送Presence给服务器,通知服务器客户端下线
    [_xmppStream sendElement:presence];
}

// 连接到服务器
- (void)connect
{

    // 1. 如果XMPPStream当前已经连接,直接返回
    if ([_xmppStream isConnected]) {
        return;
    }
    //    在C语言中if判断真假:非零即真,如果_xmppStream==nil下面这段代码,与上面的代码结果不同。
    //    if (![_xmppStream isDisconnected]) {
    //        return;
    //    }

    // 2. 指定用户名、主机(服务器),连接时不需要password
    NSString *hostName = [[LoginUser sharedLoginUser] hostName];
    NSString *userName = [[LoginUser sharedLoginUser] myJIDName];

    // 如果没有主机名或用户名(通常第一次运行时会出现),直接显示登录窗口
//    if ([hostName isEmptyString] || [userName isEmptyString]) {
//        [self showStoryboardWithLogonState:NO];
//
//        return;
//    }

    // 3. 设置XMPPStream的JID和主机
    [_xmppStream setMyJID:[XMPPJID jidWithString:userName]];
    [_xmppStream setHostName:hostName];

    // 4. 开始连接
    NSError *error = nil;
    [_xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&error];

    // 提示:如果没有指定JID和hostName,才会出错,其他都不出错。
    if (error) {
        NSLog(@"连接请求发送出错 - %@", error.localizedDescription);
    } else {
        NSLog(@"连接请求发送成功!");
    }
}

#pragma mark 连接到服务器
- (void)connectWithCompletion:(CompletionBlock)completion failed:(CompletionBlock)faild
{
    // 1. 记录块代码
    _completionBlock = completion;
    _faildBlock = faild;

    // 2. 如果已经存在连接,先断开连接,然后再次连接
    if ([_xmppStream isConnected]) {
        [_xmppStream disconnect];
    }

    // 3. 连接到服务器
    [self connect];
}

// 与服务器断开连接
- (void)disconnect
{
    // 1. 通知服务器下线
    [self goOffline];
    // 2. XMPPStream断开连接
    [_xmppStream disconnect];
}

- (void)logout
{
    // 1. 通知服务器下线,并断开连接
    [self disconnect];

    // 2. 显示用户登录Storyboard
    [self showStoryboardWithLogonState:NO];
}

#pragma mark - 代理方法
#pragma mark 连接完成(如果服务器地址不对,就不会调用此方法)
- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
    // 从系统偏好读取用户密码
    NSString *password = [[LoginUser sharedLoginUser] password];

    if (_isRegisterUser) {
        // 用户注册,发送注册请求
        [_xmppStream registerWithPassword:password error:nil];
    } else {
        // 用户登录,发送身份验证请求
        [_xmppStream authenticateWithPassword:password error:nil];
    }
}

#pragma mark 注册成功
- (void)xmppStreamDidRegister:(XMPPStream *)sender
{
    _isRegisterUser = NO;

    // 注册成功,直接发送验证身份请求,从而触发后续的操作
    [_xmppStream authenticateWithPassword:[LoginUser sharedLoginUser].password error:nil];
}

#pragma mark 注册失败(用户名已经存在)
- (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error
{
    _isRegisterUser = NO;
    if (_faildBlock != nil) {
        dispatch_async(dispatch_get_main_queue(), ^{
            _faildBlock();
        });
    }
}

#pragma mark 身份验证通过
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
    if (_completionBlock != nil) {
        dispatch_async(dispatch_get_main_queue(), ^{
            _completionBlock();
        });
    }

    // 通知服务器用户上线
    [self goOnline];

    // 显示主Storyboard
    [self showStoryboardWithLogonState:YES];
}

#pragma mark 密码错误,身份验证失败
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error
{
    if (_faildBlock != nil) {
        dispatch_async(dispatch_get_main_queue(), ^{
            _faildBlock();
        });
    }

    // 显示用户登录Storyboard
    [self showStoryboardWithLogonState:NO];
}

#pragma mark 用户展现变化
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
    NSLog(@"接收到用户展现数据 - %@", presence);

    // 1. 判断接收到的presence类型是否为subscribe
    if ([presence.type isEqualToString:@"subscribe"]) {
        // 2. 取出presence中的from的jid
        XMPPJID *from = [presence from];

        // 3. 接受来自from添加好友的订阅请求
        [_xmppRoster acceptPresenceSubscriptionRequestFrom:from andAddToRoster:YES];
    }
}

#pragma mark 判断IQ是否为SI请求
- (BOOL)isSIRequest:(XMPPIQ *)iq
{
    NSXMLElement *si = [iq elementForName:@"si" xmlns:@"http://jabber.org/protocol/si"];
    NSString *uuid = [[si attributeForName:@"id"]stringValue];

    if(si &&uuid ){
        return YES;
    }

    return NO;
}

#pragma mark 接收请求
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
    NSLog(@"接收到请求 - %@", iq);

    // 0. 判断IQ是否为SI请求
    if ([self isSIRequest:iq]) {
        TURNSocket *socket = [[TURNSocket alloc] initWithStream:_xmppStream toJID:iq.to];

        [_socketList addObject:socket];

        [socket startWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    } else if ([TURNSocket isNewStartTURNRequest:iq]) {
        // 1. 判断iq的类型是否为新的文件传输请求
        // 1) 实例化socket
        TURNSocket *socket = [[TURNSocket alloc] initWithStream:sender incomingTURNRequest:iq];

        // 2) 使用一个数组成员记录住所有传输文件使用的socket
        [_socketList addObject:socket];

        // 3)添加代理
        [socket startWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    }

    return YES;
}

#pragma mark 接收消息
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
    NSLog(@"接收到用户消息 - %@", message);

    // 1. 针对图像数据单独处理,取出数据
    NSString *imageStr = [[message elementForName:@"imageData"] stringValue];

    if (imageStr) {
        // 2. 解码成图像
        NSData *data = [[NSData alloc] initWithBase64EncodedString:imageStr options:NSDataBase64DecodingIgnoreUnknownCharacters];

        // 3. 保存图像
        UIImage *image = [UIImage imageWithData:data];
        // 4. 将图像保存到相册
        // 1) target 通常用self
        // 2) 保存完图像调用的方法
        // 3) 上下文信息
        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
    }
}

#pragma mark - XMPPRoster代理
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
{
    NSLog(@"接收到其他用户的请求 %@", presence);
}

#pragma mark - TURNSocket代理
- (void)turnSocket:(TURNSocket *)sender didSucceed:(GCDAsyncSocket *)socket
{
    NSLog(@"成功");

    // 保存或者发送文件
    // 写数据方法,向其他客户端发送文件
    //    socket writeData:<#(NSData *)#> withTimeout:<#(NSTimeInterval)#> tag:<#(long)#>
    // 读数据方法,接收来自其他客户端的文件
    //    socket readDataToData:<#(NSData *)#> withTimeout:<#(NSTimeInterval)#> tag:<#(long)#>

    // 读写操作完成之后断开网络连接
    [socket disconnectAfterReadingAndWriting];

    [_socketList removeObject:sender];
}

- (void)turnSocketDidFail:(TURNSocket *)sender
{
    NSLog(@"失败");

    [_socketList removeObject:sender];
}

@end
//  LoginViewController.h
//  02.用户登录&注册
//

#import <UIKit/UIKit.h>

@interface LoginViewController : UIViewController

@end
//
//  LoginViewController.m
//  02.用户登录&注册
//

#import "LoginViewController.h"
#import "NSString+Helper.h"
#import "AppDelegate.h"
#import "LoginUser.h"

@interface LoginViewController () <UITextFieldDelegate>

@property (weak, nonatomic) IBOutlet UITextField *userNameText;
@property (weak, nonatomic) IBOutlet UITextField *passwordText;
@property (weak, nonatomic) IBOutlet UITextField *hostNameText;

@property (weak, nonatomic) IBOutlet UIButton *registerButton;
@property (weak, nonatomic) IBOutlet UIButton *loginButton;

@end

@implementation LoginViewController

#pragma mark - AppDelegate 的助手方法
- (AppDelegate *)appDelegate
{
    return [[UIApplication sharedApplication] delegate];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 1. 拉伸按钮背景图片
    // 1) 登录按钮
    UIImage *loginImage = [UIImage imageNamed:@"LoginGreenBigBtn"];
  loginImage = [loginImage stretchableImageWithLeftCapWidth:loginImage.size.width * 0.5 topCapHeight:loginImage.size.height * 0.5];
    [_loginButton setBackgroundImage:loginImage forState:UIControlStateNormal];

    // 2) 注册按钮
    UIImage *registerImage = [UIImage imageNamed:@"LoginwhiteBtn"];
    registerImage = [registerImage stretchableImageWithLeftCapWidth:registerImage.size.width * 0.5 topCapHeight:registerImage.size.height * 0.5];
    [_registerButton setBackgroundImage:registerImage forState:UIControlStateNormal];

    // 2. 设置界面文本的初始值
    _userNameText.text = [[LoginUser sharedLoginUser] userName];
    _passwordText.text = [[LoginUser sharedLoginUser] password];
    _hostNameText.text = [[LoginUser sharedLoginUser] hostName];

    // 3. 设置文本焦点
    if ([_userNameText.text isEmptyString]) {
        [_userNameText becomeFirstResponder];
    } else {
        [_passwordText becomeFirstResponder];
    }
}

#pragma mark UITextField代理方法
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    if (textField == _userNameText) {
        [_passwordText becomeFirstResponder];
    } else if (textField == _passwordText && [_hostNameText.text isEmptyString]) {
        [_hostNameText becomeFirstResponder];
    } else {
        [self userLoginAndRegister:nil];
    }

    return YES;
}

#pragma mark - Actions
#pragma mark 用户登录
- (IBAction)userLoginAndRegister:(UIButton *)button
{
    // 1. 检查用户输入是否完整,在商业软件中,处理用户输入时
    // 通常会截断字符串前后的空格(密码除外),从而可以最大程度地降低用户输入错误
    NSString *userName = [_userNameText.text trimString];
    // 用些用户会使用空格做密码,因此密码不能去除空白字符
    NSString *password = _passwordText.text;
    NSString *hostName = [_hostNameText.text trimString];

    if ([userName isEmptyString] ||
        [password isEmptyString] ||
        [hostName isEmptyString]) {

        UIAlertView *alter = [[UIAlertView alloc] initWithTitle:@"提示" message:@"登录信息不完整" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];

        [alter show];

        return;
    }

    // 2. 将用户登录信息写入系统偏好
    [[LoginUser sharedLoginUser] setUserName:userName];
    [[LoginUser sharedLoginUser] setPassword:password];
    [[LoginUser sharedLoginUser] setHostName:hostName];

    // 3. 让AppDelegate开始连接
    // 告诉AppDelegate,当前是注册用户
    NSString *errorMessage = nil;

    if (button.tag == 1) {
        [self appDelegate].isRegisterUser = YES;
        errorMessage = @"注册用户失败!";
    } else {
        errorMessage = @"用户登录失败!";
    }

    [[self appDelegate] connectWithCompletion:nil failed:^{
        UIAlertView *alter = [[UIAlertView alloc] initWithTitle:@"提示" message:errorMessage delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];

        [alter show];

        if (button.tag == 1) {
            // 注册用户失败通常是因为用户名重复
            [_userNameText becomeFirstResponder];
        } else {
            // 登录失败通常是密码输入错误
            [_passwordText setText:@""];
            [_passwordText becomeFirstResponder];
        }
    }];
}

@end
//  LoginUser.h

#import <Foundation/Foundation.h>
#import "Singleton.h"

@interface LoginUser : NSObject
single_interface(LoginUser)

@property (strong, nonatomic) NSString *userName;
@property (strong, nonatomic) NSString *password;
@property (strong, nonatomic) NSString *hostName;

@property (strong, nonatomic, readonly) NSString *myJIDName;

@end
//
//  LoginUser.m

#import "LoginUser.h"
#import "NSString+Helper.h"

#define kXMPPUserNameKey    @"admin"
#define kXMPPPasswordKey    @"admin"
#define kXMPPHostNameKey    @"127.0.0.1"

@implementation LoginUser
single_implementation(LoginUser)

#pragma mark - 私有方法
- (NSString *)loadStringFromDefaultsWithKey:(NSString *)key
{
    NSString *str = [[NSUserDefaults standardUserDefaults] stringForKey:key];

    return (str) ? str : @"";
}

#pragma mark - getter & setter
- (NSString *)userName
{
    return [self loadStringFromDefaultsWithKey:kXMPPUserNameKey];
}

- (void)setUserName:(NSString *)userName
{
    [userName saveToNSDefaultsWithKey:kXMPPUserNameKey];
}

- (NSString *)password
{
    return [self loadStringFromDefaultsWithKey:kXMPPPasswordKey];
}

- (void)setPassword:(NSString *)password
{
    [password saveToNSDefaultsWithKey:kXMPPPasswordKey];
}

- (NSString *)hostName
{
    return [self loadStringFromDefaultsWithKey:kXMPPHostNameKey];
}

- (void)setHostName:(NSString *)hostName
{
    [hostName saveToNSDefaultsWithKey:kXMPPHostNameKey];
}

- (NSString *)myJIDName
{
    return [NSString stringWithFormat:@"%@@%@", self.userName, self.hostName];
}

@end
时间: 2024-10-11 00:34:03

XMPP之ios即时通讯客户端开发-配置XMPP基本信息之工程代码(五)的相关文章

XMPP之ios即时通讯客户端开发-配置XMPP基本信息(四)

前文已经有配置open fire,接下来要通过XMPP框架链接到open fire的服务器: 1.首先要在系统偏好设置里面打开open fire的服务器 2.代码中设置xmpp的myJID 有几个名词要理解: userName: password: hostName: myJID: 下面回顾先前配置open fire时的截图 hostName:127.0.0.1  (看填写的是什么,有的是用机器名***mac.local) userName:admin (open fire的登录名,默认的,修改

XMPP之ios即时通讯客户端开发-mac上搭建openfire服务器(二)

come from:http://www.cnblogs.com/xiaodao/archive/2013/04/05/3000554.html 一.下载并安装openfire 1.到http://www.igniterealtime.org/downloads/index.jsp下载最新openfire for mac版 比如:Openfire 3.8.1,下载后的文件:openfire_3_8_1.dmg 2.点击安装,并执行默认操作 3.启动openfire服务 在系统偏好设置的其他里,点

IOS 即时通讯的框架 配置环境

一.了解XMPP 协议(标准)XMPP 即时通讯协议SGIP 短信网关协议 这手机发短信 移动支付和网页支付 0x23232[0,1] 0x23232 0x23232 0x23232 只有协议,必须会有协议文档 二.环境配置 1.安装mysql2.修改mysql的帐户的密码>sqlite(移动平台) ,是没有密码直接连接数据库>mysql sqlServer (服务端的数据库) 是有帐户和密码  默认安装完mysql,他的帐户是root 密码为空 "使用命令登录mysql"

ios即时通讯客户端开发之-mac上基于XMPP的聊天客户端开发环境搭建

1.搭建服务器  -  安装顺序 - (mysql->openfire->spark) 数据库:mysql 服务器管理工具: openfire 测试工具: spark mysql 安装 http://www.cnblogs.com/xiaodao/archive/2013/04/04/2999426.html 注意点:在终端执行mysql命令时候,最后都要加封号(;) openfire安装http://www.cnblogs.com/xiaodao/archive/2013/04/05/300

XMPP-IOS即时通讯开发环境搭建

一.服务器搭建-安装MySQL 1.启动MySQL服务器 2.设置MySQL命令行 打开终端,输入: sudo vi ~/.bash_profile 接着输入i,进入编辑模式,输入: # mysql alias mysql='/usr/local/mysql/bin/mysql' alias mysqladmin='/usr/local/mysql/bin/mysqladmin' # ls alias ls='ls -G' 按ESC键退出编辑模式,输入: :wq 保存修改内容并退出后进行重新启动

XMPP(三)-安卓即时通讯客户端

由于时间原因,所以更新比较慢 ,还请大家谅解,此次是对上篇文章中的安卓客户端初级版本进行的一次更新优化,在这次更新后,就有那么一点样子了,可以拿的出手了,呵呵,还在关注的同学也可以及时下载更新.此次主要更新的内容如下: 1,聊天界面,新消息到来时,聊天界面同步刷新: 2,聊天界面,支持长按聊天记录时删除或复制聊天记录,及清空与该用户的全部聊天记录: 3,消息界面,支持长按某一会话,删除与该用户的会话记录: 4,支持消息未读数量显示(底部导航栏为总未读数,会话记录处为与该用户的聊天的未读消息数):

XMPP-IOS即时通讯XMPP相关框架导入

只是留存一下XMPP相关框架的导入步骤,方便以后查看 一.框架地址 1.其他语言可用XMPPFramework 框架地址 http://xmpp.org/xmpp-software/libraries/ 2.下载XMPPFramework框架: https://github.com/robbiehanson/XMPPFramework 3.git clone https://github.com/robbiehanson/XMPPFramework.git 二.导入相关框架 CocoaLumbe

ios即时通讯客户端开发之-mac上搭建openfire服务器

一.下载并安装openfire 1.到http://www.igniterealtime.org/downloads/index.jsp下载最新openfire for mac版 比如:Openfire 3.8.1,下载后的文件:openfire_3_8_1.dmg 2.点击安装,并执行默认操作 3.启动openfire服务 在系统偏好设置的其他里,点击openfire偏好 启动后,点击Open Admin Console按钮,自动在浏览器中打开本地web配置页面http://localhost

ios即时通讯客户端开发之-mac上安装MySQL

一.安装 到MySQL官网上http://dev.mysql.com/downloads/mysql/,下载mysql可安装dmg版本 比如:Mac OS X ver. 10.9 (x86, 64-bit), DMG Archive 下载完的文件为:mysql-5.6.26-osx10.9-x86_64.dmg 1.点击,安装包里的 2.安装好后,再系统偏好设置的其他里,会出现如下图标: 3.点击此图标,跳出对话框 点击Start MySQL Server按钮,启动mysql 二.打开终端,定义