XMPP即时通讯(代码实现)

1.配置XMPP(XMPPConfig.m)

2.配置XMPPFramework框架

3.创建单例类(XMPPManager.h/XMPPManager.m)管理器

XMPPManager.m:

#import "XMPPManager.h"

#import "AppDelegate.h"

//连接服务器的目的

typedef NS_ENUM(NSInteger, ConnectToServerPopurpose)

{

ConnectToServerPopurposeLogin, //登录

ConnectToServerPopurposeRegist //注册

};

@interface XMPPManager ()<XMPPStreamDelegate,XMPPRosterDelegate>

@property (nonatomic, assign) ConnectToServerPopurpose serverPurpose; //连接服务器的目的

@property (nonatomic, copy) NSString *loginPassword; //登录密码

@property (nonatomic, copy) NSString *registerPassword; //注册密码

- (void)connectServer; //连接服务器

- (void)disConnectWithServer; //断开服务器

@end

@implementation XMPPManager

static XMPPManager *manager = nil;

+ (XMPPManager *)defaultXMPPManager {

//gcd once 程序执行期间只执行一次

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

manager = [[XMPPManager alloc] init];

});

return manager;

}

//重写init方法

- (instancetype)init

{

self = [super init];

if (self) {

//创建通信通道用于和服务器进行连接和沟通

self.stream = [[XMPPStream alloc] init];

//设置服务器

self.stream.hostName = kHostName;

//设置端口号

self.stream.hostPort = kHostPort;

//添加代理

[self.stream addDelegate:self delegateQueue:dispatch_get_main_queue()];

//创建好友列表仓库

XMPPRosterCoreDataStorage *rosterCorDataStorage = [XMPPRosterCoreDataStorage sharedInstance];

//创建花名册对象

self.roster = [[XMPPRoster alloc] initWithRosterStorage:rosterCorDataStorage dispatchQueue:dispatch_get_main_queue()];

//将花名册对象添加到stream活动

[self.roster activate:self.stream];

//添加代理

[self.roster addDelegate:self delegateQueue:dispatch_get_main_queue()];

//创建信息归档对象

XMPPMessageArchivingCoreDataStorage *messageArchingCoreStorage = [XMPPMessageArchivingCoreDataStorage sharedInstance];

//创建信息归档对象

self.messageArching = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:messageArchingCoreStorage dispatchQueue:dispatch_get_main_queue()];

//添加活动到通信管道

[self.messageArching activate:self.stream];

//获取数据管理器

self.managerContext = messageArchingCoreStorage.mainThreadManagedObjectContext;

}

return self;

}

#pragma mark - XMPPRosterDelegate

- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence {

//获取请求对象的JID

XMPPJID *requestJID = presence.from;

//创建提示框

UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"添加好友提醒" message:requestJID.user preferredStyle:UIAlertControllerStyleAlert];

//创建事件

UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"添加" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction *action) {

//接受好友请求

[self.roster acceptPresenceSubscriptionRequestFrom:requestJID andAddToRoster:YES];

}];

UIAlertAction *rejectAction = [UIAlertAction actionWithTitle:@"拒绝" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {

//拒绝好友请求

[self.roster rejectPresenceSubscriptionRequestFrom:requestJID];

}];

//添加事件

[alertVC addAction:addAction];

[alertVC addAction:rejectAction];

//弹出提示框

//获取AppDelegate

AppDelegate *appDelegate  = [UIApplication sharedApplication].delegate;

//获取根视图控制器

UIViewController *rootVC = appDelegate.window.rootViewController;

[rootVC presentViewController:alertVC animated:YES completion:nil];

}

//连接服务器

- (void)connectServer {

if ([self.stream isConnected] || [self.stream isConnecting]) {

//断开连接

[self disConnectWithServer];

}

//建立新的连接(30秒超时)

NSError *error = nil;

[self.stream connectWithTimeout:30 error:&error];

if (error) {

NSLog(@"connect fail");

}

}

//登录

- (void)loginWithUserName:(NSString *)username password:(NSString *)pw {

self.loginPassword = pw; //记录登录密码

self.serverPurpose = ConnectToServerPopurposeLogin; //登录标识

//获取jid 唯一标识

XMPPJID *myJID = [XMPPJID jidWithUser:username domain:kDomin resource:kResource];

self.stream.myJID = myJID; //设置JID

//连接服务器

[self connectServer];

}

