即時聊天 / XMPP

 

MQTT是第二個即時聊天協議(瞭解)

5.即時通信 即時通信網上有第三方的解決方案,好比環信,融雲等。咱們是本身搭的xmpp服務器,服務器使用的tigase,以前寫過相關的博客,本身去年也作了對應的webim。前段時間看了環信webim的sdk,使用的也是strophe的js類庫,相關實現跟咱們的差很少,可是本身搭建xmpp會遇到了很多問題,好比丟消息!因此若是想比較快速的實現im,推薦使用第三方的解決方案。 移動端的丟消息大概是這個樣子。A和B通信,A發了一條消息給服務器,服務器發給B,可是B網絡很差掉線了,而服務器殊不知道B退出了(B正常退出會給服務器發下線通知),因此消息丟失了。XMPP中有xep-0184協議(消息回執),A給B發消息,消息體中帶一行代碼(要求消息回執),當B收到消息後發送一條回執,證實我收到了。後來XMPP又有了xep-0198協議(流管理),斷線後快速重鏈,同時判斷必定時間收不到消息,就把消息寫離線消息,減小丟消息狀況。可是可能網絡狀況複雜,加上各類不肯定因素,還會出現丟消息的問題。目前比較靠譜的方法就是存全部的聊天記錄,由手機端根據時間點去數據庫拉消息,只要別人發出的消息就不會丟。 此次即時通信模塊進行了相關改動,也是參考了以前開發人員的一些建議。好比用戶返回home的時候,斷開xmpp鏈接(iOS進入後臺後,只有5秒的處理時間,特殊方法可延長到10分鐘,若是內存不夠,應用隨時就被殺死了)。因此返回home時就斷開,進入應用再鏈接。同時應用使用狀態下,有心跳檢測,判斷是否保持鏈接。 考慮到iOS的特殊性,咱們採起了xmpp和遠程推送都走的方法,推送的自定義消息體和xmpp消息體同樣,消息的處理方法同樣。用戶聊天發送xmpp消息的同時也調用咱們的消息推送接口調用友盟push(push能夠設置過時時間,避免特殊狀況,推送延時,聊天結束了才收到推送)。一是解決iOS應用未啓動時的推送接收,二是解決xmpp丟消息的問題。 關於推送,AppDelage中有兩個方法,一個是使用中收到推送,不會提示,會直接處理推送信息。另外是程序非使用狀態,收到推送,會進行提示,能夠點擊推送消息進入應用,獲取這一條推送消息的推送消息(須要注意,點擊推送啓動應用拿到信息時view尚未加載,消息不能馬上處理)。 android端由於是真後臺,能夠後臺一直保持運行,不管收到xmpp消息仍是友盟推送,均可以本身進行處理,而後本身彈一個本地推送(也有弊端,若是android程序殺死,就沒法接受消息和推送)。iOS端由於後臺不可控,因此推送使用遠程推送,進入應用鏈接xmpp再收所有離線消息(不保證友盟推送可否保證及時)。固然大部分都仍是正常狀況,網絡狀況比較好的條件下,就實時收到了xmpp的消息或者遠程推送。咱們又不是QQ和微信,只要保證用戶看到的數據能保持一致性就好了(因此QQ和微信就是diao啊)。 根據測試反饋的狀況,iOS這個應用的丟消息狀況比上個應用有必定改善。具體狀況再進一步觀察把。 咱們的即時通信也包括語音和圖片,採用的是http的解決方案(xmpp也支持二進制的傳輸,可是估計沒人那樣用)。具體流程就是先把附件傳到附件服務器拿到附件服務器的地址,再封裝到消息體。接收方收到消息解析的時候,再從附件服務器拿到對應的資源,加載到本地。 同時屏蔽,取消屏蔽等一些實時操做也都會發xmpp,第一時間雙方更新狀態。html

 

深刻認識Tigase XMPP Server(上)http://blog.csdn.net/chszs/article/details/41280957

 

原文地址:http://blog.csdn.net/kangkangz4/article/category/1089711java

 http://blog.sina.com.cn/s/blog_5fb39f910101akyo.htmlandroid

