Creazione di un client Jabber per iOS configurazione XMPP

Benvenuti alla terza parte della nostra serie sulla creazione di un client Jabber con l'SDK di iOS. In questo tutorial, aggiungeremo funzionalità XMPP al Delegato dell'applicazione. Posizionare la funzionalità nel Delegato app ci consentirà di accedere facilmente alle funzionalità XMPP da qualsiasi punto dell'applicazione.

Integrazione di XMPP in AppDelegate

Come accennato, l'inserimento della funzionalità XMPP nel Delegato app è un ottimo modo per rendere la funzionalità facilmente disponibile in tutta l'app. In qualsiasi posizione nel codice dell'applicazione, è possibile accedere al delegato dell'app con il seguente frammento di codice:

 [Delegato di [applicazione condivisa per l'applicazione]]

La classe XMPP invierà eventi tramite protocolli che definiremo di seguito. Questa è la lista degli eventi gestiti da questa classe:

  • Il client è connesso con il server
  • Il client autenticato con il server
  • Il cliente ha ricevuto una notifica di presenza (ad esempio, un utente ha effettuato l'accesso)
  • Il cliente ha ricevuto un messaggio

Iniziamo aggiungendo alcune proprietà al delegato dell'applicazione. Per prima cosa dobbiamo importare alcune cose XMPP nell'intestazione:

 #import "XMPP.h"

Questo è l'insieme minimo di classi necessarie per costruire la nostra applicazione. Se vuoi approfondire qualcosa di più complesso, puoi eseguire il checkout dell'esempio in bundle con il repository della libreria XMPP. Ecco la nostra prima implementazione di questa classe:

 @class SMBuddyListViewController; @interface jabberClientAppDelegate: NSObject UIWindow * window; SMBuddyListViewController * viewController; XMPPStream * xmppStream; NSString * password; BOOL isOpen;  @property (nonatomic, retain) Finestra IBOutlet UIWindow *; @property (nonatomic, retain) IBOutlet SMBuddyListViewController * viewController; @property (nonatomico, readonly) XMPPStream * xmppStream; - (BOOL) connetti; - (vuoto) disconnessione; @fine

XMPPStream sarà lo snodo del nostro sistema di comunicazione client-server e tutti i messaggi saranno scambiati attraverso di esso. Definiremo anche i metodi per gestire la connessione e la disconnessione. L'implementazione di questa classe è piuttosto complessa, quindi la suddivideremo in molti passaggi. Innanzitutto, abbiamo bisogno di alcuni altri metodi accessori per gestire le comunicazioni client-server. Questi possono essere privati, quindi li inseriamo nell'implementazione della classe:

 @interface JabberClientAppDelegate () - (void) setupStream; - (vuoto) goOnline; - (vuoto) goOffline; @end @implementation JabberClientAppDelegate @end

Qui, il più importante è setupStream, che crea il canale per gestire lo scambio di messaggi.

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

Solo due righe di codice, ma dietro a ciò accadono molte cose. Il dispatch_get_main_queue () è una funzione che restituisce un riferimento
al meccanismo di esecuzione asincrona a livello di sistema, a cui possiamo riassumere compiti e ricevere notifiche. Qui "semplicemente" diciamo
che la nostra classe è il delegato per le notifiche inviate dalla coda principale, che viene eseguita nel thread principale della nostra applicazione. Vedi qui per maggiori dettagli su Grand Central Dispatch.

Le funzioni offline e online sono in grado di notificare altri utenti quando siamo connessi o meno. Sono definiti inviando un XMPPPresence oggetto attraverso la presa. Il server invierà la notifica di conseguenza.

 - (vuoto) goOnline presenza XMPPPresence * [presenza XMPPPresence]; [[self xmppStream] sendElement: presence];  - (void) goOffline XMPPPresence * presence = [XMPPPresence presenceWithType: @ "non disponibile"]; [[self xmppStream] sendElement: presence]; 

Il Collegare il metodo è il più importante, perché gestisce l'operazione di login. Restituisce un valore booleano che indica se la connessione ha avuto successo o meno. Inizialmente imposta lo stream, quindi utilizza i dati memorizzati in NSUserDefaults per decorare lo stream e chiamare un messaggio di connessione. Viene visualizzata una vista di avviso se la connessione non riesce.

 - (BOOL) connect [self setupStream]; NSString * jabberID = [[NSUserDefaults standardUserDefaults] stringForKey: @ "userID"]; NSString * myPassword = [[NSUserDefaults standardUserDefaults] stringForKey: @ "userPassword"]; if (! [xmppStream isDisconnected]) return YES;  if (jabberID == nil || myPassword == nil) return NO;  [xmppStream setMyJID: [XMPPJID jidWithString: jabberID]]; password = myPassword; NSError * error = nil; if (! [xmppStream connect: & error]) UIAlertView * alertView = [[UIAlertView alloc] initWithTitle: @ "Errore" messaggio: [NSString stringWithFormat: @ "Impossibile connettersi al server% @", [error localizedDescription]] delegate : nil cancelButtonTitle: @ "Ok" otherButtonTitles: nil]; [show di alertView]; [versione alertView]; restituire NO;  return YES; 

Per completezza, implementiamo anche il metodo di disconnessione che è definito come segue:

 - (void) disconnect [self goOffline]; [xmppStream disconnect]; 

Ora che abbiamo alcune delle funzioni di base, possiamo usarle in casi specifici, ad esempio, quando l'applicazione diventa attiva o inattiva.

 - (void) applicationWillResignActive: (applicazione UIApplication *) [self disconnect];  - (void) applicationDidBecomeActive: (applicazione UIApplication *) [self connect]; 

Ci rimane il nucleo del sistema, le notifiche di eventi e comportamenti correlati, che implementiamo tramite protocolli.

Definizione dei protocolli

Definiremo due protocolli, uno per le notifiche di chat come "un amico andato offline" e uno per i messaggi di spedizione ricevuti. Il primo protocollo include la descrizione di tre eventi:

 @protocol SMChatDelegate - (void) newBuddyOnline: (NSString *) buddyName; - (void) buddyWentOffline: (NSString *) buddyName; - (void) didDisconnect; @fine

I primi due messaggi sono legati alle presenze di un amico. Reagiremo a questi aggiungendo o rimuovendo elementi nella tabella degli amici online. Il terzo solo notifica al server quando il nostro client si disconnette. Il secondo protocollo è più semplice, poiché gestisce solo l'evento di ricezione dei messaggi.

 @protocol SMMessageDelegate - (void) newMessageReceived: (NSDictionary *) messageContent; @fine

Per semplicità, per rappresentare il messaggio useremo un dizionario con due chiavi, @ "msg" e @ "sender", per rappresentare il messaggio effettivo e il mittente effettivo.

Protocolli di implementazione

Entrambi i protocolli inviano messaggi dal UIApplicationDelegate. Quindi estendiamo la nostra classe principale aggiungendo due proprietà (una per ogni delegato).

 @interface JabberClientAppDelegate: NSObject ? __weak NSObject * _chatDelegate; __weak NSObject * _messageDelegate;  @property (nonatomic, assign) id _chatDelegate; @property (nonatomic, assign) id _messageDelegate; @fine

Nell'implementazione dovremmo ricordare di sintetizzare queste proprietà.

 @synthesize _chatDelegate, _messageDelegate;

Ora la nostra classe principale è pronta per inviare eventi ai delegati. Ma quali eventi? Quelli ricevuti dal Grand Central Dispatch. Se ti ricordi,
abbiamo impostato il nostro UIApplicationDelegate come delegato per i messaggi in streaming. Tali delegati hanno le seguenti firme. I nomi
sono piuttosto auto-esplicativi, ma abbiamo aggiunto dei commenti per renderlo ancora più chiaro.

 - (void) xmppStreamDidConnect: (XMPPStream *) mittente // connessione al server riuscita - (void) xmppStreamDidAuthenticate: (XMPPStream *) mittente // autenticazione riuscita - (void) xmppStream: (XMPPStream *) mittente didReceiveMessage :( Messaggio XMPPMessage *) // messaggio ricevuto - (void) xmppStream: (XMPPStream *) mittente didReceivePresence: (XMPPPresence *) presenza // un amico è andato offline / online

Iniziamo con l'autenticazione quando ci colleghiamo al server.

 - (void) xmppStreamDidConnect: (XMPPStream *) sender isOpen = YES; NSError * error = nil; [[self xmppStream] authenticateWithPassword: password error: & error]; 

Quando l'autenticazione ha esito positivo, dovremmo comunicare al server che siamo online.

 - (void) xmppStreamDidAuthenticate: (XMPPStream *) mittente [self goOnline]; 

Quando riceviamo una notifica di presenza, possiamo inviare il messaggio al delegato della chat.

 - (void) xmppStream: (XMPPStream *) mittente didReceivePresence: (XMPPPresence *) presence NSString * presenceType = [tipo di presenza]; // online / offline NSString * myUsername = [[mittente myJID] utente]; NSString * presenceFromUser = [[presenza da] utente]; if (! [presenceFromUser isEqualToString: myUsername]) if ([presenceType isEqualToString: @ "available"]) [_Diaggiorna nuovoBuddyOnline: [NSString stringWithFormat: @ "% @@% @", presenceFromUser, @ "jerry.local"] ];  else if ([presenceType isEqualToString: @ "non disponibile"]) [chatDelegate buddyWentOffline: [NSString stringWithFormat: @ "% @@% @", presenceFromUser, @ "jerry.local"]]; 

Il delegato utilizzerà questi eventi per compilare di conseguenza la tabella degli amici online (vedi sotto). Alla fine, ci rimane la notifica di ricezione del messaggio.

 - (void) xmppStream: (XMPPStream *) mittente didReceiveMessage: (XMPPMessage *) message NSString * msg = [[message elementForName: @ "body"] stringValue]; NSString * from = [[message attributeForName: @ "from"] stringValue]; NSMutableDictionary * m = [[NSMutableDictionary alloc] init]; [m setObject: msg forKey: @ "msg"]; [m setObject: da forKey: @ "sender"]; [_messageDelegate newMessageReceived: m]; [m release]; 

In questo caso, costruiamo un dizionario come richiesto dal protocollo e chiamiamo il metodo corrispondente. A questo punto il nucleo del nostro sistema è pronto. Dobbiamo solo fare in modo che i componenti dell'interfaccia utente reagiscano di conseguenza.

Collegando viste e controller

Iniziamo modificando il buddy list controller, che gestisce la prima vista visualizzata all'avvio dell'app. Aggiungiamo il delegato della chat all'interfaccia come segue:

 @interface SMBuddyListViewController: UIViewController   @fine

Aggiungiamo alcuni metodi di accesso per indirizzare il delegato dell'applicazione e lo stream:

 - (JabberClientAppDelegate *) appDelegate return (JabberClientAppDelegate *) [[UIApplication sharedApplication] delegate];  - (XMPPStream *) xmppStream return [[self appDelegate] xmppStream]; 

Dobbiamo anche estendere il viewDidLoad messaggio per impostare il controller di visualizzazione come delegato per il protocollo di chat.

 - (vuoto) viewDidLoad ? JabberClientAppDelegate * del = [self appDelegate]; del._chatDelegate = self; 

Quando viene visualizzata la vista, se le credenziali sono già state immesse, chiamiamo il metodo di connessione del delegato dell'applicazione:

 - (void) viewDidAppear: (BOOL) animato [super viewDidAppear: animato]; NSString * login = [[NSUserDefaults standardUserDefaults] objectForKey: @ "userID"]; if (login) if ([[app selfdesign] connect]) NSLog (@ "show buddy list");  else [self showLogin]; 

Infine, dobbiamo aggiungere o rimuovere oggetti dalla serie di amici online in base agli eventi inviati dal delegato dell'applicazione.

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

Se esegui l'applicazione ora e un amico arriva online, la vista tabella viene popolata con il suo nome utente come nella seguente figura:

Nota importante: A seconda delle impostazioni del server, potrebbe essere necessario attendere un po 'di tempo per ricevere le notifiche "nuovo amico è online". Questa volta tende ad essere tra 20 e 60 secondi.

Per avviare una chat con l'utente, dobbiamo mostrare la vista della chat quando viene toccata la cella corrispondente.

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

Per finalizzare l'applicazione è necessario aggiungere l'implementazione del messaggio delegato al controller della vista della chat. I passaggi per farlo sono simili a quelli applicati al controller buddy list. Aggiungiamo il delegato nel file di interfaccia:

 @interface SMChatViewController: UIViewController  @fine

Aggiungiamo i metodi di accesso all'implementazione:

 - (JabberClientAppDelegate *) appDelegate return (JabberClientAppDelegate *) [[UIApplication sharedApplication] delegate];  - (XMPPStream *) xmppStream return [[self appDelegate] xmppStream]; 

Aggiungiamo l'implementazione di initWithUser: username:

 - (id) initWithUser: (NSString *) userName if (self = [super init]) chatWithUser = userName;  return self; 

Estendiamo il viewDidLoad per dichiarare il messaggio delegato e impostiamo anche il campo di testo come primo interlocutore per l'input da tastiera:

 - (vuoto) viewDidLoad ? JabberClientAppDelegate * del = [self appDelegate]; del._messageDelegate = self; [self.messageField diventaFirstResponder]; 

Per inviare un messaggio, dobbiamo creare un elemento xml come richiesto dal protocollo XMPP e inviarlo tramite lo stream. Ecco come aggiorniamo il invia messaggio metodo:

 - (IBAction) sendMessage NSString * messageStr = self.messageField.text; if ([lunghezza messaggio lunghezza]> 0) corpo NSXMLElement * = [elemento NSXMLElementWithName: @ "body"]; [body setStringValue: messageStr]; NSXMLElement * message = [NSXMLElement elementWithName: @ "message"]; [messaggio addAttributeWithName: @ "tipo" stringValue: @ "chat"]; [messaggio addAttributeWithName: @ "a" stringValue: chatWithUser]; [message addChild: body]; [self.xmppStream sendElement: messaggio]; self.messageField.text = @ ""; NSString * m = [NSString stringWithFormat: @ "% @:% @", messageStr, @ "you"]; NSMutableDictionary * m = [[NSMutableDictionary alloc] init]; [m setObject: messageStr forKey: @ "msg"]; [m setObject: @ "you" forKey: @ "sender"]; [messaggi addObject: m]; [self.tView reloadData]; [m release]; 

Ora abbiamo finito! Puoi testare l'implementazione finale del nostro client iOS. Iniziamo il server, iChat e il nostro client jabber. Dopo un po ', entrambi i client dovrebbero ricevere una notifica di presenza e riconoscersi reciprocamente come online. Sull'iPhone, tocciamo il compagno online e la vista della chat appare. Ora siamo pronti per chattare. Ecco uno screenshot dell'applicazione finale al lavoro.

Codice sorgente

Il codice sorgente completo per questo progetto può essere trovato su GitHub qui.