项目开发--------XMPP即时通讯
一.基本框架结构:
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;//此时将枚举属性的值设为connectToSeverLoginself.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和域名,创建一个jidXMPPJID *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];//获取好友的jidXMPPJID *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 {//获取点击的cellUITableViewCell *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 sectionsreturn 1; }- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { #warning Incomplete implementation, return the number of rowsreturn _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
转载于:https://www.cnblogs.com/erdeng/p/4951143.html
项目开发--------XMPP即时通讯相关推荐
- Android-IM从零开始开发一个即时通讯项目
Android-IM从零开始开发一个即时通讯项目 https://www.jianshu.com/p/dca480006691 关于聊天室项目 聊天室项目,也被称为即时通讯(IM). 其原理是服务器是 ...
- 基于Android开发的即时通讯聊天app
基于Android开发的即时通讯聊天app 前言 即时通讯(Instant Messaging,简称IM)在互联网中应用十分广泛,它可以和很多的领域结合,发挥十分重要的作用.比如金融行业的支付宝.各大 ...
- [go学习笔记.第十六章.TCP编程] 3.项目-海量用户即时通讯系统-redis介入,用户登录,注册
1.实现功能-完成用户登录 在redis手动添加测试用户,并画出示意图以及说明注意事项(后续通过程序注册用户) 如:输入用户名和密码,如果在redis中存在并正确,则登录,否则退出系统,并给出相应提示 ...
- Android基于环信开发的即时通讯APP
Android基于环信开发的即时通讯APP,源代码在Github上,GitHub地址为:https://github.com/PowerDos/BLChat ,希望能够帮到你们,下面是系统简介. 简介 ...
- winform服务器消息推送,winform项目——仿QQ即时通讯程序12:服务端程序补充及优化...
原标题:winform项目--仿QQ即时通讯程序12:服务端程序补充及优化 上一篇文章大概完成了服务端程序,今天继续做项目的时候发现还有一些功能没有做,还有几处地方不够完善.不做好就会影响客户端程序的 ...
- talent-aio1.0.2 发布,让天下没有难开发的即时通讯
web开发领域,springmvc之外有jfinal:TCP长连接领域,netty之外还有更易用的talent-aio 更好用.更接开发人员地气的TCP长连接框架,talent-aio 1.0.2正式 ...
- xmpp即时通讯的笔记(摘抄)
xmpp的使用: 即时通讯 instant messaging(IM) : -->实时收发信息! 即时通讯相关软件: **QQ,MSN,GoogleTalk,AIM,Jabber(XMPP别名 ...
- 视频开发(即时通讯平台)
当前,全球环境瞬息万变,快捷的信息沟通已经成为人们正常生活的必须,而视频通信的正是借助这一市场需求完成了由"信息化代表"到"代表信息化"的完美蜕变.市场细化应用 ...
- winform项目_winform项目——仿QQ即时通讯程序01:原理及项目分析
即时通讯程序,腾讯QQ可以说是一家独大,虽然市场上仍然有类似QQ的即时通讯程序,但是基本上面向的对象都是特定人群.那么,现在做一个即时通讯的软件还有意义吗?在我看来,意义非常大.作为一个学习编程的人, ...
最新文章
- 我被编程语言PUA了!用互联网黑话写代码,每天都在“赋能”变量
- java端模拟http的get、post请求(转)
- vscode快捷替换json格式
- 鼠标右键 移动选定的文件夹到指定位置_iRightMouse:一款免费Mac鼠标右键增强神器...
- rust怎么关阳光指令_我家也有庭院多好,伸缩阳光房装上,能休闲能当车库,还不算违建...
- 使用Image.GetThumbnailImage 方法返回缩略图
- react 版权问题_react兼容ie
- php tp框架文档,Thinkphp 框架基础之入口文件功能、定义与用法分析
- java 怎么入门_学习java怎么入门
- 免费下载百度文库文档、免注册、免登录、免财富值 - 帮手网-云下载
- ManualResetEvent
- 达梦单机数据库服务器磁盘空间占满问题
- 天翼网关最新超级密码2020_5G 下体验阿里云盘后,我决定继续用天翼和度盘
- Latex排版学习笔记(1)——希腊字母表及其在latex中的表示
- 野蛮人传教士问题(上)
- TMS320F28335入门(七)eCAP学习
- NVIDIA Jetson TK1学习与开发——简介(针对嵌入式系统应用释放 GPU 的潜能)
- 苏州大学转专业计算机2019汇总,关于2019-2020学年第一学期普通本科生转专业名单的公示...
- 服务器普通硬盘,服务器硬盘和普通硬盘区别
- ettercap局域网arp欺骗,轻松窃密
热门文章
- tensorflow dataset.shuffle dataset.batch dataset.repeat 理解 注意点
- python怎么实现输入多行文字_介绍一个Python 包,几行代码可实现 OCR 文本识别!...
- mysql无法存储文字_mysql存储不了中文字符串怎么办
- 在eclipse导入SSH项目
- C#xml创建修改读取删除帮助类XmlHelper.cs
- Three.js中实现点击按钮添加删除旋转立方体
- Windows下使用Java API操作HDFS的常用方法
- Node搭建静态资源服务器时后缀名与响应头映射关系的Json文件
- MongoDb在Windows上的下载安装以及可视化工具的下载与使用
- C#中调用Windows系统服务exe程序的工具类与重启服务的流程