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
最近看了關於XMPP的框架,以文本聊天爲例,須要發送的消息爲:git
XMPP的擴展協議Jingle使得其支持語音和視頻。
- <</SPAN>message type="chat" from="kang@server.com" to="test@server.com">
- <</SPAN>body>helloWord</</SPAN>body>
- </</SPAN>message>
helloWord
基中from是從哪一個用戶發送的消息,to是發給誰的消息,XMPP的用戶都是以郵箱形式。body就是咱們發送的消息文本。github
好了,說到這裏,咱們就來開發一個基於XMPP的IOS聊天客戶端程序,首先咱們須要XMPP服務器,這裏,我就拿本機作服務器,首先從xmpp Server下載ejabberd這個服務器,ejabberd支持Linux / Mac OS X / Solaris / Windows,因此任何操做系統均可以作咱們的聊天服務器。好了,下載完後,一步一步安裝就能夠了,這裏咱們要注意一下web
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
這裏咱們的服務器就是dpc1338a(通常就是機器名,默認就能夠了,不須要改),每臺機器的用戶名都不同,這裏的服務器域名就是機器名,這個咱們須要記住哦數據庫
接着一步一步,還要設置管理員密碼,密碼固然也須要記住了,否則咱們沒辦法登陸管理員頁面去。windows
好了,安裝完後啓動,顯示以下:服務器
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
咱們點擊admin interface,會要求咱們輸入用戶名和密碼:
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
這裏用戶名是前面咱們安裝的時候有一個管理員名,將管理員名跟咱們的服務器組合就能夠了,我這裏是admin@dpc1338a,每一臺機器都不同,不要照抄哦,這樣你是登陸不了的,密碼就是安裝的時候設置的密碼
登陸成功後就會顯示以下頁面:
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
這裏咱們須要解釋的就是<<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>,也點開
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
這裏有一個<<SPAN style="COLOR: rgb(102,0,0)">用戶>,咱們須要建立幾個用戶來進行數據交互。
我建立了kang@dpc1338a,test@dpc1338a, abc@dpc1338a這幾個用戶,過一會咱們就用這幾個用戶進行聊天
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
好了,服務器裝好了之後,咱們就須要下載個客戶端來進行聊天,這裏有一些客戶端工具
http://xmpp.org/xmpp-software/clients/,這裏咱們主要推薦MAC用Adium,Windows用Citron,下一章咱們要介紹IOS的xmpp framework。
[iPhone高級] 基於XMPP的IOS聊天客戶端程序(IOS端一)
介紹完了服務器,這篇咱們就要介紹重點了,寫咱們本身的IOS客戶端程序
先看一下咱們完成的效果圖
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
首先下載xmppframework這個框架,下載
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
點ZIP下載
接下來,用Xcode新建一個工程
將如下這些文件拖入新建工程中
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
加入framework
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
並設置
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
到這裏咱們就所有設好了,跑一下試試,看有沒有錯呢
若是沒有錯的話,咱們的xmppframework就加入成功了。
咱們設置咱們的頁面以下圖:
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
咱們的KKViewController.h
- #import
- @interface KKViewController : UIViewController
- @property (strong, nonatomic) IBOutlet UITableView *tView;
- - (IBAction)Account:(id)sender;
- @end
KKViewController.m
- #import "KKViewController.h"
- @interface KKViewController (){
- //在線用戶
- NSMutableArray *onlineUsers;
- }
- @end
- @implementation KKViewController
- @synthesize tView;
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- self.tView.delegate = self;
- self.tView.dataSource = self;
- onlineUsers = [NSMutableArray array];
- // Do any additional setup after loading the view, typically from a nib.
- }
- - (void)viewDidUnload
- {
- [self setTView:nil];
- [super viewDidUnload];
- // Release any retained subviews of the main view.
- }
- - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
- {
- return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
- }
- - (IBAction)Account:(id)sender {
- }
- #pragma mark UITableViewDataSource
- -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
- return [onlineUsers count];
- }
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
- static NSString *identifier = @"userCell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
- }
- return cell;
- }
- - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
- return 1;
- }
- #pragma mark UITableViewDelegate
- -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
- }
- @end
這裏的代碼相信你們學過UITableView的話應該很熟悉了,若是不知道的話,就查一下UITableView的簡單應用學習一下吧
接下來是登陸的頁面
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
KKLoginController.m
- - (IBAction)LoginButton:(id)sender {
- if ([self validateWithUser:userTextField.text andPass:passTextField.text andServer:serverTextField.text]) {
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- [defaults setObject:self.userTextField.text forKey:USERID];
- [defaults setObject:self.passTextField.text forKey:PASS];
- [defaults setObject:self.serverTextField.text forKey:SERVER];
- //保存
- [defaults synchronize];
- [self dismissModalViewControllerAnimated:YES];
- }else {
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"請輸入用戶名,密碼和服務器"delegate:nil cancelButtonTitle:@"肯定" otherButtonTitles:nil, nil];
- [alert show];
- }
- }
- - (IBAction)closeButton:(id)sender {
- [self dismissModalViewControllerAnimated:YES];
- }
- -(BOOL)validateWithUser:(NSString *)userText andPass:(NSString *)passText andServer:(NSString *)serverText{
- if (userText.length > 0 && passText.length > 0 && serverText.length > 0) {
- return YES;
- }
- return NO;
- }
下面是聊天的頁面
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
這裏着重的仍是UITableView
KKChatController.m
- -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
- return 1;
- }
- -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
- return [messages count];
- }
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
- static NSString *identifier = @"msgCell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
- }
- NSMutableDictionary *dict = [messages objectAtIndex:indexPath.row];
- cell.textLabel.text = [dict objectForKey:@"msg"];
- cell.detailTextLabel.text = [dict objectForKey:@"sender"];
- cell.accessoryType = UITableViewCellAccessoryNone;
- return cell;
- }
這些都比較簡單,相信你們應該都能看得懂
把這些都設置好之後,咱們就要着重介紹XMPP了,怕太長了,接下一章吧。
[iPhone高級] 基於XMPP的IOS聊天客戶端程序(IOS端二)
接上一章的,這一章咱們着重介紹XMPP
爲了方便程序調用,咱們把XMPP的一些主要方法寫在AppDelegate中
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
在AppDelegate.m下這幾個方法爲:
- -(void)setupStream{
- //初始化XMPPStream
- xmppStream = [[XMPPStream alloc] init];
- [xmppStream addDelegate:self delegateQueue:dispatch_get_current_queue()];
- }
- -(void)goOnline{
- //發送在線狀態
- XMPPPresence *presence = [XMPPPresence presence];
- [[self xmppStream] sendElement:presence];
- }
- -(void)goOffline{
- //發送下線狀態
- XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
- [[self xmppStream] sendElement:presence];
- }
- -(BOOL)connect{
- [self setupStream];
- //從本地取得用戶名,密碼和服務器地址
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- NSString *userId = [defaults stringForKey:USERID];
- NSString *pass = [defaults stringForKey:PASS];
- NSString *server = [defaults stringForKey:SERVER];
- if (![xmppStream isDisconnected]) {
- return YES;
- }
- if (userId == nil || pass == nil) {
- return NO;
- }
- //設置用戶
- [xmppStream setMyJID:[XMPPJID jidWithString:userId]];
- //設置服務器
- [xmppStream setHostName:server];
- //密碼
- password = pass;
- //鏈接服務器
- NSError *error = nil;
- if (![xmppStream connect:&error]) {
- NSLog(@"cant connect %@", server);
- return NO;
- }
- return YES;
- }
- -(void)disconnect{
- [self goOffline];
- [xmppStream disconnect];
- }
這幾個是基礎方法,接下來就是XMPPStreamDelegate中的方法,也是接受好友狀態,接受消息的重要方法
- //鏈接服務器
- - (void)xmppStreamDidConnect:(XMPPStream *)sender{
- isOpen = YES;
- NSError *error = nil;
- //驗證密碼
- [[self xmppStream] authenticateWithPassword:password error:&error];
- }
- //驗證經過
- - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
- [self goOnline];
- }
- //收到消息
- - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message{
- // NSLog(@"message = %@", message);
- NSString *msg = [[message elementForName:@"body"] stringValue];
- NSString *from = [[message attributeForName:@"from"] stringValue];
- NSMutableDictionary *dict = [NSMutableDictionary dictionary];
- [dict setObject:msg forKey:@"msg"];
- [dict setObject:from forKey:@"sender"];
- //消息委託(這個後面講)
- [messageDelegate newMessageReceived:dict];
- }
- //收到好友狀態
- - (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence{
- // NSLog(@"presence = %@", presence);
- //取得好友狀態
- NSString *presenceType = [presence type]; //online/offline
- //當前用戶
- NSString *userId = [[sender myJID] user];
- //在線用戶
- NSString *presenceFromUser = [[presence from] user];
- if (![presenceFromUser isEqualToString:userId]) {
- //在線狀態
- if ([presenceType isEqualToString:@"available"]) {
- //用戶列表委託(後面講)
- [chatDelegate newBuddyOnline:[NSString stringWithFormat:@"%@@%@", presenceFromUser, @"nqc1338a"]];
- }else if ([presenceType isEqualToString:@"unavailable"]) {
- //用戶列表委託(後面講)
- [chatDelegate buddyWentOffline:[NSString stringWithFormat:@"%@@%@", presenceFromUser, @"nqc1338a"]];
- }
- }
- }
這裏面有兩個委託方法,一個是用戶列表委託,還有一個就是消息委託,用戶列表委託主要就是取得在線用戶,更新用戶TableView,消息委託就是取得好友發送的消息,並更新消息TableView,固然這兩個TableView是在不一樣的Controller中的
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
定義完兩個委託,咱們就要在不一樣的Controller中實現這兩個委託了
在好友Controller中實現並寫入以下方法
- //取得當前程序的委託
- -(KKAppDelegate *)appDelegate{
- return (KKAppDelegate *)[[UIApplication sharedApplication] delegate];
- }
- //取得當前的XMPPStream
- -(XMPPStream *)xmppStream{
- return [[self appDelegate] xmppStream];
- }
- //在線好友
- -(void)newBuddyOnline:(NSString *)buddyName{
- if (![onlineUsers containsObject:buddyName]) {
- [onlineUsers addObject:buddyName];
- [self.tView reloadData];
- }
- }
- //好友下線
- -(void)buddyWentOffline:(NSString *)buddyName{
- [onlineUsers removeObject:buddyName];
- [self.tView reloadData];
- }
在viewDidLoad中加入
- //設定在線用戶委託
- KKAppDelegate *del = [self appDelegate];
- del.chatDelegate = self;
這兩行代碼,讓好友列表的委託實現方法在本程序中
在viewWillAppear中加入
- [super viewWillAppear:animated];
- NSString *login = [[NSUserDefaults standardUserDefaults] objectForKey:@"userId"];
- if (login) {
- if ([[self appDelegate] connect]) {
- NSLog(@"show buddy list");
- }
- }else {
- //設定用戶
- [self Account:self];
- }
判斷本地保存的數據中是否有userId,沒有的話就跳轉到登陸頁面
這裏最重要的就是connect了,這一句話就是登陸了,成功的話,頁面就會顯示好友列表了。
- #pragma mark UITableViewDelegate
- -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
- //start a Chat
- chatUserName = (NSString *)[onlineUsers objectAtIndex:indexPath.row];
- [self performSegueWithIdentifier:@"chat" sender:self];
- }
- -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
- if ([segue.identifier isEqualToString:@"chat"]) {
- KKChatController *chatController = segue.destinationViewController;
- chatController.chatWithUser = chatUserName;
- }
- }
當顯示出好友列表,咱們選擇一個好友進行聊天
將當前好友名稱發送給聊天頁面
下面是聊天Controller了
在KKChatController.h中加入
- NSMutableArray *messages;
這是咱們要顯示的消息,每一條消息爲一條字典
接下來就是每一條消息的顯示了
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
- static NSString *identifier = @"msgCell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
- }
- NSMutableDictionary *dict = [messages objectAtIndex:indexPath.row];
- cell.textLabel.text = [dict objectForKey:@"msg"];
- cell.detailTextLabel.text = [dict objectForKey:@"sender"];
- cell.accessoryType = UITableViewCellAccessoryNone;
- return cell;
- }
跟上面好友Controller同樣,這裏咱們也須要XMPPStream
- -(KKAppDelegate *)appDelegate{
- return (KKAppDelegate *)[[UIApplication sharedApplication] delegate];
- }
- -(XMPPStream *)xmppStream{
- return [[self appDelegate] xmppStream];
- }
在ViewDidLoad中加入
- KKAppDelegate *del = [self appDelegate];
- del.messageDelegate = self;
設定消息委託由本身來接收和處理
- #pragma mark KKMessageDelegate
- -(void)newMessageReceived:(NSDictionary *)messageCotent{
- [messages addObject:messageCotent];
- [self.tView reloadData];
- }
接下來最重要的就是發送消息了
- - (IBAction)sendButton:(id)sender {
- //本地輸入框中的信息
- NSString *message = self.messageTextField.text;
- if (message.length > 0) {
- //XMPPFramework主要是經過KissXML來生成XML文件
- //生成文檔
- 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];
- }
- }
文檔 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端三)
前兩篇介紹瞭如何經過XMPP來發送消息和接收消息,這一篇咱們主要介紹如何來美化咱們的聊天程序,看一下最終效果呢,固然源程序也會在最後放出
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
好了,咱們來看一下咱們寫的程序
這裏咱們自定義了TableViewCell
![[iPhone高級] <wbr>基於XMPP的IOS聊天客戶端程序(全)【轉】](http://static.javashuo.com/static/loading.gif)
一行是顯示發佈日期,一行是顯示發送的消息,還有一個是背景
- -(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
- self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
- if (self) {
- //日期標籤
- senderAndTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, 300, 20)];
- //居中顯示
- senderAndTimeLabel.textAlignment = UITextAlignmentCenter;
- senderAndTimeLabel.font = [UIFont systemFontOfSize:11.0];
- //文字顏色
- senderAndTimeLabel.textColor = [UIColor lightGrayColor];
- [self.contentView addSubview:senderAndTimeLabel];
- //背景圖
- bgImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
- [self.contentView addSubview:bgImageView];
- //聊天信息
- messageContentView = [[UITextView alloc] init];
- messageContentView.backgroundColor = [UIColor clearColor];
- //不可編輯
- messageContentView.editable = NO;
- messageContentView.scrollEnabled = NO;
- [messageContentView sizeToFit];
- [self.contentView addSubview:messageContentView];
- }
- return self;
- }
定義好,在UITableViewCell中將Cell改爲咱們本身定義的Cell
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
- static NSString *identifier = @"msgCell";
- KKMessageCell *cell =(KKMessageCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
- if (cell == nil) {
- cell = [[KKMessageCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
- }
- NSMutableDictionary *dict = [messages objectAtIndex:indexPath.row];
- //發送者
- NSString *sender = [dict objectForKey:@"sender"];
- //消息
- NSString *message = [dict objectForKey:@"msg"];
- //時間
- NSString *time = [dict objectForKey:@"time"];
- CGSize textSize = {260.0 ,10000.0};
- CGSize size = [message sizeWithFont:[UIFont boldSystemFontOfSize:13] constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];
- size.width +=(padding/2);
- cell.messageContentView.text = message;
- cell.accessoryType = UITableViewCellAccessoryNone;
- cell.userInteractionEnabled = NO;
- UIImage *bgImage = nil;
- //發送消息
- if ([sender isEqualToString:@"you"]) {
- //背景圖
- bgImage = [[UIImage imageNamed:@"BlueBubble2.png"] stretchableImageWithLeftCapWidth:20topCapHeight:15];
- [cell.messageContentView setFrame:CGRectMake(padding, padding*2, size.width, size.height)];
- [cell.bgImageView setFrame:CGRectMake(cell.messageContentView.frame.origin.x - padding/2, cell.messageContentView.frame.origin.y - padding/2, size.width + padding, size.height + padding)];
- }else {
- bgImage = [[UIImage imageNamed:@"GreenBubble2.png"] stretchableImageWithLeftCapWidth:14topCapHeight:15];
- [cell.messageContentView setFrame:CGRectMake(320-size.width - padding, padding*2, size.width, size.height)];
- [cell.bgImageView setFrame:CGRectMake(cell.messageContentView.frame.origin.x - padding/2, cell.messageContentView.frame.origin.y - padding/2, size.width + padding, size.height + padding)];
- }
- cell.bgImageView.image = bgImage;
- cell.senderAndTimeLabel.text = [NSString stringWithFormat:@"%@ %@", sender, time];
- return cell;
- }
在這個Cell裏設置了發送的消息的背景圖和接收消息的背景圖
這裏在字典裏有一個"time"
這是咱們接收和發送消息的時間
- +(NSString *)getCurrentTime{
- NSDate *nowUTC = [NSDate date];
- NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
- [dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
- [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
- [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
- return [dateFormatter stringFromDate:nowUTC];
- }
在AppDelegate.m中
將咱們收到消息的內容也作一下調整
- - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message{
- // ......
- NSMutableDictionary *dict = [NSMutableDictionary dictionary];
- [dict setObject:msg forKey:@"msg"];
- [dict setObject:from forKey:@"sender"];
- //消息接收到的時間
- [dict setObject:[Statics getCurrentTime] forKey:@"time"];
- ......
- }
最後咱們再設置一下每一行顯示的高度
- //每一行的高度
- -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
- NSMutableDictionary *dict = [messages objectAtIndex:indexPath.row];
- NSString *msg = [dict objectForKey:@"msg"];
- CGSize textSize = {260.0 , 10000.0};
- CGSize size = [msg sizeWithFont:[UIFont boldSystemFontOfSize:13] constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];
- size.height += padding*2;
- CGFloat height = size.height < 65 ? 65 : size.height;
- return height;
- }
,對了,在發送消息的時候,別忘了也加上
- - (IBAction)sendButton:(id)sender {
- //本地輸入框中的信息
- ......
- if (message.length > 0) {
- .....
- NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
- [dictionary setObject:message forKey:@"msg"];
- [dictionary setObject:@"you" forKey:@"sender"];
- [dictionary setObject:[Statics getCurrentTime] forKey:@"time"];
- [messages addObject:dictionary];
- //從新刷新tableView
- [self.tView reloadData];
- }
- }
好了,這裏關於XMPP發送消息的教程就結束了,之後咱們會詳細介紹其餘關於XMPP的內容
源碼下載
GitHub資源下載: https://github.com/robbiehanson/XMPPFramework
GitHub iOS客戶端使用教程: https://github.com/robbiehanson/XMPPFramework/wiki/GettingStarted_iOS