//注册

- (void)registWithUserName:(NSString *)username passeord:(NSString *)pw {

self.registerPassword = pw; //记录注册密码

self.serverPurpose = ConnectToServerPopurposeRegist; //注册标识

//获取JID唯一标识

XMPPJID *myJID = [XMPPJID jidWithUser:username domain:kDomin resource:kResource];

self.stream.myJID = myJID; //设置JID

//连接服务器

[self connectServer];

}

//添加好友

- (void)addFriend:(NSString *)name {

//创建JID

XMPPJID *myJID = [XMPPJID jidWithString:[NSString stringWithFormat:@"%@@%@",name,kHostName]];

//添加好友

[self.roster subscribePresenceToUser:myJID];

}

//删除好友

- (void)deleteFriend:(NSString *)name {

//获取JID

XMPPJID *myJID = [XMPPJID jidWithString:[NSString stringWithFormat:@"%@@%@",name,kHostName]];

[self.roster removeUser:myJID];

}

//断开服务器连接

- (void)disConnectWithServer {

//断开服务器

[self.stream disconnect];

}

#pragma mark - XMPPStreamDelegate

//成功连接服务器

- (void)xmppStreamDidConnect:(XMPPStream *)sender {

NSLog(@"connect success");

switch (self.serverPurpose) {

case ConnectToServerPopurposeLogin:

//登录

{

[self.stream authenticateWithPassword:self.loginPassword error:nil];

}

break;

case ConnectToServerPopurposeRegist:

//注册

{

[self.stream registerWithPassword:self.registerPassword error:nil];

}

break;

default:

break;

}

}

//连接超时

- (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender {

NSLog(@"connect time out");

}

@end

用户登录:

#import "LoginViewController.h"

#import "XMPPManager.h"

#import "RosterTableViewController.h"

BOOL isClickButton = YES;

@interface LoginViewController ()<XMPPStreamDelegate>

@property (weak, nonatomic) IBOutlet UITextField *userNameTF;

@property (weak, nonatomic) IBOutlet UITextField *passwordTF;

@end

@implementation LoginViewController

- (void)viewDidLoad {

[super viewDidLoad];

//添加代理

[[XMPPManager defaultXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];

}

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

/*

#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

// Get the new view controller using [segue destinationViewController].

// Pass the selected object to the new view controller.

}

*/

#pragma mark - handleAction

- (IBAction)handleLogin:(UIButton *)sender {

isClickButton = YES; //标识点击了登录button

[[XMPPManager defaultXMPPManager] loginWithUserName:self.userNameTF.text password:self.passwordTF.text];

}

- (IBAction)handleRegister:(UIButton *)sender {

}

#pragma mark - XMPPStreamDelegate

//登录成功

- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {

//上线--更改状态

XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"];

[[XMPPManager defaultXMPPManager].stream sendElement:presence];

if (isClickButton) {

//提示

UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"温馨提示" message:@"欢迎回来" preferredStyle:(UIAlertControllerStyleAlert)];

//添加事件

UIAlertAction *action = [UIAlertAction actionWithTitle:@"好" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction *action) {

//获取从storyBoard中获取联系人列表界面

RosterTableViewController *rosterVC = [self.storyboard instantiateViewControllerWithIdentifier:@"contact"];

//传值

rosterVC.userName = self.userNameTF.text;

rosterVC.paassWord = self.passwordTF.text;

//push

[self.navigationController pushViewController:rosterVC animated:YES];

}];

[alertVC addAction:action];

//弹出提示

[self presentViewController:alertVC animated:YES completion:nil];

//更改BOOL

isClickButton = NO;

}

}

//登录失败

- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error {

//提示

UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"温馨提示" message:@"账号或密码错误请核对" preferredStyle:(UIAlertControllerStyleAlert)];

//添加事件

UIAlertAction *action = [UIAlertAction actionWithTitle:@"好" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction *action) {

}];

[alertVC addAction:action];

//弹出提示

[self presentViewController:alertVC animated:YES completion:nil];

}

@end

用户注册:

#import "RegisterViewController.h"

