Construirea unui client Jabber pentru iOS XMPP Setup

Bine ați venit în cea de-a treia tranșă a seriei noastre despre construirea unui client Jabber cu SDK-ul iOS. În acest tutorial, vom adăuga funcționalități XMPP la Aplicația Delegată. Plasarea funcționalității în App Delegate ne va permite să accesăm ușor funcțiile XMPP de oriunde din aplicație.

Integrarea XMPP în AppDelegate

Așa cum am menționat, introducerea funcției XMPP în aplicația App Delegate este o modalitate excelentă de a face funcționalitatea ușor accesibilă în întreaga aplicație. În orice loc al codului aplicației, puteți accesa Delegatul de aplicații cu următorul fragment de cod:

 [[UIApplication sharedApplication] delegat]

Clasa XMPP va expedia evenimente prin intermediul protocoalelor pe care le vom defini mai jos. Aceasta este lista de evenimente gestionate de această clasă:

  • Clientul conectat cu serverul
  • Clientul autentificat cu serverul
  • Clientul a primit o notificare de prezență (de exemplu, un utilizator conectat)
  • Clientul a primit un mesaj

Să începem prin adăugarea unei anumite proprietăți delegatului aplicației. Mai întâi trebuie să importim niște chestii XMPP în antet:

 #import "XMPP.h"

Acesta este setul minim de clase necesare pentru a construi aplicația noastră. Dacă dorești să faci ceva mai complex, poți verifica exemplul inclus în depozitul bibliotecii XMPP. Iată prima noastră implementare a acestei clase:

 @class SMBuddyListViewController; @ interfață jabberClientAppDelegate: NSObject UIWindow * fereastră; SMBuddyListViewController * viewController; XMPPStream * xmppStream; NSString * parola; BOOL isOpen;  fereastra @property (nonatomic, reține) IBOutlet UIWindow *; @property (nonatomic, reține) IBOutlet SMBuddyListViewController * viewController; @property (nonatomic, readonly) XMPPStream * xmppStream; - (BOOL) conectați; - (void) deconectați; @Sfârșit

XMPPStream va fi barebonul sistemului nostru de comunicare client-server și toate mesajele vor fi schimbate prin intermediul acestuia. De asemenea, vom defini metodele de gestionare a conexiunii și a deconectării. Punerea în aplicare a acestei clase este destul de complexă, așa că o vom rupe în mai multe etape. În primul rând, avem nevoie de câteva metode suplimentare pentru a gestiona comunicațiile client-server. Acestea pot fi private, așadar le punem în implementarea clasei:

 @ interfață JabberClientAppDelegate () - (void) setupStream; - (void) goOnline; - (void) goOffline; @end @implementation JabberClientAppDelegate @end

Aici, cel mai important este setupStream, care creează canalul pentru a gestiona schimbul de mesaje.

 - (void) setupStream xmppStream = [[XMPPStream alocare] init]; [xmppStream addDelegate: delegateQueue: dispatch_get_main_queue ()]; 

Doar două linii de cod, dar în spatele ei se întâmplă multe lucruri. dispatch_get_main_queue () este o funcție care returnează o referință
la mecanismul de execuție asincron la nivel de sistem, la care putem comuta sarcinile și primim notificări. Aici "pur și simplu" spunem
că clasa noastră este delegatul pentru notificările trimise din coada principală, care se desfășoară în subiectul principal al aplicației noastre. Vedeți aici pentru mai multe detalii despre Grand Central Dispatch.

Funcțiile offline și online pot să notifice alți utilizatori atunci când suntem conectați sau nu. Acestea sunt definite prin trimiterea unui mesaj XMPPPresence obiect prin soclu. Serverul va trimite notificarea în consecință.

 - (void) goOnline XMPPPresence * prezență = [prezență XMPPPresență]; [[auto xmppStream] sendElement: prezență];  - (void) goOffline XMPPPresență * prezență = [XMPPPresence presenceWithType: @ "indisponibil"]; [[auto xmppStream] sendElement: prezență]; 

