码迷,mamicode.com
首页 > 其他好文 > 详细

即时通信

时间:2016-05-22 21:33:11      阅读:180      评论:0      收藏:0      [点我收藏+]

标签:

XMPPManager.h

 1 #import <Foundation/Foundation.h>
 2 #import "XMPPFramework.h"
 3 
 4 @interface XMPPManager : NSObject
 5 
 6 /**
 7  *  创建一个通道的属性
 8  */
 9 @property (nonatomic, strong) XMPPStream *xmppStream;
10 
11 /**
12  *  管理好友,好友的列表
13  */
14 @property (nonatomic, strong) XMPPRoster *xmppRoster;
15 
16 /**
17  *  和聊天相关的属性
18  */
19 @property (nonatomic, strong) XMPPMessageArchiving *messageArchiving;
20 
21 /**
22  *  消息归档
23  */
24 @property (nonatomic, strong) NSManagedObjectContext *context;
25 
26 
27 // 创建单例
28 + (instancetype)shareManager;
29 
30 // 登录的方法
31 - (void)loginWithUserName:(NSString *)userName password:(NSString *)password;
32 
33 // 注册的方法
34 - (void)registerWithUserName:(NSString *)userName password:(NSString *)password;
35 
36 // 添加好友
37 - (void)addFriend;
38 // 删除好友
39 - (void)removeFriendWithName:(NSString *)name;
40 
41 @end

XMPPManager.m

  1 #import "XMPPManager.h"
  2 
  3 // 列举枚举(登录和注册)
  4 typedef NS_ENUM(NSInteger, ConnectToServerPurpose) {
  5     ConnectToServerPurposeLogin,
  6     ConnectToServerPurposeRegister,
  7 };
  8 
  9 
 10 @interface XMPPManager () <XMPPStreamDelegate, XMPPRosterDelegate>
 11 
 12 // 登录的属性
 13 @property (nonatomic, strong) NSString *userName;  // 用户名
 14 @property (nonatomic, strong) NSString *password;  // 密码
 15 
 16 // 注册的属性
 17 @property (nonatomic, strong) NSString *registerUserName;  // 用户名
 18 @property (nonatomic, strong) NSString *registerPassword;  // 密码
 19 
 20 // 记录当前是登录还是注册
 21 @property (nonatomic, assign) ConnectToServerPurpose connectToserver;
 22 
 23 // 接收添加好友的名字
 24 @property (nonatomic, strong) UITextField *textField;
 25 
 26 @end
 27 
 28 
 29 static XMPPManager *xmpp = nil;
 30 
 31 @implementation XMPPManager
 32 
 33 // 创建单例
 34 + (instancetype)shareManager {
 35     
 36     static dispatch_once_t onceToken;
 37     dispatch_once(&onceToken, ^{
 38         xmpp = [[XMPPManager alloc] init];
 39     });
 40     return xmpp;
 41 }
 42 
 43 
 44 #pragma mark - 初始化
 45 - (instancetype)init {
 46     
 47     if (self = [super init]) {
 48         
 49 #pragma mark - 初始化通道
 50         // 初始化通道对象
 51         self.xmppStream = [[XMPPStream alloc] init];
 52         
 53         // 设置openfire服务器地址
 54         self.xmppStream.hostName = kHostName;
 55         
 56         // 设置服务器端口号
 57         self.xmppStream.hostPort = kHostPort;
 58         
 59         // 添加代理
 60         [self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
 61         
 62         
 63 #pragma mark - 管理好友
 64         //获取管理好友的单例对象
 65         XMPPRosterCoreDataStorage *rosterStorage = [XMPPRosterCoreDataStorage sharedInstance];
 66         
 67         // 初始化好友列表
 68         self.xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:rosterStorage dispatchQueue:dispatch_get_global_queue(0, DISPATCH_QUEUE_PRIORITY_BACKGROUND)];
 69         
 70         // 在通道中激活添加好友
 71         [self.xmppRoster activate:self.xmppStream];
 72         
 73         // 设置花名册代理
 74         [self.xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
 75         
 76         
 77 #pragma mark - 管理消息
 78         // 获取管理消息的存储对象
 79         XMPPMessageArchivingCoreDataStorage *storage = [XMPPMessageArchivingCoreDataStorage sharedInstance];
 80         
 81         // 进行消息管理器的初始化
 82         self.messageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:storage dispatchQueue:dispatch_get_main_queue()];
 83         
 84         // 在通道中激活
 85         [self.messageArchiving activate:self.xmppStream];
 86         
 87         // 设置代理
 88         [self.messageArchiving addDelegate:self delegateQueue:dispatch_get_main_queue()];
 89         
 90         // 管理上下文
 91         self.context = storage.mainThreadManagedObjectContext;
 92         
 93     }
 94 
 95     return self;
 96 }
 97 
 98 
 99 #pragma mark - 登录和注册的方法