#import "XMPPManager.h"

@interface RegisterViewController ()<XMPPStreamDelegate>

@property (weak, nonatomic) IBOutlet UITextField *userNameTF;

@property (weak, nonatomic) IBOutlet UITextField *passwordTF;

@property (weak, nonatomic) IBOutlet UITextField *rePasswordTF;

@end

@implementation RegisterViewController

- (void)viewDidLoad {

[super viewDidLoad];

//添加代理

[[XMPPManager defaultXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];

}

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

/*

#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

// Get the new view controller using [segue destinationViewController].

// Pass the selected object to the new view controller.

}

*/

#pragma mark - handleAction

- (IBAction)handleSubmit:(UIButton *)sender {

//注册

[[XMPPManager defaultXMPPManager] registWithUserName:self.userNameTF.text passeord:self.passwordTF.text];

}

- (IBAction)handleCleare:(UIButton *)sender {

}

#pragma mark - XMPPStreamDelegate

//注册成功

- (void)xmppStreamDidRegister:(XMPPStream *)sender {

NSLog(@"register success");

}

//注册失败

- (void)xmppStream:(XMPPStream *)sender didNotRegister:(NSXMLElement *)error {

NSLog(@"register fail");

}

@end

联系人列表

#import "RosterTableViewController.h"

#import "RosterCell.h"

#import "ChatTableViewController.h"

#import "XMPPManager.h"

@interface RosterTableViewController ()<XMPPRosterDelegate>

@property (nonatomic, strong) NSMutableArray *contacts; //联系人数组

@end

@implementation RosterTableViewController

- (void)viewDidLoad {

[super viewDidLoad];

// Uncomment the following line to preserve selection between presentations.

// self.clearsSelectionOnViewWillAppear = NO;

// Uncomment the following line to display an Edit button in the navigation bar for this view controller.

//     self.navigationItem.rightBarButtonItem = self.editButtonItem;

self.contacts = [NSMutableArray array]; //创建数组

//添加代理

[[XMPPManager defaultXMPPManager].roster addDelegate:self delegateQueue:dispatch_get_main_queue()];

//再次登录

[[XMPPManager defaultXMPPManager] loginWithUserName:self.userName password:self.paassWord];

}

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

return 1;

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

return self.contacts.count;

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

RosterCell *cell = [tableView dequeueReusableCellWithIdentifier:@"roster" forIndexPath:indexPath];

//获取对应的联系人JID

XMPPJID *jid = self.contacts[indexPath.row];

cell.textLabel.text = jid.user;

return cell;

}

#pragma mark - XMPPRosterDelegate

//开始检索好友

- (void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender {

NSLog(@"begin search friends");

}

//检索好友,每执行一次获取一个好友信息

- (void)xmppRoster:(XMPPRoster *)sender didRecieveRosterItem:(NSXMLElement *)item {

NSLog(@"%@",[[item attributeForName:@"jid"] stringValue]);

//获取JIDStr

NSString *jidStr = [[item attributeForName:@"jid"] stringValue];

//获取JID

XMPPJID *myJID = [XMPPJID jidWithString:jidStr resource:kResource];

//防止重复添加好友

for (XMPPJID *JID in self.contacts) {

if ([JID.user isEqualToString:myJID.user]) {

return;

}

}

//放入数组

[self.contacts addObject:myJID];

//刷新界面

[self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.contacts.count - 1 inSection:0]] withRowAnimation:UITableViewRowAnimationLeft];

}

//结束检索好友

- (void)xmppRosterDidEndPopulating:(XMPPRoster *)sender {

NSLog(@"end search friends");

}

#pragma mark - Navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

//界面传值

//获取下一个试图控制器

ChatTableViewController *chatVC = segue.destinationViewController;

//获取cell

UITableViewCell *cell = sender;

//获取下标

NSInteger index = [self.tableView indexPathForCell:cell].row;

//获取对应的对象

XMPPJID *JID = self.contacts[index];

chatVC.friendJID = JID;

}

@end

聊天控制器

#import "ChatTableViewController.h"

#import "ChatCell.h"

@interface ChatTableViewController ()<XMPPStreamDelegate>

@property (nonatomic, strong) NSMutableArray *messageArray; //用来存储信息

@end

