[Objective-c] iPhone et Webservices SOAP
juillet 19, 2009
Voilà un tutorial qu’on m’a souvent demandé. Nous allons voir comment réaliser une application qui va utiliser un WebService simple, envoyer un message SOAP, recevoir la réponse et la parser pour afficher le résultat.
Il va y avoir 4 étapes :
- Creation du message SOAP
- Envoie du message SOAP
- Réception de la réponse
- Parser la réponse et l’afficher
I) Le WebService
J’ai crée un petit Webservice qui attend une chaîne et qui renvoie « Hello votre-chaine ». Un simple « HelloWorld » en quelque sorte. Il est accessible à l’url : http://www.jkraft.fr/ws/serveur.php
II) Interface Builder
Première étape on crée notre interface graphique. On part d’un modèle « View-based-application », je l’ai appelé « Soap ». On ajoute 3 UILabel, un UITextField et un UIButton pour que ça ressemble à ça .
III) Xcode
Ensuite on ajoute notre code dans SoapViewController.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @interface SoapViewController : UIViewController { IBOutlet UITextField *maSaisie; IBOutlet UILabel *monLabel; NSMutableData *webData; NSMutableString *soapResults; NSXMLParser *xmlParser; BOOL xmlResults; } @property(nonatomic, retain) IBOutlet UITextField *maSaisie; @property(nonatomic, retain) IBOutlet UILabel *monLabel; @property(nonatomic, retain) NSMutableData *webData; @property(nonatomic, retain) NSMutableString *soapResults; @property(nonatomic, retain) NSXMLParser *xmlParser; -(IBAction)envoyer; @end |
On n’oublie pas de retourner dans Interface Builder pour lier le Label à son IBOutlet et notre bouton à son action.
Ensuite on attaque le gros morceau SoapViewController.m.
On ajoute les synthetize qui vont bien :
@synthesize maSaisie, monLabel, webData, soapResults, xmlParser; |
Puis on s’occupe de la fonction envoyer. C’est elle qui va créer le message soap et l’envoyer au Webservice.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | -(IBAction)envoyer { xmlResults = FALSE; NSString *soapMessage = [NSString stringWithFormat: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" "<soap:Body>\n" "<Hello xmlns=\"http://www.jkraft.com/\">\n" "<nom>%@</nom>\n" "</Hello>\n" "</soap:Body>\n" "</soap:Envelope>\n", maSaisie.text ]; NSLog(soapMessage); NSURL *url = [NSURL URLWithString:@"http://www.jkraft.fr/ws/serveur.php"]; NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url]; NSString *msgLength = [NSString stringWithFormat:@"%d", [soapMessage length]]; [theRequest addValue: @"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; [theRequest addValue: @"http://www.jkraft.com/Hello" forHTTPHeaderField:@"SOAPAction"]; [theRequest addValue: msgLength forHTTPHeaderField:@"Content-Length"]; [theRequest setHTTPMethod:@"POST"]; [theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]]; NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self]; if( theConnection ) { webData = [[NSMutableData data] retain]; } else { NSLog(@"theConnection is NULL"); } [maSaisie resignFirstResponder]; } |
Donc on créer notre message Soap ligne 5. De la ligne 18 à 26 on prépare la connexion, en définissant l’url et très important en préparant les bonnes entêtes (Content-type, SOAPAction).
Ligne 27 on lance la connexion, attention au delegate=self il implique de gérer la connexion et ses retours.
C’est pour cela qu’on ajoute ces fonctions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { [webData setLength: 0]; } -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [webData appendData:data]; } -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"ERROR with theConkenction"); [connection release]; [webData release]; } -(void)connectionDidFinishLoading:(NSURLConnection *)connection { NSLog(@"DONE. Received Bytes: %d", [webData length]); NSString *theXML = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding]; NSLog(theXML); [theXML release]; if( xmlParser ) { [xmlParser release]; } xmlParser = [[NSXMLParser alloc] initWithData: webData]; [xmlParser setDelegate: self]; [xmlParser setShouldResolveExternalEntities: YES]; [xmlParser parse]; [connection release]; [webData release]; } |
Celle qui nous interesse le plus est connectionDidFinishLoading. Car une fois reçu la réponse, c’est ici qu’on va la traiter et dans notre cas parser le xml reçu.
Les lignes 21-22-23 ne servent que pour l’affichage dans les logs. Ligne 30 à 33 on parse notre réponse qui est webData. Attention encore une fois au [xmlParser setDelegate: self], il faut définir quelques fonctions supplémentaires qui font le boulot.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName attributes: (NSDictionary *)attributeDict { if( [elementName isEqualToString:@"Result"]) { if(!soapResults) { soapResults = [[NSMutableString alloc] init]; } xmlResults = YES; } } -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { if( xmlResults ) { [soapResults appendString: string]; } } -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { if( [elementName isEqualToString:@"Result"]) { xmlResults = FALSE; monLabel.text = soapResults; [soapResults release]; soapResults = nil; } } |
La ça se complique un peu. C’est 3 fonctions ouvrent chaque balise XML (ligne 1 à 13) regarde le nom de la balise (ligne 15 à 21) et s’il correspond à celui recherché (ici c’est Result) alors elle sauvegarde le résultat (ligne 19) et l’affiche ( ligne 28).
Attention à la gestion de la mémoire, ne pas oublier de release les objets devenus inutiles.
On peut maintenant compiler et tester l’application. Dans les logs vous devriez voir l’appel et la réponse en XML, et le résultat s’afficher dans le label.
Les sources sont téléchargeables : soap.zip
Catégorie(s): Développement, Iphone, Objective-C | Comments (19)
exemple complet et fonctionnel, hyper bien expliqué et détaillé
merci
Joli Boulot ! Merci c’est très pédagogique…
C’est exactement ce dont j’avais besoin !
Si tu pouvais m’en dire plus sur ton petit webService (création-mise en place), tu serais génial !
Bonjour,
je voudrais savoir ce que fait le fichier serveur.php
Superbe exemple, simple et fonctionnel.
Merci d’avoir laisser le webService qui va bien avec.
Je dois passer un proxy pour accéder au web, peux tu m’aiguiller sur comme générer la ligne « proxy-authorisation: …. » dans le message Soap.
Merci.
Excellent. Super bien expliqué. Ca serait très gentil de joindre la partie serveur en php
Clair, précis et efficace.
Merci pour le boulot
Merci beaucoup pour ce tuto :)))
Y a t il une possibilité d´avoir un exemple d´un formulaire écrit en objective C?
Même une petite idée sur son code?
Merci pour votre coopération
Bonjour, super tuto, les autres aussi sont bien expliqués.
Je voulais savoir comment tu as fait pour la partie php, j’en ai besoin pour un projet que je dois finir dans 1 semaine.
Toutes les autres réponses sont les bienvenues.
Merci d’avance 🙂
Bonjour, j’ai bien aimé le tuto et j’ai telechargé le code source et ça marche mais j’ai rencontré des problemes quand j’ai utilisé mon propre service en locale http://localhost:8080/axis2/services/helloWorld
j’ai pas bien su manipuler le fichier xml peut etre donc j’ai besoin de votre aide
Bonjour, comme pour safi, j’ai voulu créer mon propre webservice avec axis2 mais j’ai du mal avec l’appel de ce dernier. Comment tu fais pour écrire le message SOAP en fonction du wsdl?
Merci.
Hello Great tutorial thank you. For some reason i don’t get the result to show up what iphone simulator version are you running it in. I don’t get any error message either but i can’t get the result to show up…. Please help me Thank you…
Oui, trop trop bien ton tutoriel, il manque juste la partie PHP pour qu’il soit parfait, comment pourrait-on la récupérer?
[…] [Objective-c] iPhone et Webservices SOAP […]
thank you veru much for entry
Hi,
I have a problem with at the taking data from the web service. The problem is;
in my web service i have a datasets and its own datatables. when i request the data at the dataset which has one data table i can read data, but when i request data from dataset which has many datatable i can not read the data, i think i should request exact datatable name from the dataset. But i cannot wrote this code. Please help me.
Salut !
Excellent mais comme bcp, j aurais bien aimé avoir des infos sur la partie serveur car actuellement c est la ou je bloque ! Creer le webservice qui va communiquer entre une BDD mysql et mon appli iPhone !!
D avance merci
Bonjour, j ‘ai une petite question je viens de faire la meme sur mon webservice mais j aimerai savoir est que la donnée est enregsitrer dans la BDD mysql d ailleur romain si jamais tu as debloquer je suis prenant merci encore pour ce tuto
pourriez vous donnez lindication de ou recuperer toutes les autres données par exemple d une fonction get perso je les vois apparaitre dans le log mais apres comment les recuperer ?merci
Merci exemple complet, est ce que je peut tester dans un pc Windows ? (j’ai pas Mac)