Archive for the ‘ iPhone / iPad ’ Category

Supprimer les balises HTML dans une NSString

Dans un flux RSS, je récupère un article au format HTML et je souhaite l’afficher sans tenir compte des balises HTML. Pour supprimer les balises HTML (tags) d’une chaine de caractère NSString, j’ai intégré la solution dans une « extension » de la classe NSString.

Tout d’abord le fichier NSString-Extensions.h

@interface NSString(Extensions)
- (NSString *)removeHTMLtags;
@end

Puis le fichier NSString-Extensions.m qui contient la méthode removeHTMLtags qui permet de supprimer les balises HTML d’une NSString.

#import "NSString-Extensions.h"

@implementation NSString(HTML)

- (NSString *)removeHTMLtags {

NSString *text = nil;
NSString* html = self;

NSScanner *theScanner = [NSScanner scannerWithString:html];

while ([theScanner isAtEnd] == NO) {

        [theScanner scanUpToString:@"<" intoString:NULL] ;
        [theScanner scanUpToString:@">" intoString:&text] ;

        html = [ html stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@"%@>", text] withString:@" "];
    }
    return html;
}
@end

Source : http://rudis.net/content/2009/01/21/flatten-html-content-ie-strip-tags-cocoaobjective-c

URLWithString retourne nil

En cherchant à créer un NSURL à partir d’un fichier local, j’ai utilisé la méthode URLWithString de NSURL comme ceci :

NSURL *baseURL = [NSURL URLWithString:url];

URLWithString retournait nil… Le problème venait du chemin local qui contenait un espace, ce chemin était du type :

/Library/Application Support/iPhone Simulator/4.0.2/Applications/516C..

L’espace entre iPhone et Simulator n’était pas apprécié par URLWithString. Pour contourner le problème, il suffit de supprimer du chemin tous les caractères non-ASCII :

