Bonjour,
Bienvenue dans un nouveau tutoriel pour encore plus de folie !
Nous allons faire un mini projet, sur 2 tutos, exploitant les capacités GPS de l'iPhone, la gestion de deux vues, ...
Nous allons utiliser dans ce tuto : la gestion d'erreurs, la géolocalisation, un aperçu d'une manière de débugguer, un UIActivityIndicatorView, ...
Tout d'abord, voici ce que vous allez avoir à la fin de ce tuto :


Motivé ? Let's go !
1) Apprenons à utiliser la console en débuggage
Vous allez le remarquer, nous allons commencer à écrire un peu plus de lignes de codes qu'avant, et pour cela, nous allons utiliser la console. C'est un moyen assez simple de voir où votre code coince.
Commençons tout d'abord par modifier les préférences de XCode (<pomme + ,>) :

Voilà, c'est bien beau, mais...
Vous allez utiliser ceci :
NSLog(@"Votre texte ici");
Par exemple :
- (IBAction) updateLocation{
NSLog(@"IbAction updateLocation");
}vous affichera dans la console, lorsque vous toucherez le bouton permettant de mettre à jour votre position, "IbAction updateLocation" :

Un autre exemple, lorsque vous utilisez un tableau :
NSArray = [[NSMutableArray alloc] init]; NSLog(@"premier élément = %@", [array objectAtIndex:0]);
Vous pouvez également ajouter des points d'arrêts : en cliquant dans la colonne :

Voilà, il y a encore bien des choses à apprendre, et cela fera sûrement partie d'un tuto plus tard. Pour l'instant, je ne vous donne que les "bases" pour vous aider.
2) Entrons dans le vif du sujet avec la création de la vue
Commencez un projet View Based, "GPS up" puis créons la vue, du "GPS_upViewController.xib" qui doit ressembler à ça :

Attention, modifiez cette vue :

Important : si vous souhaitez mettre une UIImageView, créez l'interface de la vue, puis insérez une UIImageView que vous mettrez à l'aide du menu layout, en arrière plan et qui ne servira qu'à afficher le fond d'écran. (ne recevra aucune interaction)
Petite astuce : pour dupliquer les éléments sélectionnés : <pomme + d>
Nommez la vue "VueAffichageGPS"
Voici le VueAffichageGPS.h :
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
@interface VueAffichageGPS : UIView {
IBOutlet UITextField *textFieldLat;
IBOutlet UITextField *textFieldLon;
IBOutlet UITextField *textFieldAlt;
IBOutlet UIWebView *webGoogleMap;
IBOutlet UILabel *labelInfo; // le label juste au dessus de la WebView
IBOutlet UIBarButtonItem *itemStartStop;
IBOutlet UIActivityIndicatorView *indicateurActivite;
}
@endReliez tout et continuons
3) Attaquons-nous au GPS...
Alors, pour cette partie, il va falloir lire un peu...
C'est très important, car sinon vous ne comprendrez pas forcément d'où sort ce que j'écris...
Commencez par ça puis ceci et si vous êtes curieux
voilà de quoi vous occuper !
Ouf !
Ensuite, il va vous falloir ajouter la bibliothèque pour utiliser le GPS :

Allez dans