conectați metoda este cea mai importantă, deoarece gestionează operația de autentificare. Aceasta returnează un boolean reprezentând dacă conexiunea a avut succes sau nu. La început se instalează fluxul, apoi se utilizează datele stocate în NSUserDefaults pentru a decora fluxul și pentru a apela un mesaj de conectare. O vizualizare de alertă este afișată dacă conexiunea nu are succes.

 - (BOOL) conectați [self setupStream]; NSString * jabberID = [[NSUserDefaults standardUserDefaults] stringForKey: @ "userID"]; NSString * myPassword = [[NSUserDefaults standardUserDefaults] stringForKey: @ "userPassword"]; dacă [! [xmppStream este deconectat]) return YES;  dacă (jabberID == nil || myPassword == zero) return NO;  [xmppStream setMyJID: [XMPPJID jidWithString: jabberID]]; password = myPassword; NSError * eroare = zero; dacă [! [xmppStream connect: & eroare]) UIAlertView * alertView = [UIAlertView alinia] initWithTitle: @ mesajul "Error": [NSString stringWithFormat: @ "Nu se poate conecta la server% @", [eroare localizedDescription] : nul anuleazăButtonTitle: @ "Ok" otherButtonTitles: nil]; [alertView show]; [alertView release]; retur NO;  reveniți DA; 

Din motive de exhaustivitate, implementăm și metoda de deconectare care este definită după cum urmează:

 - (void) deconectați [self goOffline]; [xmppStream disconnect]; 

Acum, că avem câteva dintre funcțiile de bază, le putem folosi în anumite cazuri, de exemplu, când aplicația devine activă sau inactivă.

 - (void) applicationWillResignActive: (UIApplication *) aplicație [self disconnect];  - (void) applicationDidBecomeActive: (UIApplication *) cerere [auto connect]; 

Suntem lasati cu nucleul sistemului, notificarile evenimentelor si comportamentele conexe pe care le implementam prin intermediul protocoalelor.

Definirea protocoalelor

Vom defini două protocoale, unul pentru notificările de chat precum "un prieten am plecat offline" și unul pentru trimiterea mesajelor primite. Primul protocol include descrierea a trei evenimente:

 @protocolul SMChatDelegate - (void) newBuddyOnline: (NSString *) buddyName; - (void) buddyWentOffline: (NSString *) nume prieten; - (void) a deconectat; @Sfârșit

Primele două mesaje sunt legate de prezența unui prieten. Vom reacționa la acestea adăugând sau eliminând elemente în tabela de prieteni online. Al treilea doar notifică serverul atunci când clientul se deconectează. Al doilea protocol este mai simplu, deoarece gestionează doar evenimentul de primire a mesajelor.

 @protocolul SMMessageDelegate - (void) newMessageReceived: (NSDictionary *) messageContent; @Sfârșit

Din motive de simplitate, pentru a reprezenta mesajul, vom folosi un dicționar cu două taste, "msg" și @ "expeditor", pentru a reprezenta mesajul real și expeditorul real.

Protocoale de implementare

Ambele protocoale expediază mesaje de la UIApplicationDelegate. Astfel, extindem clasa principală prin adăugarea a două proprietăți (câte unul pentru fiecare delegat).

 @ interfață JabberClientAppDelegate: NSObject ? __weak NSObject * _chatDelegate; __weak NSObject * _messageDelegate;  @property (nonatomic, atribuire) id _chatDelegate; @property (nonatomic, atribuire) id _messageDelegate; @Sfârșit

În implementare ar trebui să ne amintim să sintetizeze aceste proprietăți.

 @synthesize _chatDelegate, _messageDelegate;