[iPhone高級] 基於XMPP的IOS聊天客戶端程序(XMPP服務器架構)ios

 

最近看了關於XMPP的框架,以文本聊天爲例,須要發送的消息爲:git

 XMPP的擴展協議Jingle使得其支持語音和視頻。
  1. <</SPAN>message type="chat" from="kang@server.com" to="test@server.com">
  2. <</SPAN>body>helloWord</</SPAN>body>
  3. </</SPAN>message>
helloWord

基中from是從哪一個用戶發送的消息,to是發給誰的消息,XMPP的用戶都是以郵箱形式。body就是咱們發送的消息文本。github

好了,說到這裏,咱們就來開發一個基於XMPP的IOS聊天客戶端程序,首先咱們須要XMPP服務器,這裏,我就拿本機作服務器,首先從xmpp Server下載ejabberd這個服務器,ejabberd支持Linux / Mac OS X / Solaris / Windows,因此任何操做系統均可以作咱們的聊天服務器。好了,下載完後,一步一步安裝就能夠了,這裏咱們要注意一下web

這裏咱們的服務器就是dpc1338a(通常就是機器名,默認就能夠了,不須要改),每臺機器的用戶名都不同,這裏的服務器域名就是機器名,這個咱們須要記住哦數據庫

接着一步一步,還要設置管理員密碼,密碼固然也須要記住了,否則咱們沒辦法登陸管理員頁面去。windows

好了,安裝完後啓動,顯示以下:服務器

咱們點擊admin interface,會要求咱們輸入用戶名和密碼:


這裏用戶名是前面咱們安裝的時候有一個管理員名,將管理員名跟咱們的服務器組合就能夠了,我這裏是admin@dpc1338a,每一臺機器都不同,不要照抄哦,這樣你是登陸不了的,密碼就是安裝的時候設置的密碼

登陸成功後就會顯示以下頁面:


這裏咱們須要解釋的就是<<SPAN style="COLOR: rgb(153,0,0)">訪問控制列表>,這裏是設置管理員的,咱們能夠在這裏建立其餘管理員,這個不是咱們的重點,咱們的重點是<<SPAN style="COLOR: rgb(102,0,0)">虛擬主機>

點開<<SPAN style="COLOR: rgb(102,0,0)">虛擬主機>,下面有一個<<SPAN style="COLOR: rgb(102,0,0)">dpc1338a>,也點開


這裏有一個<<SPAN style="COLOR: rgb(102,0,0)">用戶>,咱們須要建立幾個用戶來進行數據交互。

我建立了kang@dpc1338a,test@dpc1338a, abc@dpc1338a這幾個用戶,過一會咱們就用這幾個用戶進行聊天


好了,服務器裝好了之後,咱們就須要下載個客戶端來進行聊天,這裏有一些客戶端工具

http://xmpp.org/xmpp-software/clients/,這裏咱們主要推薦MAC用Adium,Windows用Citron,下一章咱們要介紹IOS的xmpp framework。

 

[iPhone高級] 基於XMPP的IOS聊天客戶端程序(IOS端一)

分類:  iPhone高級2012-07-13 07:29 7966人閱讀評論(19)收藏舉報

介紹完了服務器,這篇咱們就要介紹重點了,寫咱們本身的IOS客戶端程序

先看一下咱們完成的效果圖

首先下載xmppframework這個框架,下載


點ZIP下載

接下來,用Xcode新建一個工程

將如下這些文件拖入新建工程中

加入framework

並設置

 

到這裏咱們就所有設好了,跑一下試試,看有沒有錯呢

若是沒有錯的話,咱們的xmppframework就加入成功了。

 

咱們設置咱們的頁面以下圖:

咱們的KKViewController.h

[java]  view plain copy print ?
  1. #import
  2. @interface KKViewController : UIViewController
  3. @property (strong, nonatomic) IBOutlet UITableView *tView;
  4. - (IBAction)Account:(id)sender;
  5. @end


 

KKViewController.m

