Bygg en Jabber-klient for iOS XMPP-oppsett

Velkommen til den tredje delen av serien vår for å bygge en Jabber-klient med iOS SDK. I denne opplæringen legger vi til XMPP-funksjonaliteter til programdelegatet. Plassering av funksjonaliteten i App Delegate gjør det mulig for oss å få tilgang til XMPP-funksjonalitet fra hvor som helst i programmet.

Integrering av XMPP i AppDelegate

Som nevnt er innsetting av XMPP-funksjonaliteten i App Delegate en flott måte å gjøre funksjonaliteten lett tilgjengelig i hele appen. På et hvilket som helst sted i søknadskoden din, kan du få tilgang til appdelegatet med følgende kodestykke:

 [[UIApplication sharedApplication] delegere]

XMPP-klassen vil sende hendelser ved hjelp av protokoller som vi vil definere nedenfor. Dette er listen over hendelser som håndteres av denne klassen:

  • Klienten er koblet til serveren
  • Klienten godkjent med serveren
  • Klienten mottok et varsel om tilstedeværelse (for eksempel en bruker innlogget)
  • Klienten mottok en melding

La oss begynne med å legge til noen eiendom til programdelegatet. Først må vi importere noen XMPP-ting i overskriften:

 #import "XMPP.h"

Dette er det minimale settet av klasser som trengs for å bygge applikasjonen vår. Hvis du vil grave inn i noe mer komplekst, kan du sjekke eksemplet som er pakket sammen med XMPP-biblioteket. Her er vår første implementering av denne klassen:

 @ klasse SMBuddyListViewController; @interface jabberClientAppDelegate: NSObject UIWindow * vindu; SMBuddyListViewController * viewController; XMPPStream * xmppStream; NSString * passord; BOOL isOpen;  @property (nonatomic, behold) IBOutlet UIWindow * vindu; @property (nonatomic, behold) IBOutlet SMBuddyListViewController * viewController; @property (nonatomic, readonly) XMPPStream * xmppStream; - (BOOL) tilkobling; - (tom) koble fra; @slutt

XMPPStream vil være barebone av våre klient-server kommunikasjonssystem og alle meldinger vil bli utvekslet gjennom den. Vi vil også definere metodene for å administrere tilkobling og frakobling. Gjennomføringen av denne klassen er ganske kompleks, så vi vil bryte den ned i mange trinn. Først trenger vi noen få ekstra tilbehørsmetoder for å håndtere kunde-serverkommunikasjon. Disse kan være private, så vi plasserer dem i gjennomføringen av klassen:

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

Her er det viktigste setupStream, som skaper kanalen til å administrere utveksling av meldinger.

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

Bare to kodelinjer, men bak det skjer mange ting. De dispatch_get_main_queue () er en funksjon som returnerer en referanse
til systemnivå asynkron kjøremekanisme, som vi kan oppsummere oppgaver og motta varsler om. Her forteller vi "bare"
at vår klasse er representant for meldingene sendt fra hovedkøen, som kjøres i hovedtråden i søknaden vår. Se her for mer informasjon om Grand Central Dispatch.

Frakoblet og Online-funksjoner er i stand til å varsle andre brukere når vi er koblet til eller ikke. De er definert ved å sende en XMPPPresence gjenstand gjennom stikkontakten. Serveren vil sende varselet tilsvarende.

 - (ugyldig) goOnline XMPPPresence * presence = [XMPPPresence presence]; [[self xmppStream] sendElement: tilstedeværelse];  - (void) goOffline XMPPPresence * presence = [XMPPPresence presenceWithType: @ "utilgjengelig"]; [[self xmppStream] sendElement: tilstedeværelse]; 

De koble Metode er det viktigste, for det styrer påloggingsoperasjonen. Den returnerer en boolsk som representerer om forbindelsen var vellykket eller ikke. Først setter den opp strømmen, da bruker den data lagret i NSUserDefaults å dekorere strømmen og ringe en tilkoblingsmelding. En varselvisning vises hvis tilkoblingen ikke er vellykket.

 - (BOOL) koble [selvoppsettStream]; NSString * jabberID = [[NSUserDefaults standardUserDefaults] stringForKey: @ "userID"]; NSString * myPassword = [[NSUserDefaults standardUserDefaults] stringForKey: @ "userPassword"]; hvis (! [xmppStream isDonn Connected]) return YES;  hvis (jabberID == nil || myPassword == nil) return NO;  [xmppStream setMyJID: [XMPPJID jidWithString: jabberID]]; passord = myPassword; NSError * error = nil; hvis ! [xmppStream connect: & error]) UIAlertView * alertView = [[UIAlertView tildeling] initWithTitle: @ "Feil" melding: [NSString stringWithFormat: @ "Kan ikke koble til server% @", [error localizedDescription]] delegate : null annullerButtonTitle: @ "Ok" otherButtonTitles: null]; [alertView show]; [alertView release]; returnere nei;  returnere JA; 