Voilà, nous avons la bibliothèque qu'il nous faut. Maintenant il faut l'utiliser :
Votre VueAffichageGPS.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <CoreLocation/CLLocationManagerDelegate.h>
@interface VueAffichageGPS : UIView {
/// la suite du code
}Lancez votre appli et vérifiez que tout fonctionne, du moins s'affiche... Comment-ça, le gps ne se lance pas ? Vous avez dû oublier quelque chose
... Meuh non, continuez !
4) Codons !
Nous allons travailler dans VueAffichageGPS.m :
Implémentons tout d'abord la méthode awakeFromNib :
- (void) awakeFromNib{
labelInfo.text = @"";
textFieldLat.text = @"latitude";
textFieldLon.text = @"longitude";
textFieldAlt.text = @"altitude";
[itemStartStop setTitle:@"Start"];
}Ensuite, écrivons les fonctions suivantes :
- (IBAction) commencerArreterLocalisation : (id)sender; - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *) oldLocation; - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *) error;
Commençons par
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *) oldLocation;
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *) oldLocation{
NSLog(@"LocManager StartUpdate");
CLLocationCoordinate2D loc = [newLocation coordinate];
textFieldLon.text = [NSString stringWithFormat: @"%f", loc.longitude];
textFieldLat.text = [NSString stringWithFormat: @"%f", loc.latitude];
textFieldAlt.text = [NSString stringWithFormat: @"%f m", newLocation.altitude];
[self afficherDansVuesLattitude:loc.latitude longitude:loc.longitude];
}Hum, qu'est-ce que cette dernière ligne ? Une méthode que nous allons créer ensemble :
dans votre .h
- (void) afficherDansVuesLattitude:(float)lat longitude:(float)lon;
dans le .m
- (void) afficherDansVuesLattitude:(float)lat longitude:(float)lon{
NSLog(@"Affichage dans googleMap latitude %f, longitude %f",lat,lon);
NSString *mapUrl = [NSString stringWithFormat: @"http://maps.google.com/maps?q=%f,%f", lat, lon];
NSURL *url = [NSURL URLWithString:mapUrl];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[webGoogleMap loadRequest:requestObj];
}Bon, maintenant, il nous faut pouvoir dire si l'on commence ou arrête la géolocalisation... Lorsque l'on appuiera sur le bouton Start/Stop. Cela se fait dans la méthode
- (IBAction) commencerArreterLocalisation : (id)sender{
}Créez tout d'abord un objet dans le .h
CLLocationManager *locManager;
Ainsi qu'une variable BOOL
BOOL enCoursDeGeolocalisation;
Une variable BOOL est une variable identique à char, mais est utilisée comme valeur booléenne :
- YES vaut 1
- NO vaut 0
Notez la modification :
- (void) awakeFromNib{
labelInfo.text = @"";
textFieldLat.text = @"latitude";
textFieldLon.text = @"longitude";
textFieldAlt.text = @"altitude";
[itemStartStop setTitle:@"Start"];
enCoursDeGeolocalisation = NO;
locManager = [[CLLocationManager alloc] init]; // initialisation de locManager
[locManager setDelegate:self]; // envoi des événements de locManager à la vue VueAffichageGPS
}Notez que comme l'on dit que notre vue "VueAffichageGPS" est delegate pour les événements de LocationManager, il faut implémenter CLLocationManagerDelegate.
La délégation sera expliquée dans le tuto 9, pas d'inquiétudes!
En java, c'est un "implements MouseListener". Ici :
@interface VueAffichageGPS : UIView <CLLocationManagerDelegate>{
// Votre code
}Le code de IBAction :
- (IBAction) commencerArreterLocalisation : (id)sender{
[locManager setDesiredAccuracy:kCLLocationAccuracyBest]; // regardez la doc pour voir les autres choix
if (enCoursDeGeolocalisation) {
[locManager stopUpdatingLocation];
enCoursDeGeolocalisation = NO;
[itemStartStop setTitle:(@"Start")];
[indicateurActivite stopAnimating];
} else {
[locManager startUpdatingLocation];
enCoursDeGeolocalisation = YES;
[itemStartStop setTitle:(@"Stop")];
[indicateurActivite startAnimating];
}
}Il faut également rajouter cette méthode, pour libérer la mémoire car on fait un init pour locManager :
- (void)dealloc {
[locManager release];
[super dealloc];
}Comme awakeFromNib, pas besoin de la déclarer dans le .h
Si vous regardez dans la doc
, vous trouvez les choix suivants pour la gestion de la précision :
Accuracy Constants
Constant values you can use to specify the accuracy of a location.
extern const CLLocationAccuracy kCLLocationAccuracyBest;
extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;
extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters;
extern const CLLocationAccuracy kCLLocationAccuracyKilometer;
extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;
Constants
kCLLocationAccuracyBest
Use the best possible accuracy.
Available in iPhone OS 2.0 and later.
Declared in CLLocation.h.
kCLLocationAccuracyNearestTenMeters
Accurate to within ten meters of the desired target.
Available in iPhone OS 2.0 and later.
Declared in CLLocation.h.
kCLLocationAccuracyHundredMeters
Accurate to within one hundred meters.
Available in iPhone OS 2.0 and later.
Declared in CLLocation.h.
kCLLocationAccuracyKilometer
Accurate to the nearest kilometer.
Available in iPhone OS 2.0 and later.
Declared in CLLocation.h.
kCLLocationAccuracyThreeKilometers
Accurate to the nearest three kilometers.
Available in iPhone OS 2.0 and later.
Declared in CLLocation.h.
Nous verrons dans le tutoriel n°9, qui sera la suite de ce projet, comment modifier cette valeur sans repasser par le code.
Lancez votre programme... Appuyez sur start. Attendez quelques secondes... Est-ce ce quelque chose s'écrit dans la console ? Oui, bravo vous avez bien retenus les anciens tutos... Non ? Shame on you ! vous avez oublié de relier le bouton à la méthode ! Ca ne marche toujours pas ? Revérifiez ce que vous avez fait puis ... si vous êtes désespérés, posez la question ! Ou regardez les sources...
Ensuite, nous allons nous occuper de cette méthode
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *) error
Le faire est optionnel, mais c'est toujours mieux de gérer les erreurs et nous sommes là pour apprendre non ?
Voici la méthode :
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *) error{
NSMutableString *messageErreur = [[[NSMutableString alloc] init] autorelease];// NSMutableString est un NSString auquel on peut rajouter du texte lorsque l'on veut
// autorelease, car nous souhaitons ne pas nous occuper de la gestion de ce NSMutableString
if ([error domain] == kCLErrorDomain) {
// Il nous faut gérer les différents types d'erreurs :
switch ([error code]) {
// L'erreur suivante est généralement retournée lorsque l'utilisateur tape "Ne pas autoriser" lorsque
// l'application lui demande si elle peut utiliser le lieu actuel. Vous devez ensuite redémarrer
// votre appli pour que ce message soit redemandé.
//
// Sachez que si vous refusez deux fois, en deux lancements successifs d'une appli, elle comprendra
// "Ne JAMAIS autoriser" ... Vous pouvez faire un reset : Réglages > Général > Réinitialiser > Réinitialiser alertes de localisation
//
case kCLErrorDenied:
messageErreur = @"Localisation refusee";
break;
// Ce message d'erreur est usuellement retourné lorsque voter iPhone n'a pas établi de connexion
//(3G, E ou Wifi), ou lorsque l'endroit ou vous vous trouvez ne peut être déterminé
//
// CoreLocation va continuer d'essayer, vous pouvez donc attendre ou avertir l'utilisateur
case kCLErrorLocationUnknown:
messageErreur = @"Localisation inconnue";
break;
// Au cas où il y ait une erreur inconnue ...
default:
messageErreur = @"Erreur globale localisation";
break;
}
} else {
//Nous gérons ici les erreurs ne concernant pas la localisation
[messageErreur appendFormat:@"Error domain: \"%@\" Error code: %d\n", [error domain], [error code]];
[messageErreur appendFormat:@"Description: \"%@\"\n", [error localizedDescription]];
}
labelInfo.text = messageErreur; // on choisit de mettre ici dans le label
}Bon, on commence à en voir le bout non ? Comment ça c'est fini ? Et oui... Du moins pour le premier tuto.
Améliorons un peu notre appli :
Gérons ensemble les directions Est/Ouest/Sud/Nord :
Voici la méthode terminée :
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *) oldLocation{
NSLog(@"LocManager StartUpdate");
CLLocationCoordinate2D loc = [newLocation coordinate];
textFieldLon.text = [NSString stringWithFormat: @"%f %@", fabs(loc.longitude),(signbit(newLocation.coordinate.longitude) ? @"Ouest" : @"Est")];
textFieldLat.text = [NSString stringWithFormat: @"%f %@", fabs(loc.latitude), (signbit(newLocation.coordinate.latitude) ? @"Sud" : @"Nord")];
textFieldAlt.text = [NSString stringWithFormat: @"%f m", newLocation.altitude];
[self afficherDansVuesLatitude:loc.latitude longitude:loc.longitude];
}Hummmm
Soit vous comprenez cette syntaxe, et c'est tant mieux pour vous, sinon, je vous l'explique en détail...
Commençons par
@"%f %@"
Ceci nous indique que notre NSString va attendre un float (%f) et un objet (%@)
fabs(nombre) // renvoie la valeur absolue de nombre
signbit(nombre) // renvoie une valeur différente de 0 si nombre est négatif ! (cherchez dans la documentation d'Apple)
signbit
long signbit (
float x
);
Parameters
x
A value of type float or double, NaN, infinity, or zero.
Return Value
Returns a non-zero value only if the sign of the argument is negative.
Discussion
This function is implemented as an inline macro.
Availability
Available in Mac OS X version 10.0 and later.
Declared In
fp.h
Je suis gentil, je l'ai fait pour vous...
Vous le savez certainement, le développeur est fainéant... La preuve :
NSString *monString = [[NSString alloc] initWithString:((signbit(newLocation.coordinate.longitude) ? @"Ouest" : @"Est")];
est équivalent à :
NSString *monString = [[NSString alloc] init];
if(signbit(newLocation.coordinate.longitude))
monString = @"Ouest"; // si longitude négative
else
monString = @"Est";Tout simplement! Vous avez compris ? Alors gérez le fait d'être au dessus ou en dessous de la mer !
des fois que vous plongiez avec votre iPhone...
Ce coup-ci on va faire quelque chose de très très dur... Insérer un splash screen (image au démarrage pour faire patienter l'utilisateur). Choisissez cette image et nommez là exactement "Default.png". Ajoutez la dans le dossier ressources de votre appli. Lancez votre appli, et ... Tadamm! Quel travail !
Comme exercices, vous pouvez afficher dans le labelInfo la vitesse par exemple. Cherchez dans la doc !
Vous pouvez également voir pour mettre les infos suivantes : distance entre 2 mesures de position, ainsi que le temps.
NB : sur simulateur, n'espérez pas être géolocalisé. Vous n'aurez droit qu'à une valeur par défaut.
A bientôt pour la suite!
sources
Ipodishima
Copyright © 2009 - ipup.fr • création de Jérémy Lagrue • design de Loann Fraillon • contact