@implementation ChatTableViewController

- (void)viewDidLoad {

[super viewDidLoad];

// Uncomment the following line to preserve selection between presentations.

// self.clearsSelectionOnViewWillAppear = NO;

// Uncomment the following line to display an Edit button in the navigation bar for this view controller.

self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"发送" style:(UIBarButtonItemStyleDone) target:self action:@selector(sendMessage)];

//添加代理

[[XMPPManager defaultXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];

//创建数组

self.messageArray = [NSMutableArray array];

//获取本地聊天信息

[self reloadMessage];

}

//发送新的消息

- (void)sendMessage

{

//创建新的信息

XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.friendJID];

//添加信息体

[message addBody:@"比如说"];

[[XMPPManager defaultXMPPManager].stream sendElement:message];

}

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

return 1;

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

return self.messageArray.count;

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

ChatCell *cell = [tableView dequeueReusableCellWithIdentifier:@"chat" forIndexPath:indexPath];

//获取对应数组元素

XMPPMessage *message = self.messageArray[indexPath.row];

if ([message isKindOfClass:[XMPPMessage class]]) {

//将收到的信息放到左边,发送的放到右边

if ([message.from.user isEqualToString:self.friendJID.user]) {

cell.textLabel.text = message.body;

cell.detailTextLabel.text = @"";

}else {

cell.textLabel.text = @"";

cell.detailTextLabel.text = message.body;

}

}else {

//数组中的对象时XMPPMessageArchiving_Mesage_CoreDataObject类型

XMPPMessageArchiving_Message_CoreDataObject *mes = (XMPPMessageArchiving_Message_CoreDataObject *)message;

//Outgoing发送,用来判断消息是接受的 还是发送的

if (![mes isOutgoing]) {

cell.textLabel.text = mes.message.body;

cell.detailTextLabel.text = @"";

}else {

cell.textLabel.text = @"";

cell.detailTextLabel.text = mes.message.body;

}

}

return cell;

}

//读取本地信息

- (void)reloadMessage

{

//获取数据管理器

NSManagedObjectContext *managerContext = [XMPPManager defaultXMPPManager].managerContext;

//请求对象

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

//实体描述对象

//XMPPMessageArchiving_Message_CoreDataObject是持久化信息对应的实体类

NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:managerContext];

[fetchRequest setEntity:entity];

// 查询条件

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"bareJidStr == %@ AND streamBareJidStr == %@", self.friendJID.bare,[XMPPManager defaultXMPPManager].stream.myJID.bare];

[fetchRequest setPredicate:predicate];

// 排序

//按照时间排序

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timestamp"

ascending:YES];

[fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];

NSError *error = nil;

//执行查询,获取符合条件的对象

NSArray *fetchedObjects = [managerContext executeFetchRequest:fetchRequest error:&error];

if (fetchedObjects == nil) {

NSLog(@"your content is null for search");

}

//将查询到的本地聊天信息存放到数组中

[self.messageArray addObjectsFromArray:fetchedObjects];

//刷新数据

[self.tableView reloadData];

}

//展示信息

- (void)showMessageWithMessage:(XMPPMessage *)message {

//将信息放入数组

[self.messageArray addObject:message];

//刷新数据

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.messageArray.count - 1 inSection:0];

[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];

//滑动tableView到对应的cell

[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:(UITableViewScrollPositionBottom) animated:YES];

}

#pragma mark - XMPPSteamDelegate

//接收信息

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

NSLog(@"%@",message.body);

//只获取当前好友的聊天信息

if ([message.from.user isEqualToString:self.friendJID.user]) {

//展示信息

[self showMessageWithMessage:message];

}

}

//发送信息

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

[self showMessageWithMessage:message];

}

/*

#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

// Get the new view controller using [segue destinationViewController].

// Pass the selected object to the new view controller.

}

*/

@end

时间: 2024-08-21 22:49:45

XMPP即时通讯(代码实现)的相关文章

分享基于Android系统的XMPP即时通讯技术项目实战(仿微信开发架构,自定义控件)

