标签:
一.基本框架结构:
StroyBoard的基本页面搭建:
二.个功能代码块的是实现
LoginViewController.m文件(登录页面的基本配置)
#import "LoginViewController.h"
#import "XMPPManager.h"
@interface LoginViewController ()<XMPPStreamDelegate>
@property (weak, nonatomic) IBOutlet UITextField *userNameTes;
@property (weak, nonatomic) IBOutlet UITextField *passwordTes;
@end
@implementation LoginViewController
- (void)viewDidLoad {
[super viewDidLoad];
//添加代理方法
[[XMPPManager sharedXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
}
#pragma mark ---实现XMPPStreamDelegate中的代理方法
//认证登录成功的代理方法
-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
NSLog(@"登录成功");
//登陆成功进入好友聊天页面
[self dismissViewControllerAnimated:YES completion:nil];
}
//认证登录失败的代理方法
-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error
{
NSLog(@"登录失败%@",error);
}
- (IBAction)loginWithUserNameAndPassword:(id)sender {
//登录
[[XMPPManager sharedXMPPManager] loginWithUserName:self.userNameTes.text passWord:self.passwordTes.text];
}
@end
RegisterViewController.m文(注册页面的基本配置)
#import "RegisterViewController.h"
#import "XMPPManager.h"
@interface RegisterViewController () <XMPPStreamDelegate>
@property (weak, nonatomic) IBOutlet UITextField *userNameTes;
@property (weak, nonatomic) IBOutlet UITextField *passwordTes;
@end
@implementation RegisterViewController
- (void)viewDidLoad {
[super viewDidLoad];
//给stream 设置代理监测注册是否成功
[[XMPPManager sharedXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
}
#pragma mark ---实现XMPPStreamDelegate中的代理方法
//注册成功
-(void)xmppStreamDidRegister:(XMPPStream *)sender
{
NSLog(@"注册成功");
//注册成功 进入登陆页面
[self.navigationController popViewControllerAnimated:YES];
}
//注册失败
-(void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error
{
NSLog(@"注册失败");
}
- (IBAction)registerWithUserNameAndPassword:(id)sender {
//注册
[[XMPPManager sharedXMPPManager] registerWithUserName:self.userNameTes.text passWord:self.passwordTes.text];
}
@end
XMPPManager.h文件 (主要功能实现文件)
#import <Foundation/Foundation.h>
#import "XMPPFramework.h"
@interface XMPPManager : NSObject<XMPPStreamDelegate>
//声明一个‘通道‘属性 为了其他类中能够访问到
@property(nonatomic,strong)XMPPStream *stream;
//与好友有关的操作
@property(nonatomic,strong)XMPPRoster *roster;
//与聊天信息有关的 聊天信息托管上下文
@property(nonatomic,strong)NSManagedObjectContext *context;
//信息归档 聊天信息归档对象
@property(nonatomic,strong)XMPPMessageArchiving *messageAchiving;
#pragma mark ---获取一个单例对象
+(XMPPManager *)sharedXMPPManager;
#pragma mark ---登录
-(void)loginWithUserName:(NSString *)userName passWord:(NSString *)passWord;
#pragma mark ---注册
-(void)registerWithUserName:(NSString *)userName passWord:(NSString *)passWord;
#pragma mark ---删除好友
-(void)removeFriendName:(NSString *)name;
@end
XMPPManager.m文件(主要功能实现文件)
#import "XMPPManager.h"
//枚举
typedef NS_ENUM(NSUInteger,connectToSeverType){
connectToSeverLogin,
connectToSeverRegister
};
//枚举
//typedef enum : NSUInteger {
// <#MyEnumValueA#>,
// <#MyEnumValueB#>,
// <#MyEnumValueC#>,
//} <#MyEnum#>;
@interface XMPPManager ()
//登录用户名
@property(nonatomic,strong)NSString *LoginuserName;
//登录密码
@property(nonatomic,strong)NSString *loginPassWord;
//注册名
@property(nonatomic,strong)NSString *registerUserName;
//注册密码
@property(nonatomic,strong)NSString *registerPassWord;
//用来表示访问服务器的目的(登录或注册)
@property(nonatomic,assign)connectToSeverType connectPurpose;
@end
@implementation XMPPManager
#pragma mark ---获取一个单例对象
+(XMPPManager *)sharedXMPPManager
{
static XMPPManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[XMPPManager alloc] init];
});
return manager;
}
//重写XMPPManager的init方法,是为了创建 通道(xmppStream)
//init方法
- (instancetype)init
{
self = [super init];
if (self) {
//初始化通道
self.stream = [[XMPPStream alloc] init];
//指定其连接的服务器IP地址
self.stream.hostName = kHostName;
//指定服务器端口 默认为5222
//端口号 是制定当前连接的是什么服务
self.stream.hostPort = kHostPort;
//给stream设置代理,来检测链接状态和认证状态
[self.stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
//初始化管理好友对象roster(与好友相关的操作)
XMPPRosterCoreDataStorage *storage = [XMPPRosterCoreDataStorage sharedInstance];
self.roster = [[XMPPRoster alloc] initWithRosterStorage:storage dispatchQueue:dispatch_get_main_queue()];
//在管道上激活对象
[self.roster activate:self.stream];
//初始化messageAchiving对象
XMPPMessageArchivingCoreDataStorage *messageStroge = [XMPPMessageArchivingCoreDataStorage sharedInstance];
self.messageAchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:messageStroge dispatchQueue:dispatch_get_main_queue()];
//激活
[self.messageAchiving activate:self.stream];
//托管上下文对象
self.context = messageStroge.mainThreadManagedObjectContext;
}
return self;
}
#pragma mark ---登录
-(void)loginWithUserName:(NSString *)userName passWord:(NSString *)passWord
{
self.loginPassWord = userName;
self.LoginuserName = userName;
//此时将枚举属性的值设为connectToSeverLogin
self.connectPurpose = connectToSeverLogin;
//链接
[self linkConnect];
}
//链接的方法
-(void)linkConnect
{
//在真正链接之前,需要告诉服务器你是谁,
//XMPPJID在Xmpp中身份的唯一标识
XMPPJID *myJID = nil;
switch (self.connectPurpose) {
case connectToSeverLogin:{
myJID = [XMPPJID jidWithUser:self.LoginuserName domain:kDomin resource:kResource];
break;
}
case connectToSeverRegister:{
myJID = [XMPPJID jidWithUser:self.registerUserName domain:kDomin resource:kResource];
break;
}
default:
break;
}
// XMPPJID *myJID = [XMPPJID jidWithUser:self.LoginuserName domain:kDomin resource:kResource];
//将自己的JID设置到Stream通道上
self.stream.myJID = myJID;
//开始链接
if ([self.stream isConnected] || [self.stream isConnecting]) {
//先断开
[self disconnectToSever];
}
//连接到服务器
NSError *error = nil;
[self.stream connectWithTimeout:30.0 error:
&error];
if (error) {
NSLog(@"error:%@",error);
}
}
//断开链接
-(void)disconnectToSever{
//设置下线状态元素
XMPPPresence *pressence = [XMPPPresence presenceWithType:@"unavailable"];
//将stream上的状态改为下线
[self.stream sendElement:pressence];
//断开链接
[self.stream disconnect];
}
#pragma mark ---注册
-(void)registerWithUserName:(NSString *)userName passWord:(NSString *)passWord
{
self.registerPassWord = passWord;
self.registerUserName = userName;
//将枚举值设为注册
self.connectPurpose = connectToSeverRegister;
//链接
[self linkConnect];
}
#pragma mark ---XMPPStreamDelegate的方法
//链接成功
-(void)xmppStreamDidConnect:(XMPPStream *)sender
{
NSLog(@"连接成功");
//进行认证
switch (self.connectPurpose) {
case connectToSeverLogin:
//如果链接的目的是登录,这里需要一个登录的passWord
[self.stream authenticateWithPassword:self.loginPassWord error:nil];
break;
case connectToSeverRegister:
//如果链接的目的是注册,这里需要一个注册的passWord
[self.stream registerWithPassword:self.registerPassWord error:nil];
break;
default:
break;
}
}
//链接失败
-(void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
{
NSLog(@"连接失败%@",error);
}
//链接超时
-(void)xmppStreamConnectDidTimeout:(XMPPStream *)sender
{
NSLog(@"链接超时");
}
//认证成功
-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
NSLog(@"认证成功");
//设置上线状态
XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"];
[self.stream sendElement:presence];
}
#pragma mark ---删除好友
-(void)removeFriendName:(NSString *)name
{
//根据username和域名,创建一个jid
XMPPJID *friendJid = [XMPPJID jidWithString:[NSString stringWithFormat:@"%@@%@",name,kDomin ]];
//取消对好友的监听
[self.roster unsubscribePresenceFromUser:friendJid];
//将好友移除
[self.roster removeUser:friendJid];
}
@end
RosterTableViewController.m文件(好友界面功能的实现)
#import "RosterTableViewController.h"
#import "XMPPManager.h"
#import "ChatTableViewController.h"
@interface RosterTableViewController ()<XMPPRosterDelegate,UIAlertViewDelegate,XMPPStreamDelegate>
//所有好友
@property(nonatomic,strong)NSMutableArray *allRoster;
//请求者的jid
@property(nonatomic,strong)XMPPJID *requestJid;
@end
//存放所有的好友
@implementation RosterTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
//对数组进行初始化
self.allRoster = [NSMutableArray array];
//通过代理协议,获取好友
[[XMPPManager sharedXMPPManager].roster addDelegate:self delegateQueue:dispatch_get_main_queue()];
//监听好友的状态 通过代理协议的形式
[[XMPPManager sharedXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
}
#pragma mark ---实现XMPPRosterDelegate协议中的方法
//开始获取好友
-(void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender
{
NSLog(@"开始获取好友");
}
//正在获取好友 有几个好友这个放法就会执行几次
-(void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item
{
NSLog(@"%@",item);
//to 订阅了别人
//from 别人订阅了你
//both 互为好友
NSString *subscription = [[item attributeForName:@"subscription"] stringValue];
if ([subscription isEqualToString:@"from"] || [subscription isEqualToString:@"both"]) {
//获取好友的jid字符串
NSString *jidStr = [[item attributeForName:@"jid" ] stringValue];
//获取好友的jid
XMPPJID *frienfJid = [XMPPJID jidWithString:jidStr];
//如果之前加过了,表示好友已经存在
if ([_allRoster containsObject:frienfJid ]) {
return;
}
//将好友对象(frienfJid) 添加到数组中
[self.allRoster addObject:frienfJid];
//插入行
//插入到最后一行
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.allRoster.count - 1 inSection:0];
[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
//结束获取好友
-(void)xmppRosterDidEndPopulating:(XMPPRoster *)sender
{
NSLog(@"好友获取结束");
}
//获取好友请求
-(void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
{
NSLog(@"获取好友请求!");
self.requestJid = presence.from;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"好友请求" message:_requestJid.user delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
[alert show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch (buttonIndex) {
case 0:
//点击拒绝按钮
[[XMPPManager sharedXMPPManager].roster rejectPresenceSubscriptionRequestFrom:self.requestJid];
break;
case 1:
//接受请求按钮
[[XMPPManager sharedXMPPManager].roster acceptPresenceSubscriptionRequestFrom:self.requestJid andAddToRoster:NO];
break;
default:
break;
}
self.requestJid = nil;
}
#pragma mark --实现XMPPStreamDelegate中的方法
//监听好友的状态
-(void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
//监测好友的状态
NSString *presenceType = presence.type;
if ([presenceType isEqualToString:@"available"]) {
NSLog(@"好友在线状态!");
} else if ([presenceType isEqualToString:@"unavailable"])
NSLog(@"好友处于下线状态!");
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return self.allRoster.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"roster" forIndexPath:indexPath];
XMPPJID *friendJid = _allRoster[indexPath.row];
cell.textLabel.text = friendJid.user;
return cell;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//删除数据源
XMPPJID *jid = _allRoster[indexPath.row];
[[XMPPManager sharedXMPPManager]removeFriendName:jid.user];
[self.allRoster removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
#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 {
//获取点击的cell
UITableViewCell *cell = (UITableViewCell *)sender;
NSIndexPath *indexPah = [self.tableView indexPathForCell:cell];
ChatTableViewController *chatVC = (ChatTableViewController *)segue.destinationViewController;
chatVC.chatToJid = _allRoster[indexPah.row];
}
@end
ChatTableViewController.h文件(聊天界面功能的实现)
#import <UIKit/UIKit.h>
#import "XMPPManager.h"
@interface ChatTableViewController : UITableViewController
@property(nonatomic,strong)XMPPJID *chatToJid;
@end
ChatTableViewController.m文件(聊天界面功能的实现)
#import "ChatTableViewController.h"
#import "XMPPManager.h"
@interface ChatTableViewController ()<XMPPStreamDelegate>
//信息数组
@property(nonatomic,strong)NSMutableArray *allMessages;
- (IBAction)sendMessage:(UIBarButtonItem *)sender;
@end
@implementation ChatTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
//初始化数组
self.allMessages = [NSMutableArray array];
//设置代理
[[XMPPManager sharedXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
//显示历史记录
[self parseMesage];
}
#pragma mark --实现协议中的方法
//已经接受好友发送的信息
-(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
NSLog(@"已经接受信息:%@",message);
[self parseMesage];
}
-(void)parseMesage
{
//查询请求
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:[XMPPManager sharedXMPPManager].context];
[fetchRequest setEntity:entity];
// Specify criteria for filtering which objects to fetch
//谓词 查询条件
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"bareJidStr == %@ AND streamBareJidStr == %@", _chatToJid.bare,[XMPPManager sharedXMPPManager].stream.myJID.bare];
[fetchRequest setPredicate:predicate];
// Specify how the fetched objects should be sorted
//排序
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timestamp"
ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];
NSError *error = nil;
NSArray *fetchedObjects = [[XMPPManager sharedXMPPManager].context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
NSLog(@"没有聊天记录!");
} else {
//清空之前的聊天记录
[self.allMessages removeAllObjects];
[self.allMessages addObjectsFromArray:fetchedObjects];
[self.tableView reloadData];
if (_allMessages.count == 0) {
return;
}
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.allMessages.count -1 inSection:0];
[self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionBottom];
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
#warning Incomplete implementation, return the number of sections
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
#warning Incomplete implementation, return the number of rows
return _allMessages.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"chat" forIndexPath:indexPath];
XMPPMessageArchiving_Message_CoreDataObject *message = _allMessages[indexPath.row];
if (message.isOutgoing == YES) { //自己发的
cell.detailTextLabel.text = message.body;
cell.textLabel.text = @"";
} else {
cell.textLabel.text = message.body;
cell.detailTextLabel.text = @"";
}
return cell;
}
#pragma mark --给好友发送消息
- (IBAction)sendMessage:(UIBarButtonItem *)sender {
//发送给谁消息(Jid)
XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatToJid];
//设置发送内容
[message addBody:@"你好!"];
//开始发送
[[XMPPManager sharedXMPPManager].stream sendElement:message];
}
//信息发送成功
-(void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message
{
NSLog(@"信息发送成功:%@",message);
[self parseMesage];
}
//信息发送失败
-(void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error
{
NSLog(@"信息发送失败:%@",error);
}
@end
标签:
原文地址:http://www.cnblogs.com/erdeng/p/4951143.html