100 // 登录方法的实现
101 - (void)loginWithUserName:(NSString *)userName password:(NSString *)password {
102     
103     self.userName = userName;
104     self.password= password;
105     
106     // 记录登录状态
107     self.connectToserver = ConnectToServerPurposeLogin;
108     
109     // 连接服务器
110     [self linkServer];
111 }
112 
113 
114 // 注册方法的实现
115 - (void)registerWithUserName:(NSString *)userName password:(NSString *)password {
116     
117     self.registerUserName = userName;
118     self.registerPassword = password;
119     
120     // 记录登录状态
121     self.connectToserver = ConnectToServerPurposeRegister;
122     
123     // 连接服务器
124     [self linkServer];
125 }
126 
127 
128 #pragma mark - 连接服务器
129 - (void)linkServer {
130     
131     // 判断是登录还是注册
132     NSString *string = [[NSString alloc] init];
133     switch (self.connectToserver) {
134         case ConnectToServerPurposeLogin:
135             string = [NSString stringWithFormat:@"%@", self.userName];
136             break;
137         case ConnectToServerPurposeRegister:
138             string = [NSString stringWithFormat:@"%@", self.registerUserName];
139             break;
140             
141         default:
142             break;
143     }
144     
145     // 要链接服务器,要有用户认证
146     // 身份证
147     // 参数1:用户名
148     // 参数2:域名
149     // 参数3:资源
150     // 通过通道进行身份验证
151     XMPPJID *jid = [XMPPJID jidWithUser:string domain:kDomin resource:kResource];
152     self.xmppStream.myJID = jid;
153     
154     // 如果当前聊天工具处于链接状态或者已经链接了,此时,你需要去切断链接,【此逻辑不唯一】
155     if ([self.xmppStream isConnected] || [self.xmppStream isConnecting]) {
156         [self disconnectToServer];
157     }
158     
159     // 链接超时
160     NSError *error = nil;
161     [self.xmppStream connectWithTimeout:5 error:&error];
162     
163     if (error) {
164         NSLog(@"服务器链接超时");
165     }
166 }
167 
168 
169 // 断开链接
170 - (void)disconnectToServer {
171     
172     // 当前用户下线了
173     XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
174     
175     // 告诉通道下线了
176     [self.xmppStream sendElement:presence];
177     
178     // 使通道失去链接
179     [self.xmppStream disconnect];
180 }
181 
182 
183 #pragma mark - XMPPStreamDelegate协议方法
184 #pragma mark - 链接超时
185 - (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender {
186     
187     NSLog(@"连接超时");
188 }
189 
190 
191 #pragma mark - 连接成功
192 - (void)xmppStreamDidConnect:(XMPPStream *)sender {
193     
194     NSLog(@"连接成功");
195     
196     // 区分登录和注册进行密码验证
197     switch (self.connectToserver) {
198         case ConnectToServerPurposeLogin:
199             // 登录密码的验证
200             [self.xmppStream authenticateWithPassword:self.password error:nil];
201             break;
202         case ConnectToServerPurposeRegister:
203             // 注册密码的验证
204             [self.xmppStream registerWithPassword:self.registerPassword error:nil];
205             break;
206             
207         default:
208             break;
209     }
210 }
211 
212 
213 #pragma mark - 断开链接
214 - (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error {
215     
216     // 1.自己手动断开
217     // 2.被动断开
218     if (error) {
219         NSLog(@"断开链接,error = %@", error);
220     }
221 }
222 
223 
224 #pragma mark - 认证失败(登录失败)
225 - (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error {
226     
227     NSLog(@"认证失败, error = %@", error);
228 }
229 
230 
231 #pragma mark - 认证成功(登录成功)
232 - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
233     
234     // 上线
235     XMPPPresence *presennce = [XMPPPresence presenceWithType:@"available"];
236     [self.xmppStream sendElement:presennce];
237     
238     NSLog(@"登录成功");
239 }
240 
241 
242 #pragma mark - 添加好友
243 - (void)addFriend {
244     
245     UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"添加好友" message:@"请输入好友的姓名" preferredStyle:UIAlertControllerStyleAlert];
246     
247     __weak typeof(self)mySelf = self;
248     [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
249         mySelf.textField = textField;
250     }];
251     
252     UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
253         NSLog(@"取消添加好友");
254     }];
255     UIAlertAction *action2 = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
256         // 使用JID记录
257         XMPPJID *friendJID = [XMPPJID jidWithUser:mySelf.textField.text domain:kDomin resource:kResource];
258         
259         // 监听好友的动作
260         [mySelf.xmppRoster subscribePresenceToUser:friendJID];
261         NSLog(@"===============%@", mySelf.textField.text);
262         // 添加好友
263         [mySelf.xmppRoster addUser:friendJID withNickname:mySelf.textField.text];
264     }];
265     
266     [alertController addAction:action1];
267     [alertController addAction:action2];
268     
269     [[self getCurrentVC] presentViewController:alertController animated:YES completion:nil];
270 }
271 
272 
273 //获取当前屏幕显示的viewcontroller
274 - (UIViewController *)getCurrentVC
275 {
276     UIViewController *result = nil;
277     
278     UIWindow * window = [[UIApplication sharedApplication] keyWindow];
279     if (window.windowLevel != UIWindowLevelNormal)
280     {
281         NSArray *windows = [[UIApplication sharedApplication] windows];
282         for(UIWindow * tmpWin in windows)
283         {
284             if (tmpWin.windowLevel == UIWindowLevelNormal)
285             {
286                 window = tmpWin;
287                 break;
288             }
289         }
290     }
291     
292     UIView *frontView = [[window subviews] objectAtIndex:0];
293     id nextResponder = [frontView nextResponder];
294     
295     if ([nextResponder isKindOfClass:[UIViewController class]])
296         result = nextResponder;
297     else
298         result = window.rootViewController;
299     
300     return result;
301 }
302 
303 
304 #pragma mark - 删除好友
305 - (void)removeFriendWithName:(NSString *)name {
306     
307     // 使用JID记录要删除的用户
308     XMPPJID *friendJID = [XMPPJID jidWithUser:name domain:kDomin resource:kResource];
309     
310     // 停止监听好友
311     [self.xmppRoster unsubscribePresenceFromUser:friendJID];
312     
313     // 删除好友
314     [self.xmppRoster removeUser:friendJID];
315 }
316 
317 
318 #pragma mark - XMPPRosterDelegate代理方法
319 // 开始获取好友
320 - (void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender {
321     
322     NSLog(@"开始获取好友");
323 }
324 
325 
326 // 结束获取好友
327 - (void)xmppRosterDidEndPopulating:(XMPPRoster *)sender {
328     
329     NSLog(@"结束获取好友");
330 }
331 
332 
333 // 接受好友的信息
334 - (void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item {
335     
336     // 好友状态的显示信息
337     NSLog(@"好友信息====%@", item);
338 }
339 
340 
341 // 收到好友监听请求,是同意还是拒绝
342 - (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence {
343     
344     NSLog(@"获取好友请求");
345 }
346 
347 @end

LoginViewController.m

  1 #import "LoginViewController.h"
  2 #import "Masonry.h"
  3 #import "RegisterViewController.h"
  4 #import "XMPPManager.h"
  5 #import "RosterTableViewController.h"
  6 
  7 @interface LoginViewController () <XMPPStreamDelegate>
  8 
  9 /**
 10  *  姓名输入框
 11  */
 12 @property (nonatomic, strong) UITextField *userTextField;
 13 
 14 /**
 15  *  密码输入框
 16  */
 17 @property (nonatomic, strong) UITextField *passwordTextField;
 18 
 19 /**
 20  *  登录按钮
 21  */
 22 @property (nonatomic, strong) UIButton *loginButton;
 23 
 24 /**
 25  *  注册按钮
 26  */
 27 @property (nonatomic, strong) UIButton *registerButton;
 28 
 29 @end
 30 
 31 @implementation LoginViewController
 32 
 33 - (void)viewDidLoad {
 34     [super viewDidLoad];
 35     // Do any additional setup after loading the view.
 36     
 37     self.navigationItem.title = @"首页";
 38     self.view.backgroundColor = [UIColor orangeColor];
 39     
 40     
 41     // 布局页面
 42     [self initLayout];
 43     
 44     
 45     // 给登录和注册按钮添加事件
 46     [_loginButton addTarget:self action:@selector(loginClick:) forControlEvents:UIControlEventTouchUpInside];
 47     [_registerButton addTarget:self action:@selector(registerClick:) forControlEvents:UIControlEventTouchUpInside];
 48     
 49     
 50     // 设置代理
 51     [[XMPPManager shareManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
 52     
 53 }
 54 
 55 
 56 #pragma mark - 登录和注册按钮的点击事件
 57 // 登录按钮的点击事件
 58 - (void)loginClick:(UIButton *)sender {
 59     
 60     [[XMPPManager shareManager] loginWithUserName:self.userTextField.text password:self.passwordTextField.text];
 61 }
 62 
 63 
 64 // 注册按钮的点击事件
 65 - (void)registerClick:(UIButton *)sender {
 66     
 67     RegisterViewController *registerVC = [[RegisterViewController alloc] init];
 68     [self.navigationController pushViewController:registerVC animated:YES];
 69 }
 70 
 71 
 72 #pragma mark - XMPPStreamDelegate代理方法
 73 // 登录成功
 74 - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
 75     
 76     NSLog(@"登录成功");
 77     
 78     RosterTableViewController *rosterVC = [[RosterTableViewController alloc] init];
 79     [self.navigationController pushViewController:rosterVC animated:YES];
 80 }
 81 
 82 // 登录失败
 83 - (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error {
 84     
 85     NSLog(@"登录失败");
 86 }
 87 
 88 
 89 #pragma mark - 布局页面
 90 - (void)initLayout {
 91     
 92     // 创建子控件
 93     _userTextField = [[UITextField alloc] init];
 94     _userTextField.borderStyle = UITextBorderStyleRoundedRect;
 95     _userTextField.layer.cornerRadius = 5;
 96     _userTextField.backgroundColor = [UIColor whiteColor];
 97     _userTextField.placeholder = @"请输入用户名";
 98     [self.view addSubview:_userTextField];
 99     
100     _passwordTextField = [[UITextField alloc] init];
101     _passwordTextField.borderStyle = UITextBorderStyleRoundedRect;
102     _passwordTextField.layer.cornerRadius = 5;
103     _passwordTextField.backgroundColor = [UIColor whiteColor];
104     _passwordTextField.placeholder = @"请输入密码";
105     [self.view addSubview:_passwordTextField];
106     
107     _loginButton = [UIButton buttonWithType:UIButtonTypeSystem];
108     _loginButton.layer.cornerRadius = 5;
109     [_loginButton setTitle:@"登   录" forState:UIControlStateNormal];
110     [_loginButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
111     _loginButton.backgroundColor = [UIColor whiteColor];
112     [self.view addSubview:_loginButton];
113     
114     _registerButton = [UIButton buttonWithType:UIButtonTypeSystem];
115     _registerButton.layer.cornerRadius = 5;
116     [_registerButton setTitle:@"注   册" forState:UIControlStateNormal];
117     [_registerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
118     _registerButton.backgroundColor = [UIColor whiteColor];
119     [self.view addSubview:_registerButton];
120     
121     
122     // 设置frame
123     [_userTextField mas_makeConstraints:^(MASConstraintMaker *make) {
124         
125         make.top.offset(120);
126         make.left.offset(50);
127         make.right.offset(-50);
128         make.height.mas_equalTo(50);
129         
130     }];
131     
132     [_passwordTextField mas_makeConstraints:^(MASConstraintMaker *make) {
133         
134         make.top.equalTo(_userTextField.mas_bottom).offset(50);
135         make.left.offset(50);
136         make.right.offset(-50);
137         make.height.mas_equalTo(50);
138         
139     }];
140     
141     [_loginButton mas_makeConstraints:^(MASConstraintMaker *make) {
142         
143         make.top.equalTo(_passwordTextField.mas_bottom).offset(50);
144         make.left.offset(80);
145         make.width.mas_equalTo((self.view.frame.size.width - 80 - 80 - 50) / 2);
146         make.height.mas_equalTo(50);
147         
148     }];
149     
150     [_registerButton mas_makeConstraints:^(MASConstraintMaker *make) {
151         
152         make.top.equalTo(_loginButton.mas_top);
153         make.right.offset(-80);
154         make.width.mas_equalTo((self.view.frame.size.width - 80 - 80 - 50) / 2);
155         make.height.mas_equalTo(50);
156         
157     }];
158 }
159 
160 @end

RegisterViewController.m

  1 #import "RegisterViewController.h"
  2 #import "Masonry.h"
  3 #import "XMPPManager.h"
  4 
  5 @interface RegisterViewController () <XMPPStreamDelegate>
  6 
  7 /**
  8  *  姓名输入框
  9  */
 10 @property (nonatomic, strong) UITextField *userTextField;
 11 
 12 /**
 13  *  密码输入框
 14  */
 15 @property (nonatomic, strong) UITextField *passwordTextField;
 16 
 17 /**
 18  *  注册按钮
 19  */
 20 @property (nonatomic, strong) UIButton *registerButton;
 21 
 22 @end
 23 
 24 @implementation RegisterViewController
 25 
 26 - (void)viewDidLoad {
 27     [super viewDidLoad];
 28     // Do any additional setup after loading the view.
 29     
 30     
 31     self.navigationItem.title = @"注册";
 32     self.view.backgroundColor = [UIColor purpleColor];
 33     
 34     
 35     // 页面布局
 36     [self initLayout];
 37     
 38     
 39     // 设置代理
 40     [[XMPPManager shareManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
 41     
 42     
 43     // 注册按钮的点击事件
 44     [_registerButton addTarget:self action:@selector(registerClick:) forControlEvents:UIControlEventTouchUpInside];
 45     
 46 }
 47 
 48 
 49 #pragma mark - 注册按钮点击事件
 50 - (void)registerClick:(UIButton *)sender {
 51     
 52     [[XMPPManager shareManager] registerWithUserName:self.userTextField.text password:self.passwordTextField.text];
 53 }
 54 
 55 
 56 #pragma mark - XMPPStreamDelegate实现协议方法
 57 // 实现协议是为了实现需求:注册成功之后dismiss到登录界面
 58 // 注册成功
 59 - (void)xmppStreamDidRegister:(XMPPStream *)sender {
 60     
 61     NSLog(@"注册成功");
 62     [self.navigationController popViewControllerAnimated:YES];
 63 }
 64 
 65 
 66 // 注册失败
 67 - (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error {
 68     
 69     NSLog(@"注册失败 = %@", error);
 70 }
 71 
 72 
 73 #pragma mark - 布局页面
 74 - (void)initLayout {
 75     
 76     // 创建子控件
 77     _userTextField = [[UITextField alloc] init];
 78     _userTextField.borderStyle = UITextBorderStyleRoundedRect;
 79     _userTextField.layer.cornerRadius = 5;
 80     _userTextField.backgroundColor = [UIColor whiteColor];
 81     _userTextField.placeholder = @"请输入用户名";
 82     [self.view addSubview:_userTextField];
 83     
 84     _passwordTextField = [[UITextField alloc] init];
 85     _passwordTextField.borderStyle = UITextBorderStyleRoundedRect;
 86     _passwordTextField.layer.cornerRadius = 5;
 87     _passwordTextField.backgroundColor = [UIColor whiteColor];
 88     _passwordTextField.placeholder = @"请输入密码";
 89     [self.view addSubview:_passwordTextField];
 90     
 91     _registerButton = [UIButton buttonWithType:UIButtonTypeSystem];
 92     _registerButton.layer.cornerRadius = 5;
 93     [_registerButton setTitle:@"注   册" forState:UIControlStateNormal];
 94     [_registerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
 95     _registerButton.backgroundColor = [UIColor whiteColor];
 96     [self.view addSubview:_registerButton];
 97     
 98     
 99     // 设置frame
100     [_userTextField mas_makeConstraints:^(MASConstraintMaker *make) {
101         
102         make.top.offset(120);
103         make.left.offset(50);
104         make.right.offset(-50);
105         make.height.mas_equalTo(50);
106         
107     }];
108     
109     [_passwordTextField mas_makeConstraints:^(MASConstraintMaker *make) {
110         
111         make.top.equalTo(_userTextField.mas_bottom).offset(50);
112         make.left.offset(50);
113         make.right.offset(-50);
114         make.height.mas_equalTo(50);
115         
116     }];
117     
118     [_registerButton mas_makeConstraints:^(MASConstraintMaker *make) {
119         
120         make.top.equalTo(_passwordTextField.mas_bottom).offset(50);
121         make.left.offset(150);
122         make.right.offset(-150);
123         make.height.mas_equalTo(50);
124         
125     }];
126 }
127 
128 @end

RosterTableViewController.m

  1 #import "RosterTableViewController.h"
  2 #import "XMPPManager.h"
  3 #import "ChatTableViewController.h"
  4 
  5 @interface RosterTableViewController () <XMPPStreamDelegate, XMPPRosterDelegate>
  6 
  7 /**
  8  *  存储好友列表的数组
  9  */
 10 @property (nonatomic, strong) NSMutableArray *allRosterArray;
 11 
 12 /**
 13  *  用来存储发送请求者的JID
 14  */
 15 @property (nonatomic, strong) XMPPJID *fromJID;
 16 
 17 
 18 @end
 19 
 20 @implementation RosterTableViewController
 21 
 22 // 懒加载
 23 - (NSMutableArray *)allRosterArray {
 24     
 25     if (!_allRosterArray) {
 26         _allRosterArray = [NSMutableArray array];
 27     }
 28     return _allRosterArray;
 29 }
 30 
 31 
 32 - (void)viewDidLoad {
 33     [super viewDidLoad];
 34     
 35     
 36     self.navigationItem.title = @"好友列表";
 37     
 38     
 39     // 设置代理
 40     [[XMPPManager shareManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
 41     [[XMPPManager shareManager].xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
 42     
 43     
 44     // 注册cell
 45     [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
 46     
 47     
 48     // 设置添加按钮和返回按钮
 49     self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addFriendAction:)];
 50     self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAction:)];
 51     
 52 }
 53 
 54 
 55 #pragma mark - 添加和注销按钮的实现
 56 // 添加按钮的方法实现
 57 - (void)addFriendAction:(UIBarButtonItem *)sender {
 58     
 59     [[XMPPManager shareManager] addFriend];
 60 }
 61 
 62 // 注销按钮的方法实现
 63 - (void)cancelAction:(UIBarButtonItem *)sender {
 64     
 65     [self.navigationController popViewControllerAnimated:YES];
 66 }
 67 
 68 
 69 #pragma mark - 设置cell
 70 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 71 
 72     return self.allRosterArray.count;
 73 }
 74 
 75 
 76 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 77     
 78     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
 79     // 根据情况分析,合理添加判断
 80     if (self.allRosterArray.count > 0) {
 81         //获取用户
 82         XMPPJID *jid = self.allRosterArray[indexPath.row];
 83         cell.textLabel.text = jid.user;
 84     }
 85     
 86     return cell;
 87 }
 88 
 89 
 90 #pragma mark - 编辑页面(删除)
 91 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
 92     
 93     return YES;
 94 }
 95 
 96 
 97 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
 98     if (editingStyle == UITableViewCellEditingStyleDelete) {
 99         // 处理要删除的数据
100         // 要删除用户的jid
101         XMPPJID *jid = self.allRosterArray[indexPath.row];
102         [[XMPPManager shareManager] removeFriendWithName:jid.user];
103         [self.allRosterArray removeObjectAtIndex:indexPath.row];
104         [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
105     }
106 }
107 
108 
109 #pragma mark - XMPPRosterDelegate代理方法
110 // 开始获取好友
111 - (void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender {
112     
113     NSLog(@"开始获取好友");
114 }
115 
116 // 结束获取好友
117 - (void)xmppRosterDidEndPopulating:(XMPPRoster *)sender {
118     
119     // 当前页面适用于显示好友列表的,所以在结束好友获取的代理方法中要进行刷新页面,然后将数据显示
120     // 刷新页面
121     [self.tableView reloadData];
122 }
123 
124 
125 // 接收好友的信息
126 // 这个代理方法会被执行多次,每添加完好友,相应的好友信息都需要反馈
127 - (void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item {
128     
129     /*
130      both 互为好友
131      none 互不为好友
132      to 我已添加对方为好友,但是对方还没有接收
133      from 对方已添加自己为好友,但是自己还没有接收
134      remove 曾经删除的好友
135      */
136     // 描述自己和对方之间的关系
137     NSString *description = [[item attributeForName:@"subscription"] stringValue];
138     NSLog(@"description = %@", description);
139     
140     if ([description isEqualToString:@"none"] || [description isEqualToString:@"to"] || [description isEqualToString:@"from"] || [description isEqualToString:@"both"]) {
141         
142         // 添加好友
143         // 获取要添加好友的JID
144         NSString *friendJID = [[item attributeForName:@"jid"] stringValue];
145         XMPPJID *jid = [XMPPJID jidWithString:friendJID];
146         
147         // 如果数组中含有这个用户就不用进行接下来的操作
148         if ([self.allRosterArray containsObject:jid]) {
149             return;
150         }
151         
152         // 添加好友到数组中
153         [self.allRosterArray addObject:jid];
154         
155         // 在tableView中添加这条数据
156         NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.allRosterArray.count - 1 inSection:0];
157         [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];
158     }
159 }
160 
161 
162 // 对方好友是同意还是拒绝
163 - (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence {
164     
165     self.fromJID = presence.from;
166     // 需要相关的提醒框去确定是否接受
167     
168     UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"好友请求" message:@"是否接受好友请求" preferredStyle:UIAlertControllerStyleAlert];
169     
170     __weak typeof(self)weakSelf = self;
171     UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"接受" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
172         // 在花名册中去接受好友
173         [[XMPPManager shareManager].xmppRoster acceptPresenceSubscriptionRequestFrom:weakSelf.fromJID andAddToRoster:YES];
174     }];
175     UIAlertAction *action2 = [UIAlertAction actionWithTitle:@"拒绝" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
176         // 在花名册中拒绝好友
177         [[XMPPManager shareManager].xmppRoster rejectPresenceSubscriptionRequestFrom:weakSelf.fromJID];
178     }];
179     
180     [alertController addAction:action1];
181     [alertController addAction:action2];
182     
183     [self presentViewController:alertController animated:YES completion:^{
184         
185     }];
186 }
187 
188 
189 #pragma mark - XMPPStreamDelegate代理方法
190 // 获取好友是否在线
191 - (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {
192     
193     NSLog(@"status = %@", presence.status);
194     
195     NSString *type = presence.type;
196     NSString *presenceOfUser = presence.to.user;
197     
198     // 判断当前用户是否为你的好友
199     if ([presenceOfUser isEqualToString:[sender myJID].user]) {
200         if ([type isEqualToString:@"avaialble"]) {
201             NSLog(@"该用户处于上线状态");
202         } else if([type isEqualToString:@"uianaialble"]) {
203             NSLog(@"该用户处于下线状态");
204         }
205     }
206     
207 }
208 
209 
210 #pragma mark - 点击cell进入聊天界面
211 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
212     
213     ChatTableViewController *chatVC = [[ChatTableViewController alloc] init];
214     XMPPJID *jid = self.allRosterArray[indexPath.row];
215     
216     chatVC.chatToJID = jid;
217     [self.navigationController pushViewController:chatVC animated:YES];
218 }
219 
220 @end

ChatTableViewController.h

 1 #import <UIKit/UIKit.h>
 2 #import "XMPPManager.h"
 3 
 4 @interface ChatTableViewController : UITableViewController
 5 
 6 /**
 7  *  当前和谁进行聊天
 8  */
 9 @property (nonatomic, strong) XMPPJID *chatToJID;
10 
11 @end

ChatTableViewController.m

  1 #import "ChatTableViewController.h"
  2 #import "ChatCell.h"
  3 
  4 @interface ChatTableViewController () <XMPPStreamDelegate>
  5 
  6 /**
  7  *  存储消息
  8  */
  9 @property (nonatomic, strong) NSMutableArray *allMessageArray;
 10 
 11 @end
 12 
 13 @implementation ChatTableViewController
 14 
 15 // 懒加载
 16 - (NSMutableArray *)allMessageArray {
 17     
 18     if (!_allMessageArray) {
 19         _allMessageArray = [NSMutableArray array];
 20     }
 21     return _allMessageArray;
 22 }
 23 
 24 
 25 - (void)viewDidLoad {
 26     [super viewDidLoad];
 27     
 28     // 隐藏tableView每一行的线
 29     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
 30     
 31     
 32     // 设置代理
 33     [[XMPPManager shareManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
 34     
 35     
 36     // 获取显示消息的方法
 37     [self showMessage];
 38     
 39     
 40     // 注册cell
 41     [self.tableView registerClass:[ChatCell class] forCellReuseIdentifier:@"cell"];
 42     
 43     
 44     // 写两个按钮,一个用于发送,一个用于取消
 45     self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"发送" style:UIBarButtonItemStylePlain target:self action:@selector(sureAction)];
 46     self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(cancelAction)];
 47 }
 48 
 49 
 50 #pragma mark - 按钮的发送方法和取消方法
 51 // 发送方法
 52 - (void)sureAction {
 53     
 54     // 设置message的body
 55     XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatToJID];
 56     
 57     [message addBody:@"我爱你"];
 58     
 59     // 通过通道进行消息发送
 60     [[XMPPManager shareManager].xmppStream sendElement:message];
 61 }
 62 
 63 // 取消方法
 64 - (void)cancelAction {
 65     
 66     [self.navigationController popViewControllerAnimated:YES];
 67 }
 68 
 69 
 70 #pragma mark - 显示消息
 71 - (void)showMessage {
 72     
 73     // 获取管理上下文
 74     NSManagedObjectContext *context = [XMPPManager shareManager].context;
 75     
 76     // 初始化请求对象
 77     NSFetchRequest *request = [[NSFetchRequest alloc] init];
 78     
 79     // 获取实体
 80     NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:context];
 81     
 82     // 设置查询请求的实体
 83     [request setEntity:entity];
 84     
 85     // 设置谓词查询(当前用户的JID,对方用户的JID)
 86     NSPredicate *predicate = [NSPredicate predicateWithFormat:@"streamBareJidStr == %@ AND bareJidStr == %@",[XMPPManager shareManager].xmppStream.myJID.bare,self.chatToJID.bare];
 87     
 88     [request setPredicate:predicate];
 89     
 90     // 按照时间顺序进行排列
 91     NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:YES];
 92     
 93     // 设置排序
 94     [request setSortDescriptors:@[sort]];
 95     
 96     // 执行相关的操作
 97     NSArray *resultArray = [context executeFetchRequest:request error:nil];
 98     
 99     // 先清空消息数组
100     [self.allMessageArray removeAllObjects];
101     
102     // 在进行添加context执行的结果数组
103     [self.allMessageArray addObjectsFromArray:resultArray];
104     
105     // 刷新UI
106     [self.tableView reloadData];
107     
108     // 当前聊天记录跳到最后一行
109     if (self.allMessageArray.count > 0) {
110         NSIndexPath * indexPath = [NSIndexPath indexPathForRow:self.allMessageArray.count-1 inSection:0];
111         // 跳到最后一行
112         [self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionBottom];
113     }
114 }
115 
116 
117 #pragma mark - 设置cell
118 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
119     
120     return 1;
121 }
122 
123 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
124     
125     return self.allMessageArray.count;
126 }
127 
128 
129 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
130     
131     ChatCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
132     
133     // 千万要记住数组里存储的message对象是XMPPMessageArchiving_Message_CoreDataObject类型的
134     XMPPMessageArchiving_Message_CoreDataObject *message = [self.allMessageArray objectAtIndex:indexPath.row];
135     
136     // 设置cell的相关数据
137     cell.isOut = message.isOutgoing;
138     cell.message = message.body;
139     
140     
141     return cell;
142 }
143 
144 
145 // 设置cell高度
146 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
147     
148     return 70;
149 }
150 
151 
152 #pragma mark - XMPPStreamDelegate的相关代理方法
153 // 发送消息成功
154 - (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message {
155     
156     // 重新显示相关信息
157     [self showMessage];
158 }
159 
160 // 接受消息成功
161 - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
162     
163     // 重新显示相关信息
164     [self showMessage];
165 }
166 
167 
168 // 发送消息失败
169 - (void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error {
170     
171     NSLog(@"发送消息失败");
172 }
173 
174 @end

ChatCell.h

 1 #import <UIKit/UIKit.h>
 2 
 3 @interface ChatCell : UITableViewCell
 4 
 5 /**
 6  *  判断是对方发送过来的消息,还是自己发出的消息
 7  */
 8 @property (nonatomic, assign) BOOL isOut;
 9 
10 /**
11  *  消息内容
12  */
13 @property (nonatomic, strong) NSString *message;
14 
15 @end

ChatCell.m

 1 #import "ChatCell.h"
 2 
 3 @interface ChatCell ()
 4 
 5 @property(nonatomic,strong)UIImageView * headerImageView;
 6 @property(nonatomic,strong)UIImageView * backgroundImageView;
 7 
 8 /**
 9  *  显示每一条聊天内容
10  */
11 @property(nonatomic,strong)UILabel * contentLabel;
12 
13 @end
14 
15 
16 @implementation ChatCell
17 
18 //使用懒加载创建并初始化所有UI控件
19 - (UILabel *)contentLabel{
20     if (_contentLabel == nil) {
21         _contentLabel = [[UILabel alloc] init];
22     }
23     return _contentLabel;
24 }
25 - (UIImageView *)backgroundImageView
26 {
27     if (_backgroundImageView == nil) {
28         _backgroundImageView = [[UIImageView alloc] init];
29     }
30     return _backgroundImageView;
31 }
32 - (UIImageView *)headerImageView
33 {
34     if (_headerImageView == nil) {
35         _headerImageView = [[UIImageView alloc] init];
36     }
37     return _headerImageView;
38 }
39 
40 
41 - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
42     self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
43     if (self) {
44         //设置cell不能选中
45         self.selectionStyle = UITableViewCellSelectionStyleNone;
46         
47         [self.contentView addSubview:self.backgroundImageView];
48         [self.contentView addSubview:self.headerImageView];
49         [self.backgroundImageView addSubview:self.contentLabel];
50     }
51     return self;
52 }
53 
54 
55 //重写isOut的setter方法,来设定cell上的不同布局
56 - (void)setIsOut:(BOOL)isOut
57 {
58     _isOut = isOut;
59     CGRect rect = self.frame;
60     if (_isOut) {
61         self.headerImageView.frame = CGRectMake(rect.size.width-50, 10, 50, 50);
62         self.headerImageView.image = [UIImage imageNamed:@"xiaoming"];
63     }else{
64         self.headerImageView.frame = CGRectMake(0, 10, 50, 50);
65         self.headerImageView.image = [UIImage imageNamed:@"angel"];
66     }
67 }
68 
69 
70 //重写message方法,在cell上显示聊天记录
71 - (void)setMessage:(NSString *)message
72 {
73     if (_message != message) {
74         _message = message;
75         self.contentLabel.text = _message;
76         //        self.contentLabel.numberOfLines = 0;
77         [self.contentLabel sizeToFit];
78         
79         CGRect rect = self.frame;
80         if (self.isOut) {//发出去的
81             self.backgroundImageView.image = [[UIImage imageNamed:@"chat_to"] stretchableImageWithLeftCapWidth:45 topCapHeight:40];
82             self.backgroundImageView.frame = CGRectMake(rect.size.width - self.contentLabel.frame.size.width - 50-20, 10, self.contentLabel.frame.size.width+20, rect.size.height-20);
83         }else{//接收的
84             self.backgroundImageView.image = [[UIImage imageNamed:@"chat_from"] stretchableImageWithLeftCapWidth:45 topCapHeight:40];
85             self.backgroundImageView.frame = CGRectMake(50, 10,self.contentLabel.frame.size.width+40, rect.size.height-20);
86         }
87         //因为contentLabel已经自适应文字大小,故不用设置宽高,但需要设置位置
88         self.contentLabel.center = CGPointMake(self.backgroundImageView.frame.size.width/2.0, self.backgroundImageView.frame.size.height/2.0);
89         
90     }
91 }
92 
93 @end

 

即时通信

标签:

原文地址:http://www.cnblogs.com/zhizunbao/p/5517663.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!