Acum, clasa noastră principală este pregătită să trimită evenimente delegaților. Dar ce evenimente? Acelea primite de la Marele Dispensar Central. Daca iti amintesti,
avem setarea noastră UIApplicationDelegate ca un delegat pentru mesajele stream. Acești delegați au următoarele semnături. Numele
sunt destul de auto-explicative, dar am adăugat comentarii în interiorul pentru a face mai clar.

 - (void) xmppStreamDidConnect: (XMPPStream *) expeditor // conexiune la serverul de succes - (void) xmppStreamDidAuthenticate: (XMPPStream *) expeditor // autentificare reușită - (void) xmppStream: (XMPPStream *) expeditor didReceiveMessage :( XMPPMessage *) mesajul // mesaj primit - (void) xmppStream: (XMPPStream *) expeditor didReceivePresence: (XMPPPresence *) prezență // a buddy offline offline / online

Să începem prin autentificare când ne conectăm la server.

 - (void) xmppStreamDidConnect: (XMPPStream *) expeditor isOpen = YES; NSError * eroare = zero; [[auto xmppStream] autentificaWithPassword: eroare de parola: & error]; 

Atunci când autentificarea are succes, trebuie să informăm serverul că suntem online.

 - (void) xmppStreamDidAuthenticate: (XMPPStream *) expeditor [auto goOnline]; 

Când primim o notificare de prezență, putem trimite mesajul către delegatul de chat.

 - (void) xmppStream: (XMPPStream *) expeditor didReceivePresence: (XMPPPresence *) prezență NSString * presenceType = [tip prezență]; // online / offline NSString * numele meu = [[expeditor myJID]]; NSString * presenceFromUser = [[prezență de la] utilizator]; dacă [prezențăFromUser esteEqualToString: numele meuUtilizator]) dacă ([TypeType esteEqualToString: @ "disponibil"]) [_chatDelegate newBuddyOnline: [NSString stringWithFormat: @ "% @@% @", presenceFromUser, @ "jerry.local"] ];  altfel dacă ([TypeType esteEqualToString: @ "indisponibil"]) [_chatDelegate buddyWentOffline: [NSString stringWithFormat: @ "% @@% @", presenceFromUser, @ "jerry.local"]]; 

Delegatul va folosi aceste evenimente pentru a popula tabelul online de prieteni (vezi mai jos). În cele din urmă, suntem lasați cu notificarea primită.

 - (void) xmppStream: (XMPPStream *) expeditor didReceiveMessage: (XMPPMessage *) mesaj NSString * msg = [[elementul mesajuluiForName: @ "body"] stringValue]; NSString * din = [[message attributeForName: @ "din"] stringValue]; NSMutableDictionary * m = [[NSMutableDictionary alloc] init]; [m setObject: msg pentruKey: @ "msg"]; [m setObject: de la forKey: @ "expeditor"]; [_messageDelegate newMessageReceived: m]; [eliberare m]; 

În acest caz, construim un dicționar așa cum este solicitat de protocol și numim metoda corespunzătoare. În acest moment nucleul sistemului nostru este gata. Trebuie doar să facem ca componentele interfeței utilizator să reacționeze în consecință.

Conectează vizualizări și controale

Începem prin modificarea controlerului lista de prieteni, care gestionează prima vizualizare afișată la pornirea aplicației. Adăugăm delegatul de chat în interfață după cum urmează:

 @interface SMBuddyListViewController: UIViewController   @Sfârșit

Adăugăm câteva metode de acces pentru a indica destinația delegatului și fluxului:

 - (JabberClientAppDelegate *) appDelegate retur (JabberClientAppDelegate *) [[UIApplication sharedApplication] delegat];  - (XMPPStream *) xmppStream retur [[self appDelegate] xmppStream]; 

De asemenea, trebuie să extindem viewDidLoad mesaj pentru a seta controlerul nostru de vizualizare ca delegat al protocolului de chat.

 - (void) viewDidLoad ? JabberClientAppDelegate * del = [auto appDelegate]; del._chatDelegate = auto; 

Când apare vizualizarea, dacă deja au fost introduse acreditările, sunăm metoda de conectare a delegatului aplicației:

 - (vid) viewDidAppear: (BOOL) animat [super viewDidAppear: animat]; NSString * autentificare = [[NSUserDefaults standardUserDefaults] objectForKey: @ "userID"]; dacă (login) if ([[app appDelegate] se conectează]) NSLog (@ "show buddy list");  altceva [self showLogin]; 