即时通讯技术是 网络技术中的明珠.即时通讯产品改变了人们的生活习惯.经过十几年的发展,即时通讯功能的应用也逐渐从专门软件才能实现的功能逐渐成为标准配置.即时通讯技术的应用不仅仅只是用于社交领域,在大多的协同工作领域,以及需要分布结构的网络通讯领域都是非常重要的.讲师本人在android领域有多年的开发经验,在即时通讯系统方面也有深入的研究.在本课程中,详细讲解了android开发中要解决的一些主要的问题,即时通讯在客户端实现的过程,并手把手的进行操作,方便学习和理解.因为课时的原因,对于一些初级

xmPP(即时通讯)向远程服务器请求数据

首先在本地初始化一个数据库 - (void)initDatabase { //最终数据库路径 NSString *dbPath  = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/database.db"]; NSFileManager *fm = [NSFileManager defaultManager]; if(![fm fileExistsAtPath:dbPath]) { EGODatabase*

xmpp即时通讯协议的特性---长处和缺点!

xmpp协议的定义? XMPP是一种基于标准通用标记语言的子集XML的协议,它继承了在XML环境中灵活的发展性. 因此.基于XMPP的应用具有超强的可扩展性.经过扩展以后的XMPP能够通过发送扩展的信息来处理用户的需求.以及在XMPP的顶端建立如内容公布系统和基于地址的服务等应用程 序. 并且,XMPP包括了针对server端的软件协议,使之能与还有一个进行通话,这使得开发人员更easy建立客户应用程序或给一个配好系统加入功能. 在此我概括一下xmpp协议的优缺点: 长处: XMPP协议是自由.

iOS开发之XMPP即时通讯简单实现

首先搭载服务器和数据库 搭载服务器我用的是openfire,数据库用的是mysql 这里推荐两个链接 配置mysql,用的是mysql workbench http://justsee.iteye.com/blog/1753467 配置服务器 openfire http://www.cnblogs.com/xiaodao/archive/2013/04/05/3000554.html 先配置好数据库然后配置服务器 两个都打开 下一个XMPP客户端,就是用来测试的 我下的是Adium 这里下 ht

XMPP即时通讯

XMPP:XMPP是基于XML的点对点通讯协议,The Extensible Messaging and Presence Protocol(可扩展通讯和表示协议). XMPP可用于服务类实时通讯,表示和需求响应服务中的XML数据元流失传输.XMPP以Jabber协议为基础,而Jabber是即时通讯中常用的开放式协议. 基本结构. XML是一个典型的C/S架构,而不是像大多数即时通讯软件一样,使用P2P客户端到客户端的架构,也就是说在大多数情况下,当两个客户端进行通讯时,他们的消息都是通过服务器

XMPP - 即时通讯技术

XMPP-即时通讯技术简介 (IM -- Instant Messaging)支持用户在线实时交谈.如果要发送一条信息,用户需要打开一个小窗口,以便让用户及其朋友在其中输入信息并让交谈双方都看到交谈的内容 有许多的IM系统,如AOL.Yahoo IM. MSN以及QQ,它们最大的区别在于各自通讯协议的实现,所以即时通讯技术的核心在于它的传输协议 协议用来说明信息在网络上如何传输,如果有了统一的传输协议,那么应当可以实现各个IM之间的直接通讯,为了创建即时通讯的统一标准,目前已经出现过的IM协议包

项目开发--------XMPP即时通讯

一.基本框架结构: StroyBoard的基本页面搭建: 二.个功能代码块的是实现 LoginViewController.m文件(登录页面的基本配置) #import "LoginViewController.h" #import "XMPPManager.h" @interface LoginViewController ()<XMPPStreamDelegate> @property (weak, nonatomic) IBOutlet UITex

xmpp即时通讯协议的特性---优点和缺点!

xmpp协议的定义? XMPP是一种基于标准通用标记语言的子集XML的协议,它继承了在XML环境中灵活的发展性.因此,基于XMPP的应用具有超强的可扩展性.经过扩展以后的XMPP可以通过发送扩展的信息来处理用户的需求,以及在XMPP的顶端建立如内容发布系统和基于地址的服务等应用程 序.而且,XMPP包含了针对服务器端的软件协议,使之能与另一个进行通话,这使得开发者更容易建立客户应用程序或给一个配好系统添加功能. 在此我概括一下xmpp协议的优缺点: 优点: XMPP协议是自由.开放.公开的,并且

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 <UIK