For fullstendig skyld implementerer vi også frakoblingsmetoden som er definert som følger:

 - (ugyldig) koble fra [self goOffline]; [xmppStream koble fra]; 

Nå som vi har noen av de grunnleggende funksjonene, kan vi bruke dem i bestemte tilfeller, for eksempel når applikasjonen blir aktiv eller inaktiv.

 - (ugyldig) applicationWillResignActive: (UIApplication *) søknad [selvkobling];  - (ugyldig) applicationDidBecomeActive: (UIApplication *) søknad [selvkoble]; 

Vi er igjen med kjernen i systemet, meldinger om hendelser og tilhørende atferd, som vi implementerer ved hjelp av protokoller.

Definere protokoller

Vi vil definere to protokoller, en for chatvarsler som "en venn gikk frakoblet", og en for å sende meldinger mottatt. Den første protokollen inneholder beskrivelsen av tre hendelser:

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

De to første meldingene er relatert til en venns ansettelser. Vi vil reagere på disse ved å legge til eller fjerne elementer i online buddies tabellen. Den tredje kunngjør serveren når klienten kobles fra. Den andre protokollen er enklere, for det styrer bare meldingen om mottak.

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

For enkelhets skyld, for å representere meldingen vil vi bruke en ordbok med to nøkler, @ "msg" og @ "avsender", for å representere den faktiske meldingen og den faktiske avsenderen.

Implementeringsprotokoller

Begge protokollene sender meldinger fra UIApplicationDelegate. Så vi utvider vår hovedklasse ved å legge til to egenskaper (en for hver delegat).

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

I implementeringen bør vi huske å syntetisere disse egenskapene.

 @synthesize _chatDelegate, _messageDelegate;

Nå er hovedklassen vår klar til å sende hendelser til delegater. Men hvilke hendelser? De mottok fra Grand Central Dispatch. Hvis du husker,
Vi har oppsett vår UIApplicationDelegate som en delegat for strømmeldinger. Slike delegater har følgende signaturer. Navnene
er ganske selvforklarende, men vi la til kommentarer innen for å gjøre det enda tydeligere.

 - (void) xmppStreamDidConnect: (XMPPStream *) avsender // tilkobling til serveren vellykket - (void) xmppStreamDidAuthenticate: (XMPPStream *) avsender // autentisering vellykket - (void) xmppStream: (XMPPStream *) avsenderReceiveMessage :( XMPPMessage *) melding // melding mottatt - (void) xmppStream: (XMPPStream *) avsender gjordeReceivePresence: (XMPPPresence *) tilstedeværelse // en kompis gikk offline / online

La oss starte med autentisering når vi kobler til serveren.

 - (ugyldig) xmppStreamDidConnect: (XMPPStream *) avsender isOpen = YES; NSError * error = nil; [[self xmppStream] authenticateWithPassword: passord feil: & error]; 

Når godkjenning er vellykket, bør vi varsle serveren om at vi er online.

 - (ugyldig) xmppStreamDidAuthenticate: (XMPPStream *) avsender [self goOnline]; 

Når vi mottar et tilstedeværelsesvarsel, kan vi sende meldingen til chatdelegatet.

 - (void) xmppStream: (XMPPStream *) avsender gjordeReceivePresence: (XMPPPresence *) tilstedeværelse NSString * presenceType = [tilstedeværelsestype]; // online / offline NSString * myUsername = [[sender myJID] bruker]; NSString * presenceFromUser = [[tilstedeværelse fra] bruker]; hvis ! [presenceFromUser isEqualToString: myUsername]) if ([presenceType isEqualToString: @ "available"]) [_chatDelegere newBuddyOnline: [NSString stringWithFormat: @ "% @@% @", presenceFromUser, @ "jerry.local"] ];  ellers hvis ([presenceType isEqualToString: @ "utilgjengelig"]) [_chatDelegate buddyWentOffline: [NSString stringWithFormat: @ "% @@% @", presenceFromUser, @ "jerry.local"]]; 