[java]  view plain copy print ?
  1. #import "KKViewController.h"
  2. @interface KKViewController (){
  3. //在線用戶
  4. NSMutableArray *onlineUsers;
  5. }
  6. @end
  7. @implementation KKViewController
  8. @synthesize tView;
  9. - (void)viewDidLoad
  10. {
  11. [super viewDidLoad];
  12. self.tView.delegate = self;
  13. self.tView.dataSource = self;
  14. onlineUsers = [NSMutableArray array];
  15. // Do any additional setup after loading the view, typically from a nib.
  16. }
  17. - (void)viewDidUnload
  18. {
  19. [self setTView:nil];
  20. [super viewDidUnload];
  21. // Release any retained subviews of the main view.
  22. }
  23. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
  24. {
  25. return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
  26. }
  27. - (IBAction)Account:(id)sender {
  28. }
  29. #pragma mark UITableViewDataSource
  30. -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
  31. return [onlineUsers count];
  32. }
  33. -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
  34. static NSString *identifier = @"userCell";
  35. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
  36. if (cell == nil) {
  37. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
  38. }
  39. return cell;
  40. }
  41. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
  42. return 1;
  43. }
  44. #pragma mark UITableViewDelegate
  45. -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
  46. }
  47. @end

這裏的代碼相信你們學過UITableView的話應該很熟悉了,若是不知道的話,就查一下UITableView的簡單應用學習一下吧

接下來是登陸的頁面

KKLoginController.m

[java]  view plain copy print ?
  1. - (IBAction)LoginButton:(id)sender {
  2. if ([self validateWithUser:userTextField.text andPass:passTextField.text andServer:serverTextField.text]) {
  3. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  4. [defaults setObject:self.userTextField.text forKey:USERID];
  5. [defaults setObject:self.passTextField.text forKey:PASS];
  6. [defaults setObject:self.serverTextField.text forKey:SERVER];
  7. //保存
  8. [defaults synchronize];
  9. [self dismissModalViewControllerAnimated:YES];
  10. }else {
  11. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"請輸入用戶名,密碼和服務器"delegate:nil cancelButtonTitle:@"肯定" otherButtonTitles:nil, nil];
  12. [alert show];
  13. }
  14. }
  15. - (IBAction)closeButton:(id)sender {
  16. [self dismissModalViewControllerAnimated:YES];
  17. }
  18. -(BOOL)validateWithUser:(NSString *)userText andPass:(NSString *)passText andServer:(NSString *)serverText{
  19. if (userText.length > 0 && passText.length > 0 && serverText.length > 0) {
  20. return YES;
  21. }
  22. return NO;
  23. }

下面是聊天的頁面


這裏着重的仍是UITableView

KKChatController.m

[java]  view plain copy print ?
  1. -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
  2. return 1;
  3. }
  4. -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
  5. return [messages count];
  6. }
  7. -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
  8. static NSString *identifier = @"msgCell";
  9. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
  10. if (cell == nil) {
  11. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
  12. }
  13. NSMutableDictionary *dict = [messages objectAtIndex:indexPath.row];
  14. cell.textLabel.text = [dict objectForKey:@"msg"];
  15. cell.detailTextLabel.text = [dict objectForKey:@"sender"];
  16. cell.accessoryType = UITableViewCellAccessoryNone;
  17. return cell;
  18. }

這些都比較簡單,相信你們應該都能看得懂

把這些都設置好之後,咱們就要着重介紹XMPP了,怕太長了,接下一章吧。

 

[iPhone高級] 基於XMPP的IOS聊天客戶端程序(IOS端二)

分類:  iPhone高級2012-07-13 08:25 6625人閱讀評論(27)收藏舉報

接上一章的,這一章咱們着重介紹XMPP

爲了方便程序調用,咱們把XMPP的一些主要方法寫在AppDelegate中

在AppDelegate.m下這幾個方法爲:

[java]  view plain copy print ?
  1. -(void)setupStream{
  2. //初始化XMPPStream
  3. xmppStream = [[XMPPStream alloc] init];
  4. [xmppStream addDelegate:self delegateQueue:dispatch_get_current_queue()];
  5. }
  6. -(void)goOnline{
  7. //發送在線狀態
  8. XMPPPresence *presence = [XMPPPresence presence];
  9. [[self xmppStream] sendElement:presence];
  10. }
  11. -(void)goOffline{
  12. //發送下線狀態
  13. XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
  14. [[self xmppStream] sendElement:presence];
  15. }
  16. -(BOOL)connect{
  17. [self setupStream];
  18. //從本地取得用戶名,密碼和服務器地址
  19. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  20. NSString *userId = [defaults stringForKey:USERID];
  21. NSString *pass = [defaults stringForKey:PASS];
  22. NSString *server = [defaults stringForKey:SERVER];
  23. if (![xmppStream isDisconnected]) {
  24. return YES;
  25. }
  26. if (userId == nil || pass == nil) {
  27. return NO;
  28. }
  29. //設置用戶
  30. [xmppStream setMyJID:[XMPPJID jidWithString:userId]];
  31. //設置服務器
  32. [xmppStream setHostName:server];
  33. //密碼
  34. password = pass;
  35. //鏈接服務器
  36. NSError *error = nil;
  37. if (![xmppStream connect:&error]) {
  38. NSLog(@"cant connect %@", server);
  39. return NO;
  40. }
  41. return YES;
  42. }
  43. -(void)disconnect{
  44. [self goOffline];
  45. [xmppStream disconnect];
  46. }
這幾個是基礎方法,接下來就是XMPPStreamDelegate中的方法,也是接受好友狀態,接受消息的重要方法
[java]  view plain copy print ?
  1. //鏈接服務器
  2. - (void)xmppStreamDidConnect:(XMPPStream *)sender{
  3. isOpen = YES;
  4. NSError *error = nil;
  5. //驗證密碼
  6. [[self xmppStream] authenticateWithPassword:password error:&error];
  7. }
  8. //驗證經過
  9. - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
  10. [self goOnline];
  11. }
  12. //收到消息
  13. - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message{
  14. // NSLog(@"message = %@", message);
  15. NSString *msg = [[message elementForName:@"body"] stringValue];
  16. NSString *from = [[message attributeForName:@"from"] stringValue];
  17. NSMutableDictionary *dict = [NSMutableDictionary dictionary];
  18. [dict setObject:msg forKey:@"msg"];
  19. [dict setObject:from forKey:@"sender"];
  20. //消息委託(這個後面講)
  21. [messageDelegate newMessageReceived:dict];
  22. }
  23. //收到好友狀態
  24. - (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence{
  25. // NSLog(@"presence = %@", presence);
  26. //取得好友狀態
  27. NSString *presenceType = [presence type]; //online/offline
  28. //當前用戶
  29. NSString *userId = [[sender myJID] user];
  30. //在線用戶
  31. NSString *presenceFromUser = [[presence from] user];
  32. if (![presenceFromUser isEqualToString:userId]) {
  33. //在線狀態
  34. if ([presenceType isEqualToString:@"available"]) {
  35. //用戶列表委託(後面講)
  36. [chatDelegate newBuddyOnline:[NSString stringWithFormat:@"%@@%@", presenceFromUser, @"nqc1338a"]];
  37. }else if ([presenceType isEqualToString:@"unavailable"]) {
  38. //用戶列表委託(後面講)
  39. [chatDelegate buddyWentOffline:[NSString stringWithFormat:@"%@@%@", presenceFromUser, @"nqc1338a"]];
  40. }
  41. }
  42. }
這裏面有兩個委託方法,一個是用戶列表委託,還有一個就是消息委託,用戶列表委託主要就是取得在線用戶,更新用戶TableView,消息委託就是取得好友發送的消息,並更新消息TableView,固然這兩個TableView是在不一樣的Controller中的

定義完兩個委託,咱們就要在不一樣的Controller中實現這兩個委託了

在好友Controller中實現並寫入以下方法

[java]  view plain copy print ?
  1. //取得當前程序的委託
  2. -(KKAppDelegate *)appDelegate{
  3. return (KKAppDelegate *)[[UIApplication sharedApplication] delegate];
  4. }
  5. //取得當前的XMPPStream
  6. -(XMPPStream *)xmppStream{
  7. return [[self appDelegate] xmppStream];
  8. }
  9. //在線好友
  10. -(void)newBuddyOnline:(NSString *)buddyName{
  11. if (![onlineUsers containsObject:buddyName]) {
  12. [onlineUsers addObject:buddyName];
  13. [self.tView reloadData];
  14. }
  15. }
  16. //好友下線
  17. -(void)buddyWentOffline:(NSString *)buddyName{
  18. [onlineUsers removeObject:buddyName];
  19. [self.tView reloadData];
  20. }
在viewDidLoad中加入
[java]  view plain copy print ?
  1. //設定在線用戶委託
  2. KKAppDelegate *del = [self appDelegate];
  3. del.chatDelegate = self;
這兩行代碼,讓好友列表的委託實現方法在本程序中

在viewWillAppear中加入

[java]  view plain copy print ?
  1. [super viewWillAppear:animated];
  2. NSString *login = [[NSUserDefaults standardUserDefaults] objectForKey:@"userId"];
  3. if (login) {
  4. if ([[self appDelegate] connect]) {
  5. NSLog(@"show buddy list");
  6. }
  7. }else {
  8. //設定用戶
  9. [self Account:self];
  10. }
判斷本地保存的數據中是否有userId,沒有的話就跳轉到登陸頁面

這裏最重要的就是connect了,這一句話就是登陸了,成功的話,頁面就會顯示好友列表了。

[java]  view plain copy print ?
  1. #pragma mark UITableViewDelegate
  2. -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
  3. //start a Chat
  4. chatUserName = (NSString *)[onlineUsers objectAtIndex:indexPath.row];
  5. [self performSegueWithIdentifier:@"chat" sender:self];
  6. }
  7. -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
  8. if ([segue.identifier isEqualToString:@"chat"]) {
  9. KKChatController *chatController = segue.destinationViewController;
  10. chatController.chatWithUser = chatUserName;
  11. }
  12. }