În cele din urmă, trebuie să adăugăm sau să eliminăm obiecte din grupul de prieteni online, în funcție de evenimentele expediate de delegatul aplicației.

 - (void) newBuddyOnline: (NSString *) nume prieten onlineBuddies addObject: buddyName]; [self.tView reloadData];  - (void) buddyWentOffline: (NSString *) buddyName [onlineBuddies removeObject: buddyName]; [self.tView reloadData]; 

Dacă rulați aplicația acum și un prieten vine online, vizualizarea tabelului este populate cu numele de utilizator ca în figura următoare:

Notă importantă: În funcție de setările serverului, poate fi necesar să așteptați un timp pentru a primi notificările "noul prieten este online". Acest timp tinde să fie de la 20 la 60 de secunde.

Pentru a începe o discuție cu utilizatorul, trebuie să afișăm vizualizarea de chat atunci când se atinge celula corespunzătoare.

 - (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath NSString * userName = (NSString *) [onlineBuddies objectAtIndex: indexPath.row]; SMChatViewController * chatController = [[SMChatViewController alocare] initWithUser: userName]; [auto prezentModalViewController: chatController animat: YES]; 

Pentru a finaliza aplicația, trebuie să adăugăm implementarea delegatului mesajului la controlerul de vizualizare a discuțiilor. Pașii pentru a face acest lucru sunt similare cu cele aplicate controlerului lista de prieteni. Adăugăm delegatul în fișierul de interfață:

 @ interfață SMChatViewController: UIViewController  @Sfârșit

Adăugăm accesori la implementare:

 - (JabberClientAppDelegate *) appDelegate retur (JabberClientAppDelegate *) [[UIApplication sharedApplication] delegat];  - (XMPPStream *) xmppStream retur [[self appDelegate] xmppStream]; 

Adăugăm implementarea initWithUser: nume de utilizator:

 - (id) initWithUser: (NSString *) numele utilizatoruluiName if (self = [super init]) chatWithUser = userName;  întoarce-te; 

Extinde viewDidLoad să declare mesajul delegat și, de asemenea, setăm câmpul de text ca un prim răspuns la intrarea tastaturii:

 - (void) viewDidLoad ? JabberClientAppDelegate * del = [auto appDelegate]; del._messageDelegate = auto; [auto.messageField become FirstResponder]; 

Pentru a trimite un mesaj, trebuie să creați un element xml conform protocolului XMPP și să îl trimiteți peste flux. Iată cum actualizăm Trimite mesaj metodă:

 - (IBAction) sendMessage NSString * messageStr = auto.messageField.text; dacă [lungimea mesajuluiStr]> 0) NSXMLElement * corp = [NSXMLElement elementWithName: @ "body"]; [body setStringValue: messageStr]; NSXMLElement * message = [NSXMLElement elementWithName: @ "mesaj"]; [mesaj addAttributeWithName: @ "tip" stringValue: @ "chat"]; [mesaj addAttributeWithName: @ "la" stringValue: chatWithUser]; [mesaj addChild: body]; [auto.xmppStream sendElement: mesaj]; auto.messageField.text = @ ""; NSString * m = [NSString șirWithFormat: @ "% @:% @", messageStr, @ "tu"]; NSMutableDictionary * m = [[NSMutableDictionary alloc] init]; [m setObject: messageStr pentruKey: @ "msg"]; [m setObject: @ "tu" pentruKey: @ "expeditor"]; [mesaje addObject: m]; [self.tView reloadData]; [eliberare m]; 

Am terminat acum! Puteți testa implementarea finală a clientului nostru iOS. Începem serverul, iChat și clientul nostru jabber. După un timp, ambii clienți ar trebui să primească o notificare de prezență și să se recunoască reciproc ca fiind online. Pe iPhone, apăsăm pe prietenul online și se afișează chat-ul. Acum suntem gata să vorbim. Iată o captură de ecran a aplicației finale la serviciu.

Cod sursa

Codul sursă complet pentru acest proiect poate fi găsit pe GitHub aici.

Cod