Delegasjonen bruker disse hendelsene til å fylle ut nettkompisbordet tilsvarende (se nedenfor). Til slutt er vi igjen med meldingen mottatt varsel.

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

I dette tilfellet bygger vi en ordbok som forespurt av protokollen, og vi kaller den tilsvarende metoden. På dette punktet er kjernen i systemet vårt klart. Vi må bare gjøre at brukergrensesnittkomponentene reagerer tilsvarende.

Hooking opp visninger og kontrollører

Vi begynner med å endre vennelisten kontrolleren, som administrerer den første visningen som vises når appen er startet. Vi legger til chat-delegatet i grensesnittet som følger:

 @interface SMBuddyListViewController: UIViewController   @slutt

Vi legger til noen få tilgangsmetoder for å peke på programdelegatet og streame:

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

Vi må også forlenge viewDidLoad melding for å vise visningscontroller som en delegat for chatprotokollen.

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

Når visningen vises, hvis legitimasjon allerede er oppgitt, kaller vi tilkoblingsmetoden til programdelegatet:

 - (void) viewDidAppear: (BOOL) animert [super viewDidAppear: animated]; NSString * login = [[NSUserDefaults standardUserDefaults] objectForKey: @ "userID"]; hvis (logg inn) hvis ([[self appDelegate] connect]) NSLog (@ "vise venneliste");  else [self showLogin]; 

Til slutt må vi legge til eller fjerne objekter fra en rekke online-kompisar i henhold til hendelsene som sendes av programdelegatet.

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

Hvis du kjører programmet nå og en kompis kommer på nettet, blir tabellvisningen fylt med sitt brukernavn som i følgende figur:

Viktig notat: Avhengig av serverinnstillingene kan det hende at du må vente litt tid for å kunne motta meldingene "nye venner er online". Denne gangen har en tendens til å være fra 20 til 60 sekunder.

For å starte en samtale med brukeren må vi vise chatvisningen når den tilhørende cellen er tappet.

 - (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath NSString * userName = (NSString *) [onlineBuddies objectAtIndex: indexPath.row]; SMChatViewController * chatController = [[SMChatViewController alloker] initWithUser: userName]; [self presentModalViewController: chatController animated: YES]; 

For å fullføre søknaden må vi legge til implementeringen av meldingsdelegatet til chatvisningskontrollen. Fremgangsmåten for å gjøre det, ligner de som ble brukt på vennelistenes kontroller. Vi legger til delegaten i grensesnittfilen:

 @interface SMChatViewController: UIViewController  @slutt

Vi legger til accessors til implementeringen:

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

Vi legger til implementeringen av initWithUser: brukernavn:

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

Vi utvider viewDidLoad å erklære meldingsdelegatet og vi stiller også tekstfeltet som en første responder til tastaturinngang:

 - (void) viewDidLoad ? JabberClientAppDelegate * del = [self appDelegate]; del._messageDelegate = selv; [self.messageField becomeFirstRespesponder]; 

For å sende en melding, må vi opprette et XML-element som kreves av XMPP-protokollen og sende det over strømmen. Slik oppdaterer vi sende melding metode:

 - (IBAction) sendMessage NSString * messageStr = self.messageField.text; hvis ([messageStr lengde]> 0) NSXMLElement * body = [NSXMLElement elementWithName: @ "body"]; [body setStringValue: messageStr]; NSXMLElement * message = [NSXMLElement elementWithName: @ "message"]; [melding addAttributeWithName: @ "type" stringValue: @ "chat"]; [melding addAttributeWithName: @ "til" stringValue: chatWithUser]; [melding addChild: body]; [self.xmppStream sendElement: melding]; self.messageField.text = @ ""; NSString * m = [NSString stringWithFormat: @ "% @:% @", meldingStr, @ "deg"]; NSMutableDictionary * m = [[NSMutableDictionary alloc] init]; [m setObject: messageStr forKey: @ "msg"]; [m setObject: @ "du" forKey: @ "avsender"]; [meldinger addObject: m]; [self.tView reloadData]; [m utgivelse]; 

Vi er nå ferdig! Du kan teste den endelige implementeringen av vår iOS-klient. Vi starter serveren, iChat og vår jabber-klient. Etter en stund, bør begge klientene få et tilstedeværelsesvarsel og kjenne igjen hverandre som på nettet. På iPhone klikker vi på online-kompisen og chatvisningen vises. Nå er vi klare til å chatte. Her er et skjermbilde av den endelige søknaden på jobb.

Kildekode

Den komplette kildekoden for dette prosjektet finner du på GitHub her.