當顯示出好友列表,咱們選擇一個好友進行聊天

將當前好友名稱發送給聊天頁面

下面是聊天Controller了

在KKChatController.h中加入

[java]  view plain copy print ?
  1. NSMutableArray *messages;
這是咱們要顯示的消息,每一條消息爲一條字典

接下來就是每一條消息的顯示了

[java]  view plain copy print ?
  1. -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
  2. static NSString *identifier = @"msgCell";
  3. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
  4. if (cell == nil) {
  5. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
  6. }
  7. NSMutableDictionary *dict = [messages objectAtIndex:indexPath.row];
  8. cell.textLabel.text = [dict objectForKey:@"msg"];
  9. cell.detailTextLabel.text = [dict objectForKey:@"sender"];
  10. cell.accessoryType = UITableViewCellAccessoryNone;
  11. return cell;
  12. }
跟上面好友Controller同樣,這裏咱們也須要XMPPStream
[java]  view plain copy print ?
  1. -(KKAppDelegate *)appDelegate{
  2. return (KKAppDelegate *)[[UIApplication sharedApplication] delegate];
  3. }
  4. -(XMPPStream *)xmppStream{
  5. return [[self appDelegate] xmppStream];
  6. }
在ViewDidLoad中加入
[java]  view plain copy print ?
  1. KKAppDelegate *del = [self appDelegate];
  2. del.messageDelegate = self;
設定消息委託由本身來接收和處理
[java]  view plain copy print ?
  1. #pragma mark KKMessageDelegate
  2. -(void)newMessageReceived:(NSDictionary *)messageCotent{
  3. [messages addObject:messageCotent];
  4. [self.tView reloadData];
  5. }
接下來最重要的就是發送消息了
[java]  view plain copy print ?
  1. - (IBAction)sendButton:(id)sender {
  2. //本地輸入框中的信息
  3. NSString *message = self.messageTextField.text;
  4. if (message.length > 0) {
  5. //XMPPFramework主要是經過KissXML來生成XML文件
  6. //生成文檔
  7. NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
  8. [body setStringValue:message];
  9. //生成XML消息文檔
  10. NSXMLElement *mes = [NSXMLElement elementWithName:@"message"];
  11. //消息類型
  12. [mes addAttributeWithName:@"type" stringValue:@"chat"];
  13. //發送給誰
  14. [mes addAttributeWithName:@"to" stringValue:chatWithUser];
  15. //由誰發送
  16. [mes addAttributeWithName:@"from" stringValue:[[NSUserDefaults standardUserDefaults] stringForKey:USERID]];
  17. //組合
  18. [mes addChild:body];
  19. //發送消息
  20. [[self xmppStream] sendElement:mes];
  21. self.messageTextField.text = @"";
  22. [self.messageTextField resignFirstResponder];
  23. NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
  24. [dictionary setObject:message forKey:@"msg"];
  25. [dictionary setObject:@"you" forKey:@"sender"];
  26. [messages addObject:dictionary];
  27. //從新刷新tableView
  28. [self.tView reloadData];
  29. }
  30. }
