Welkom bij de derde aflevering van onze serie over het bouwen van een Jabber-client met de iOS SDK. In deze zelfstudie voegen we XMPP-functies toe aan de toepassingsafgevaardigde. Het plaatsen van de functionaliteit in de App Delegate stelt ons in staat gemakkelijk toegang te krijgen tot XMPP-functionaliteiten overal in de applicatie.
Zoals eerder vermeld, is het invoegen van de XMPP-functionaliteit in de App Delegate een uitstekende manier om de functionaliteit eenvoudig beschikbaar te maken in de hele app. Op elke plaats in uw toepassingscode heeft u toegang tot de app-gedelegeerde met het volgende codefragment:
[[UIApplication sharedApplication] delegate]
De XMPP-klasse verzendt gebeurtenissen door middel van protocollen die we hieronder zullen definiëren. Dit is de lijst met gebeurtenissen die door deze klasse worden afgehandeld:
Laten we aan de slag gaan door de eigenschap aan de toepassingsdeelnemer toe te voegen. Eerst moeten we wat XMPP-dingen importeren in de kop:
#import "XMPP.h"
Dit is de minimale set klassen die nodig is om onze applicatie te bouwen. Als u iets ingewikkelder wilt maken, kunt u het voorbeeld downloaden dat is gebundeld met de XMPP-bibliotheekrepository. Dit is onze eerste implementatie van deze klasse:
@class SMBuddyListViewController; @interface jabberClientAppDelegate: NSObject UIWindow * window; SMBuddyListViewController * viewController; XMPPStream * xmppStream; NSString * wachtwoord; BOOL is Open; @property (niet-atomair, behouden) IBOutlet UIWindow * -venster; @property (nonatomic, retain) IBOutlet SMBuddyListViewController * viewController; @property (nonatomic, readonly) XMPPStream * xmppStream; - (BOOL) verbinden; - (ongeldig) verbroken; @einde
XMPPStream
zal de barebone zijn van ons client-servercommunicatiesysteem en alle berichten zullen hierdoor worden uitgewisseld. We zullen ook de methoden definiëren voor het beheren van de verbinding en het verbreken van de verbinding. De implementatie van deze klasse is behoorlijk ingewikkeld, dus we zullen het opsplitsen in vele stappen. Ten eerste hebben we nog enkele aanvullende methoden nodig om client-servercommunicatie af te handelen. Deze kunnen privé zijn, dus we plaatsen ze in de implementatie van de klas:
@interface JabberClientAppDelegate () - (void) setupStream; - (void) goOnline; - (ongeldig) goOffline; @end @implementation JabberClientAppDelegate @end
Hier is het belangrijkste setupStream
, die het kanaal creëert om de uitwisseling van berichten te beheren.
- (void) setupStream xmppStream = [[XMPPStream allocatie] init]; [xmppStream addDelegate: self delegateQueue: dispatch_get_main_queue ()];
Slechts twee regels code, maar daarachter gebeuren veel dingen. De dispatch_get_main_queue ()
is een functie die een referentie retourneert
naar het asynchrone uitvoeringsmechanisme op systeemniveau, waar we taken kunnen verzachten en meldingen kunnen ontvangen. Hier vertellen we het "eenvoudig"
dat onze klasse de gedelegeerde is voor de meldingen verzonden vanuit de hoofdwachtrij, die wordt uitgevoerd in de hoofddraad van onze toepassing. Kijk hier voor meer informatie over Grand Central Dispatch.
Offline en online-functies kunnen andere gebruikers op de hoogte stellen wanneer we verbonden zijn of niet. Ze worden gedefinieerd door een XMPPPresence
object door de socket. De server verzendt de melding dienovereenkomstig.
- (void) goOnline XMPPPresence * presence = [XMPPPresence presence]; [[self xmppStream] sendElement: aanwezigheid]; - (void) goOffline XMPPPresence * presence = [XMPPPresence presenceWithType: @ "unavailable"]; [[self xmppStream] sendElement: aanwezigheid];
De aansluiten
methode is het belangrijkste, want het beheert de inloghandeling. Het geeft een boolean terug die aangeeft of de verbinding succesvol was of niet. Eerst wordt de stream ingesteld en vervolgens worden de gegevens gebruikt die zijn opgeslagen in NSUserDefaults
om de stream in te richten en een connect-bericht te bellen. Een waarschuwingsweergave wordt weergegeven als de verbinding niet succesvol is.
- (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]]; wachtwoord = myPassword; NSError * error = nil; if (! [xmppStream connect: & error]) UIAlertView * alertView = [[UIAlertView alloc] initWithTitle: @ "Fout" bericht: [NSString stringWithFormat: @ "Kan geen verbinding maken met server% @", [error localizedDescription]] delegate : nil cancelButtonTitle: @ "Ok" otherButtonTitles: nil]; [alertView show]; [alertView release]; return NO; return YES;
Voor de volledigheid implementeren we ook de disconnect-methode die als volgt is gedefinieerd:
- (ongeldig) verbreekt [zelf goOffline]; [xmppStream disconnect];
Nu we enkele van de basisfuncties hebben, kunnen we ze in specifieke gevallen gebruiken, bijvoorbeeld wanneer de toepassing actief of inactief wordt.
- (ongeldig) applicationWillResignActive: (UIApplication *) applicatie [self disconnect]; - (void) applicationDidBecomeActive: (UIApplication *) applicatie [self connect];
We blijven achter met de kern van het systeem, de meldingen van gebeurtenissen en gerelateerd gedrag, die we implementeren door middel van protocollen.
We zullen twee protocollen definiëren, één voor chatmeldingen zoals "een buddy ging offline" en één voor het verzenden van ontvangen berichten. Het eerste protocol bevat de beschrijving van drie gebeurtenissen:
@protocol SMChatDelegate - (void) newBuddyOnline: (NSString *) buddyName; - (void) buddyWentOffline: (NSString *) buddyName; - (void) didDisconnect; @einde
De eerste twee berichten hebben betrekking op de aanwezigheid van een buddy. We zullen hierop reageren door elementen aan de online buddies-tabel toe te voegen of te verwijderen. De derde geeft alleen een melding aan de server wanneer onze client de verbinding verbreekt. Het tweede protocol is eenvoudiger, omdat het alleen de gebeurtenis van berichtontvangst beheert.
@protocol SMMessageDelegate - (void) newMessageReceived: (NSDictionary *) messageContent; @einde
Eenvoudigheidshalve, om het bericht weer te geven, gebruiken we een woordenboek met twee sleutels, @ "msg" en @ "afzender", om het werkelijke bericht en de daadwerkelijke afzender weer te geven.
Beide protocollen verzenden berichten van de UIApplicationDelegate
. Daarom breiden we onze hoofdklasse uit door twee eigenschappen toe te voegen (één voor elke afgevaardigde).
@interface JabberClientAppDelegate: NSObject ? __zwak NSObject * _chatDelegate; __zwak NSObject * _messageDelegate; @property (nonatomic, assign) id _chatDelegate; @property (nonatomic, assign) id _messageDelegate; @einde
In de implementatie moeten we onthouden om deze eigenschappen samen te stellen.
@synthetize _chatDelegate, _messageDelegate;
Nu staat onze hoofdklasse klaar om evenementen naar afgevaardigden te sturen. Maar welke gebeurtenissen? Die ontvangen van de Grand Central Dispatch. Als je je herinnert,
we hebben ons opgezet UIApplicationDelegate
als een gedelegeerde voor streamberichten. Dergelijke afgevaardigden hebben de volgende handtekeningen. De namen
zijn vrij voor de hand liggend, maar we hebben opmerkingen toegevoegd om het nog duidelijker te maken.
- (void) xmppStreamDidConnect: (XMPPStream *) afzender // verbinding met de server gelukt - (void) xmppStreamDidAuthenticate: (XMPPStream *) afzender // authenticatie geslaagd - (void) xmppStream: (XMPPStream *) afzender didReceiveMessage :( XMPPMessage *) bericht // bericht ontvangen - (void) xmppStream: (XMPPStream *) afzender didReceivePresence: (XMPPPresence *) aanwezigheid // een buddy ging offline / online
Laten we beginnen met authenticatie wanneer we verbinding maken met de server.
- (void) xmppStreamDidConnect: (XMPPStream *) -zender isOpen = YES; NSError * error = nil; [[self xmppStream] authenticateWithPassword: wachtwoordfout: & fout];
Wanneer de authenticatie succesvol is, moeten we de server laten weten dat we online zijn.
- (void) xmppStreamDidAuthenticate: (XMPPStream *) afzender [self goOnline];
Wanneer we een aanwezigheidskennisgeving ontvangen, kunnen we het bericht verzenden naar de chatdeelnemer.
- (void) xmppStream: (XMPPStream *) afzender didReceivePresence: (XMPPPresence *) aanwezigheid NSString * presenceType = [aanwezigheidstype]; // online / offline NSString * myUsername = [[afzender myJID] gebruiker]; NSString * presenceFromUser = [[aanwezigheid van] gebruiker]; if (! [presenceFromUser isEqualToString: myUsername]) if ([presenceType isEqualToString: @ "beschikbaar"]) [_chatDelegate newBuddyOnline: [NSString stringWithFormat: @ "% @@% @", presenceFromUser, @ "jerry.local"] ]; else if ([presenceType isEqualToString: @ "unavailable"]) [_chatDelegate buddyWentOffline: [NSString stringWithFormat: @ "% @@% @", presenceFromUser, @ "jerry.local"]];
De afgevaardigde gebruikt deze evenementen om de tabel met online vrienden dienovereenkomstig te vullen (zie hieronder). Ten slotte blijven we met het bericht ontvangen melding.
- (void) xmppStream: (XMPPStream *) afzender didReceiveMessage: (XMPPMessage *) bericht NSString * msg = [[message elementForName: @ "body"] stringValue]; NSString * from = [[message attributeForName: @ "from"] stringValue]; NSMutableDictionary * m = [[NSMutableDictionary alloc] init]; [m setObject: msg forKey: @ "msg"]; [m setObject: from forKey: @ "afzender"]; [_messageDelegate newMessageReived: m]; [m release];
In dit geval bouwen we een woordenboek op zoals gevraagd door het protocol en we noemen de overeenkomstige methode. Op dit punt is de kern van ons systeem klaar. We moeten alleen de componenten van de gebruikersinterface dienovereenkomstig laten reageren.
We beginnen met het aanpassen van de buddy list-controller, die de eerste weergave beheert die wordt weergegeven wanneer de app wordt gestart. We voegen de chat-afgevaardigde als volgt toe aan de interface:
@interface SMBuddyListViewController: UIViewController , SMChatDelegate> @end
We voegen een paar toegangsmethoden toe om te wijzen naar de applicatievertegenwoordiger en stream:
- (JabberClientAppDelegate *) appDelegate return (JabberClientAppDelegate *) [[UIApplication sharedApplication] delegate]; - (XMPPStream *) xmppStream return [[self appDelegate] xmppStream];
We moeten ook de viewDidLoad
bericht om onze view controller in te stellen als een gemachtigde voor het chatprotocol.
- (void) viewDidLoad ? JabberClientAppDelegate * del = [self appDelegate]; del._chatDelegate = zelf;
Wanneer de weergave wordt weergegeven en de inloggegevens al zijn ingevoerd, noemen we de verbindingsmethode van de toepassingsdeelnemer:
- (void) viewDidAppear: (BOOL) geanimeerde [super viewDidAppear: geanimeerd]; NSString * login = [[NSUserDefaults standardUserDefaults] objectForKey: @ "userID"]; if (login) if ([[self appDelegate] connect]) NSLog (@ "toon buddylijst"); else [self showLogin];
Ten slotte moeten we objecten toevoegen aan of verwijderen uit de reeks online vrienden op basis van de gebeurtenissen die zijn verzonden door de gedelegeerde van de toepassing.
- (void) newBuddyOnline: (NSString *) buddyName [onlineBuddies addObject: buddyName]; [self.tView reloadData]; - (void) buddyWentOffline: (NSString *) buddyName [onlineBuddies removeObject: buddyName]; [self.tView reloadData];
Als u de toepassing nu uitvoert en een buddy online komt, wordt de tabelweergave gevuld met zijn gebruikersnaam zoals in de volgende afbeelding:
Belangrijke notitie: Afhankelijk van de serverinstellingen, moet u mogelijk enige tijd wachten om de "nieuwe buddy is online" -meldingen te ontvangen. Deze tijd is meestal 20 tot 60 seconden.
Om een chat met de gebruiker te starten, moeten we de chat-weergave tonen wanneer op de overeenkomstige cel wordt getikt.
- (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath NSString * userName = (NSString *) [onlineBuddies objectAtIndex: indexPath.row]; SMChatViewController * chatController = [[SMChatViewController alloc] initWithUser: userName]; [self presentModalViewController: chatController animated: YES];
Om de applicatie te finaliseren, moeten we de implementatie van de afgevaardigden van het bericht toevoegen aan de chatview-controller. De stappen om dit te doen zijn vergelijkbaar met die voor de buddy list-controller. We voegen de deelnemer toe aan het interfacebestand:
@interface SMChatViewController: UIViewController , SMMessageDelegate> @einde
We voegen accessors toe aan de implementatie:
- (JabberClientAppDelegate *) appDelegate return (JabberClientAppDelegate *) [[UIApplication sharedApplication] delegate]; - (XMPPStream *) xmppStream return [[self appDelegate] xmppStream];
We voegen de implementatie toe van initWithUser: gebruikersnaam
:
- (id) initWithUser: (NSString *) userName if (self = [super init]) chatWithUser = userName; terugkeer zelf;
We verlengen de viewDidLoad
om het bericht te delegeren en we stellen ook het tekstveld in als eerste antwoord op toetsenbordinvoer:
- (void) viewDidLoad ? JabberClientAppDelegate * del = [self appDelegate]; del._messageDelegate = zelf; [self.messageField becomeFirstResponder];
Om een bericht te verzenden, moeten we een xml-element maken zoals vereist door het XMPP-protocol en dit over de stream verzenden. Dit is hoe we het updaten bericht versturen
methode:
- (IBAction) sendMessage NSString * messageStr = self.messageField.text; if ([messageStr length]> 0) NSXMLElement * body = [NSXMLElement elementWithName: @ "body"]; [body setStringValue: messageStr]; NSXMLElement * message = [NSXMLElement elementWithName: @ "message"]; [message addAttributeWithName: @ "type" stringValue: @ "chat"]; [message addAttributeWithName: @ "to" stringValue: chatWithUser]; [bericht addChild: body]; [self.xmppStream sendElement: message]; self.messageField.text = @ ""; NSString * m = [NSString stringWithFormat: @ "% @:% @", messageStr, @ "you"]; NSMutableDictionary * m = [[NSMutableDictionary alloc] init]; [m setObject: messageStr forKey: @ "msg"]; [m setObject: @ "you" forKey: @ "afzender"]; [berichten addObject: m]; [self.tView reloadData]; [m release];
We zijn nu klaar! U kunt de uiteindelijke implementatie van onze iOS-client testen. We starten de server, iChat en onze jabber-client. Na een tijdje zouden beide klanten een aanwezigheidskennisgeving moeten ontvangen en elkaar als online moeten herkennen. Op de iPhone tikken we op de online buddy en de chat-weergave verschijnt. Nu zijn we klaar om te chatten. Hier is een screenshot van de laatste applicatie op het werk.
De volledige broncode voor dit project is hier te vinden op GitHub.