NSURL *baseURL = [NSURL URLWithString:[url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

Source : http://stackoverflow.com/questions/1981390/urlwithstring-returns-nil

Application iPhone rejetée à cause du logo Google Maps

J’ai dernièrement soumis une nouvelle application sur l’App Store. Avant d’être disponible en vente, une application doit passer par l’étape d’Approval c’est-à-dire de validation.

Apple fournit un ensemble de Guidelines à suivre à la lettre si l’on ne souhaite pas voir son application rejetée. Il y a un paquet de règles à suivre, je les ai « globalement » lues mais malheureusement je me suis fait avoir à cause d’une erreur que j’aurais pu éviter.

Je ne critique pas le principe de soumission d’une application, je ne fait que partager mon erreur pour éviter à d’autres de faire la même !

Mon application est passée en Rejected parce que le logo de Google était caché sur cette application où j’utilise Google Maps

J’ai donc reçu l’e-mail suivant de la part d’Apple :

We’ve completed the review of your application, but because the application displays images provided by Google Maps without the corresponding Google branding, as required under section 8.6 of the App Store Review Guidelines <https://developer.apple.com/appstore/resources/approval/guidelines.html>, we cannot post this version to the App Store.

Google requires their logo and branding to be retained on all their map images.  We hope you’ll consider revising and resubmitting your application.

C’est une erreur stupide qui fait perdre du temps puisqu’il faut alors :

  • corriger le problème (= rendre visible le nom de Google).
  • builder le projet pour  obtenir le fichier d’application .app
  • et surtout, l’étape la plus longue, refaire une soumission de l’application : encore quelques journées (voir semaines) de perdues…

A bon entendeur, salut !

Compiler pour iOS 3.1.3 avec Xcode 3.2.3

Je ne suis pas pressé de passer à l’ OS 4 sur mon iPhone 3G… apparemment ça rame pas mal ! En revanche je me suis mis à jour avec la dernière version de Xcode 3.2.3 et l’iphone SDK 4.0.2.

Après avoir installé la version de Xcode 3.2.3, il m’était impossible de compiler en utilisant le SDK 3.1.3, en effet, ce SDK n’apparait plus comme avant dans la liste des SDK disponibles à la compilation.

Quand je compile en utilisant le SDK 4 et que je veux essayer sur mon iPhone possédant l’ iOS 3.1.3, évidemment, ça ne fonctionne pas…  En effet, vu les problèmes liés à l’utilisation de l’OS 4 sur les iPhones comme le 3G, il y a fort à parier que les possesseurs d’iPhone « non 4G » seront bien content de trouver des applis qui ne nécessitent pas l’installation de l’iOS4. Perso, mes applications n’ont pas besoin des fonctionnalités du SDK 4 et des cibles en 3.1.3 me conviennent parfaitement…

Alors comment compiler pour iOS 3.1.3 avec Xcode 3.2.3 ?

En fait, ce n’est pas possible mais on peut compiler avec le SDK 4 et rendre l’appli compatible pour des iPhones ayant par exemple l’OS 3.1.3.

Pour cela, il suffit de compiler pour l’iOS 4 mais en précisant l’iPhone OS 3.1.3 comme Deployment Target. Pour cela, Project > Edit Active Target puis mettez la valeur iPhone OS 3.1.3 pour le setting iPhone OS Deployment Target.

L’application fonctionnera sur des iPhones équipés de l’OS 3.1.3 ou de l’OS 4.

Source  sur stackoverflow.com

Apple annonce le App Store Volume Purchase Program

Avec ce nouveau programme de vente, les écoles et universités peuvent désormais acheter un important volume de vos applications et vous pouvez leur faire un prix de gros afin de rendre l’offre intéressante.

Ce programme va tout d’abord permettre de simplifier l’achat lorsqu’une école souhaite acheter un grand nombre d’applications.

Il sera également possible de faire une réduction du prix de vente jusqu’à 50% et ce pour un achat d’au moins 20 applications. Cette ristourne est applicable à toutes vos applications ou seulement celles de votre choix.

Petit bémol, ce programme n’est actuellement valable que pour les écoles des États-Unis
Ce n’est que mon avis mais on peut imaginer que si ce programme est intéressant pour Apple, il sera probablement étendu aux autres pays.

Problème de connexion à iTunes Connect

Le site  iTunes Connect à l’adresse https://itunesconnect.apple.com fournit un ensemble d’outils qui permettent de gérer vos applications sur l’AppStore. Il permet notamment d’accéder à la rubrique Sales And Trades qui liste les ventes réalisées par toutes vos applications.

Depuis le 7 août, je n’arrivais plus du tout à accéder à la partie Sales And Trades… La connexion à iTunes Connect fonctionnait mais impossible de voir le nombre de ventes en cliquant sur Sales And Trades : le navigateur rame pendant un moment puis annonce un problème de connexion au serveur à l’adresse reportingitc.apple.com.

La solution à ce problème d’accès à la page Transaction Reports sur iTunes Connect est très simple : arrêter de passer via https://itunesconnect.apple.com mais utiliser l’adresse https://itts.apple.com qui arrive directement sur la page Transaction Reports.

StatusBar caché pendant le Splash screen

Pour cacher la Status Bar dans votre application, il suffit d’utiliser la ligne suivante :

[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];

Pour cacher la StatusBar pendant le splash screen, c’est à dire pendant l’apparition de Default.png cette ligne là n’est pas suffisante, il faut également mettre UIStatusBarHidden à YES dans Info.plist.

CLLocationManager sans Device

Le Simulator lancé à partir de Xcode est bien pratique car on n’a pas toujours son iPhone sous la main pour faire des tests.
Lorsque l’on utilise CoreLocation sans un iPhone mais avec le simulateur et que l’on cherche à avoir notre position actuelle, on récupère toujours les mêmes latitude et longitude : il s’agit tout simplement des coordonnées GPS d’Apple Inc !

Apple Inc.
1, infinite loop Cupertino
CA 95014

Lorsque l’on débugge sans device (= sans iPhone) des calculs de distances entre notre position actuelle et d’autres coordonnées GPS, on se retrouve avec des distances vraiment énormes (sauf si vous habitez à Cupertino !).

Ces distances énormes peuvent être pénibles lorsque l’on cherche par exemple à classer différentes coordonnées GPS par ordre de proximité, on préfère avoir des distances cohérentes pendant le débug afin de voir que tout se passe correctement…

Pour cela on peut par exemple regarder sa position actuelle sur Google Maps et récupérer la latitude et la longitude.

Ensuite il suffit d’utiliser les directives de compilateur comme ci-dessous :

-(void)locationManager:(CLLocationManager*)manager  didUpdateToLocation:(CLLocation*)newLocation  fromLocation:(CLLocation*)oldLocation
{
CLLocation *myLocation;
[locationMgr stopUpdatingLocation];
#if  TARGET_IPHONE_SIMULATOR // je mets en dur ma position pour ne pas avoir  le "1 infinite loop" d'Apple quand je suis en Simulator
myLocation = [[CLLocation alloc] initWithLatitude:-23.532787 longitude:-46.660141];
#else
myLocation = newLocation;
#endif
}

Petit rappel : pour utiliser CoreLocation, ne pas oublier de rajouter dans le .h l’import de CoreLocation.h et le delegate de CoreLocation

Utiliser le SDK 3.0 avec un iPhone sous OS 3.0.1

En faisant un update de son iPhone pour utiliser l’OS 3.0.1 on se retrouve avec le message suivant dans l’Organizer de Xcode lorsqu’on développe avec le SDK 3.0 :

The version of iPhone OS on « nom de l’iphone » does not match any of the versions of iPhone OS supported for developement with this copy of Xcode. Please restore the device to a version of the OS listed below.

La solution pour pouvoir utiliser le SDK 3.0 avec son iphone 3.0.1 est d’aller dans le dossier /Developer/Platforms/iPhoneOS.platform Il y a un dossier commençant par 3.0, le mien s’appelle 3.0 (7A300g) (Apparemment tout le monde n’a pas le même, j’en ai vu d’autres qui s’appelaient « 3.0 (7A341) »..). Il suffit donc de copier ce dossier et de le renommer 3.0.1 Une autre solution plus élégante est de faire un « raccourci » vers le dossier 3.0 (7A300g) en tapant dans le Terminal :

ln -s /Developer/Platforms/iPhoneOS.platform/DeviceSupport/3.0\ \(7A300g\) /Developer/Platforms/iPhoneOS.platform/DeviceSupport/3.0.1

Attention de bien vérifier que le dossier 3.0 (7A300g) s’appelle bien comme ça avant de rentrer cette ligne de commande dans le Terminal. Si le numéro entre parenthèses est différent, il faut biensûr le changer dans la ligne de commande ci-dessus. Attention également de bien taper cette ligne sur une seule ligne et pas deux :-s

Switch entre deux vues avec animation

Exemple très simple du passage d’une vue à une autre par une animation. Si l’utilisateur fait un « double tap » sur la vue, la deuxième vue apparait par-dessus la première en faisant une translation.

La création des deux vues (viewA et viewB) est faite dans le delegate de l’application.

Déclaration du delegate de l’application :

@class MyView;
@interface SwitchViewsAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
MyView *viewA;
MyView *viewB;
}
-(void)switchToOtherView:(UIView*) oldView;
@end

Implémentation du delegate de l’application :

@implementation SwitchViewsAppDelegate
@synthesize viewA, viewB;

-(void)applicationDidFinishLaunching:(UIApplication*)application
{
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
CGRect frame = [UIScreen mainScreen].applicationFrame;

viewA = [[MyView alloc] initWithFrame:frame];
viewA.backgroundColor = [UIColor redColor];
[window addSubview:viewA];

viewB = [[MyView alloc] initWithFrame:frame];
viewB.backgroundColor = [UIColor blueColor];
[window makeKeyAndVisible];
}

-(void)switchToOtherView:(UIView*) oldView
{
if (oldView == viewA)
{
[viewA removeFromSuperview];
[window addSubview:viewB];
}
else
{
[viewB removeFromSuperview];
[window addSubview:viewA];
}
}

CATransition *animation = [CATransition animation];
[animation setType:kCATransitionMoveIn];
[animation setSubtype:kCATransitionFromRight];
[animation setDuration:0.5];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[[window layer] addAnimation:animation forKey:@"TheKey"];
}

-(void)dealloc
{
[viewA release];
[viewB release];
[window release];
[super dealloc];
}
@end

Implementation de la class MyView :

@implementation MyView

-(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
if ([UITouch*)[touches anyObject] tapCount] == 2)
{
[[UIApplication sharedApplication].delegate switchToOtherView:self];
}
@end