文檔 NSXMLElement *body = [NSXMLElement elementWithName:@"body"]; [body setStringValue:message]; //生成XML消息文檔 NSXMLElement *mes = [NSXMLElement elementWithName:@"message"]; //消息類型 [mes addAttributeWithName:@"type" stringValue:@"chat"]; //發送給誰 [mes addAttributeWithName:@"to" stringValue:chatWithUser]; //由誰發送 [mes addAttributeWithName:@"from" stringValue:[[NSUserDefaults standardUserDefaults] stringForKey:USERID]]; //組合 [mes addChild:body]; //發送消息 [[self xmppStream] sendElement:mes]; self.messageTextField.text = @""; [self.messageTextField resignFirstResponder]; NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; [dictionary setObject:message forKey:@"msg"]; [dictionary setObject:@"you" forKey:@"sender"]; [messages addObject:dictionary]; //從新刷新tableView [self.tView reloadData]; } }上面都加了註釋,你們應該能明白,接下來還有一個章節,咱們會對發送的消息在界面進行美化,跟蘋果自帶的消息同樣。謝謝你們有耐心看完,我這我的比較不喜歡打字,因此有的地方註釋比較少,但願你們別介意,還有但願你們可以多多支持, 之後會接着介紹XMPP文件傳輸之類的內容。
 
 
[iPhone高級] 基於XMPP的IOS聊天客戶端程序(IOS端三)
分類:  iPhone高級2012-07-16 04:17 4063人閱讀評論(14)收藏舉報

前兩篇介紹瞭如何經過XMPP來發送消息和接收消息,這一篇咱們主要介紹如何來美化咱們的聊天程序,看一下最終效果呢,固然源程序也會在最後放出

好了,咱們來看一下咱們寫的程序

這裏咱們自定義了TableViewCell

一行是顯示發佈日期,一行是顯示發送的消息,還有一個是背景

[java]  view plain copy print ?
  1. -(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
  2. self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
  3. if (self) {
  4. //日期標籤
  5. senderAndTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(10530020)];
  6. //居中顯示
  7. senderAndTimeLabel.textAlignment = UITextAlignmentCenter;
  8. senderAndTimeLabel.font = [UIFont systemFontOfSize:11.0];
  9. //文字顏色
  10. senderAndTimeLabel.textColor = [UIColor lightGrayColor];
  11. [self.contentView addSubview:senderAndTimeLabel];
  12. //背景圖
  13. bgImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
  14. [self.contentView addSubview:bgImageView];
  15. //聊天信息
  16. messageContentView = [[UITextView alloc] init];
  17. messageContentView.backgroundColor = [UIColor clearColor];
  18. //不可編輯
  19. messageContentView.editable = NO;
  20. messageContentView.scrollEnabled = NO;
  21. [messageContentView sizeToFit];
  22. [self.contentView addSubview:messageContentView];
  23. }
  24. return self;
  25. }
定義好,在UITableViewCell中將Cell改爲咱們本身定義的Cell
[java]  view plain copy print ?
  1. -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
  2. static NSString *identifier = @"msgCell";
  3. KKMessageCell *cell =(KKMessageCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
  4. if (cell == nil) {
  5. cell = [[KKMessageCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
  6. }
  7. NSMutableDictionary *dict = [messages objectAtIndex:indexPath.row];
  8. //發送者
  9. NSString *sender = [dict objectForKey:@"sender"];
  10. //消息
  11. NSString *message = [dict objectForKey:@"msg"];
  12. //時間
  13. NSString *time = [dict objectForKey:@"time"];
  14. CGSize textSize = {260.0 ,10000.0};
  15. CGSize size = [message sizeWithFont:[UIFont boldSystemFontOfSize:13] constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];
  16. size.width +=(padding/2);
  17. cell.messageContentView.text = message;
  18. cell.accessoryType = UITableViewCellAccessoryNone;
  19. cell.userInteractionEnabled = NO;
  20. UIImage *bgImage = nil;
  21. //發送消息
  22. if ([sender isEqualToString:@"you"]) {
  23. //背景圖
  24. bgImage = [[UIImage imageNamed:@"BlueBubble2.png"] stretchableImageWithLeftCapWidth:20topCapHeight:15];
  25. [cell.messageContentView setFrame:CGRectMake(padding, padding*2, size.width, size.height)];
  26. [cell.bgImageView setFrame:CGRectMake(cell.messageContentView.frame.origin.x - padding/2, cell.messageContentView.frame.origin.y - padding/2, size.width + padding, size.height + padding)];
  27. }else {
  28. bgImage = [[UIImage imageNamed:@"GreenBubble2.png"] stretchableImageWithLeftCapWidth:14topCapHeight:15];
  29. [cell.messageContentView setFrame:CGRectMake(320-size.width - padding, padding*2, size.width, size.height)];
  30. [cell.bgImageView setFrame:CGRectMake(cell.messageContentView.frame.origin.x - padding/2, cell.messageContentView.frame.origin.y - padding/2, size.width + padding, size.height + padding)];
  31. }
  32. cell.bgImageView.image = bgImage;
  33. cell.senderAndTimeLabel.text = [NSString stringWithFormat:@"%@ %@", sender, time];
  34. return cell;
  35. }
在這個Cell裏設置了發送的消息的背景圖和接收消息的背景圖

這裏在字典裏有一個"time"

這是咱們接收和發送消息的時間

[java]  view plain copy print ?
  1. +(NSString *)getCurrentTime{
  2. NSDate *nowUTC = [NSDate date];
  3. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  4. [dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
  5. [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
  6. [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
  7. return [dateFormatter stringFromDate:nowUTC];
  8. }
在AppDelegate.m中

將咱們收到消息的內容也作一下調整

[java]  view plain copy print ?
  1. - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message{
  2. // ......
  3. NSMutableDictionary *dict = [NSMutableDictionary dictionary];
  4. [dict setObject:msg forKey:@"msg"];
  5. [dict setObject:from forKey:@"sender"];
  6. //消息接收到的時間
  7. [dict setObject:[Statics getCurrentTime] forKey:@"time"];
  8. ......
  9. }
最後咱們再設置一下每一行顯示的高度
[java]  view plain copy print ?
  1. //每一行的高度
  2. -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
  3. NSMutableDictionary *dict = [messages objectAtIndex:indexPath.row];
  4. NSString *msg = [dict objectForKey:@"msg"];
  5. CGSize textSize = {260.0 , 10000.0};
  6. CGSize size = [msg sizeWithFont:[UIFont boldSystemFontOfSize:13] constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];
  7. size.height += padding*2;
  8. CGFloat height = size.height < 65 ? 65 : size.height;
  9. return height;
  10. }
,對了,在發送消息的時候,別忘了也加上
[java]  view plain copy print ?
  1. - (IBAction)sendButton:(id)sender {
  2. //本地輸入框中的信息
  3. ......
  4. if (message.length > 0) {
  5. .....
  6. NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
  7. [dictionary setObject:message forKey:@"msg"];
  8. [dictionary setObject:@"you" forKey:@"sender"];
  9. [dictionary setObject:[Statics getCurrentTime] forKey:@"time"];
  10. [messages addObject:dictionary];
  11. //從新刷新tableView
  12. [self.tView reloadData];
  13. }
  14. }
好了,這裏關於XMPP發送消息的教程就結束了,之後咱們會詳細介紹其餘關於XMPP的內容

源碼下載

 

 

GitHub資源下載: https://github.com/robbiehanson/XMPPFramework

GitHub iOS客戶端使用教程: https://github.com/robbiehanson/XMPPFramework/wiki/GettingStarted_iOS

相關文章
相關標籤/搜索