VisuaBlog

Aller au contenu | Aller au menu | Aller à la recherche

mercredi, janvier 2 2008

iGuideTV : 23000 hits et 5100 installations en 24h !

Wow !! je n'imaginais pas qu'il y avait autant d'iPhone/iPod débloqués en France :)

J'ai reçu 23 000 demandes de mise à jour en moins de 24h pour à peu près 5100 iGuideTV installés.

Je tiens à remercier chaleureusement toutes les personnes qui m'ont adressé leurs encouragements, ça fait chaud au coeur !

Je remercie égalements toutes celles qui l'ont installé et celles qui ont pris le temps de me communiquer leurs remarques et suggestions d'améliorations dont je peux noter les plus importantes :

- affichage des résumés des programmes,
- choix des plages horaires et/ou affichage de l'intégralité des programmes des chaînes et pas uniquement les programmes de la soirée
- localisation de l'application pour la suisse, la belgique et l'allemagne
- gestion des fuseaux horaires dans l'affichage des heures.

Concernant les bugs, je note peu de problèmes (: quel bonheur :) :
- difficulté à sélectionner les chaînes dans l'écran "Vos chaînes"
- effacement des prefs utilisateurs après un quittage forcé de l'application (5 sec de pression sur le bouton Home).

Ensuite, je dois une petite explication quand à la mise à jour des programmes. La collecte et le traitement des programmes TV sont réalisés chaque nuit à 3 heures du matin. Il s'avère que toutes les chaînes n'ont pas encore publié à cette heure les programmes du lendemain (ou du jour en cours puisqu'il est 3 heures), bref. Ceci peut donc produire un affichage incohérent des programmes car certaines chaînes sont à jour et d'autres non, l'information de mise à jour en bas de l'écran étant elle correcte. Tout ça pour dire que je décalle la mise à jour des programme du jour à 7 heure du matin et que ceci devrait offrir un affichage plus stable. J'ai identifé une autre solution avoir un affichage correcte à tout heure, je m'y pencherai dans un second temps.

Enfin, pour répondre à la principale attente, je prévois pour la semaine prochaine une mise à jour qui intègrera les résumés.

... et bonne année 2008 :)

dimanche, décembre 30 2007

Iphone : VSDownloadManager, gestion des codes des réponses HTTP

NSURLConnection ne permet pas par défaut de gérer les codes retours des requêtes HTTP. Lorsqu'un 404 Not found se présente il faut le gérer à la main.

Cette version 1.1 intègre la gestion des erreurs HTTP.

samedi, décembre 29 2007

iPhone : Télécharger des fichiers avec NSURLConnection (asynchrone)

Voici un composant qui permet de télécharger des fichiers de manières asynchrone. L'avantage de cette méthode est, hormis une gestion plus précise des événements de téléchargement, de libérer du temps/machine pour faire autre chose pendant la session de téléchargement. Typiquement, l'ajout d'un progressView à ce composant est assez facile.

VSDownloadManager utilise NSURLConnection en mode asynchrone (et non NSURLDownload qui n'est pas implémenté sur l'iPhone).

Téléchargement des sources !

Exemple d'utilisation de VSDownloadManager

#import "VSDownloadManager.h"

....

....

- (void) downloadManagerDemo {

VSDownloadManager *downloadManager = [VSDownloadManager getInstance];

// set the delegate that will receive the "

[downloadManager setDelegate:self];

// Empty the current queue

[downloadManager clearItems];

// Adding an element to download

VSDownloadManagerItem *dwlItem = [[VSDownloadManagerItem alloc] initWithURL:@"http://blog.visuaweb.com/public/Images/springboard.jpeg" AndFile:@"/var/root/springboard.jpeg" AndText:nil];

[downloadManager addItem:dwlItem];

[dwlItem release];

// Addning an element to download

VSDownloadManagerItem *dwlItem = [[VSDownloadManagerItem alloc] initWithURL:@"http://blog.visuaweb.com/public/Files/snap_joe.jpg" AndFile:@"/var/root/joe.jpeg" AndText:nil];

[downloadManager addItem:dwlItem];

[dwlItem release];

// Start the download session

[downloadManager start];

}

- (void) VSDownloadManagerDidFinishedDownloadSession:(VSDownloadManager *) sender {

NSLog(@"Download session finiched!");

VSDownloadManager.h

//

//  VSDownloadManager.h

//

//  Created by Jeremie Engel on 28/12/07.

//  Copyright 2007 VISUAWEB - http://blog.visuaweb.com. All rights reserved.

//

#import <CoreFoundation/CoreFoundation.h>

#import <Foundation/Foundation.h>

@interface VSDownloadManagerItem : NSObject {

NSString*url;

NSString*filename;

NSString*text;

}

- (id) initWithURL:(NSString*) inURL AndFile:(NSString *) inFilename AndText:(NSString *) inText;

- (NSString *) url;

- (NSString *) filename;

- (NSString *) text;

@end

@interface VSDownloadManager : NSObject {

NSMutableArray*items;

VSDownloadManagerItem * currentItem;

iddelegate;

NSURLConnection*urlConnection;

NSMutableData*receivedData;

intstate;

}

+ (void) initialize;

+ (id) getInstance;

+ (id) allocWithZone:(NSZone *)zone;

- (id) init;

- (void) addItem:(VSDownloadManagerItem *) inItem ;

- (void) clearItems ;

- (void) setDelegate:(id) inDelegate ;

- (void) start ;

@end

VSDownloadManager.m

//

//  VSDownloadManager.m

//

//  Created by Jeremie Engel on 28/12/07.

//  Copyright 2007 VISUAWEB - http://blog.visuaweb.com. All rights reserved.

//

#import "VSLog.h"

#import "VSDownloadManager.h"

@implementation VSDownloadManagerItem

- (id) initWithURL:(NSString*) inURL AndFile:(NSString *) inFilename AndText:(NSString *) inText {

if ((self=[super init])) {

[inURL retain];

url = inURL;

[inFilename retain];

filename = inFilename;

if (inText) {

[inText retain] ;

text = inText;

}

return self;

}

return nil;

}

- (NSString*) url { return url; }

- (NSString*) filename { return filename; }

- (NSString*) text { return text; }

- (NSString *) description {

return url;

}

@end

/*****************************************************************************/

static VSDownloadManager  *defaultVSDownloadManager = nil;

@implementation VSDownloadManager

+ (void) initialize { }

+ (id) getInstance {

    @synchronized(self) {

        if (defaultVSDownloadManager == nil) {

            [[self alloc] init]; // assignment not done here

        }

    }

    returndefaultVSDownloadManager;

}

+ (id)allocWithZone:(NSZone *)zone

{

    @synchronized(self) {

        if (defaultVSDownloadManager == nil) {

            defaultVSDownloadManager = [super allocWithZone:zone];

            returndefaultVSDownloadManager// assignment and return on first allocation

        }

    }

    return nil; //on subsequent allocation attempts return nil

}

- (id) init {

NSLog(@"VSDownloadManager initialize");

if ((self=[super init])) {

items = [[NSMutableArray alloc] init];

//receivedData = [[NSMutableData data] retain];

}

returnself;

}

- (void) setDelegate:(id) inDelegate {

if (delegate) [delegate release];

[inDelegate retain];

delegate = inDelegate;

}

- (void) addItem:(VSDownloadManagerItem *) inItem {

if (![items containsObject:inItem]) [items addObject:inItem];

}

- (void) clearItems {

[items removeAllObjects];

}

- (void) start {

NSLog(@"Starting download");

int i;

for (i=0; i<[items count]; i++) {

state = 1;

receivedData = [[NSMutableData alloc] initWithLength: 0];

currentItem = [items objectAtIndex:i];

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[currentItem url]] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5];

urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

while(state == 1) {

[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.1f] ];

}

}

if (delegate && [delegate respondsToSelector:@selector(VSDownloadManagerDidFinishedDownloadSession:)]) {

[delegate performSelector:@selector(VSDownloadManagerDidFinishedDownloadSession:) withObject: self];

}

}

/************** NSURLConnection Delegates *****************/

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {

[receivedData setLength:0];

}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

    [receivedData appendData:data];

}

- (void)connection:(NSURLConnection *)connection  didFailWithError:(NSError *)error {

    [receivedData release];

[connection release];

state = -1;

    NSLog(@"Connection failed! Error - %@ %@",

          [error localizedDescription],

          [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);

}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

if ([currentItem filename]) [[NSFileManager defaultManager] createFileAtPath:[currentItem filename]  contents:receivedData attributes:nil] ;

[connection release];

    [receivedData release];

state = 0;

NSLog(@"Download finished for %@", [currentItem url]);

}

/***********************************************************/

- (void) dealloc {

if (receivedData) [receivedData release];

if (urlConnection) [urlConnection release];

[items release];

[superdealloc];

}

@end

 

mardi, décembre 4 2007

Redémarrer SpringBoard pour prendre en compte une nouvelle application dans votre IPhone

SpringBoard IPhone

Lorsque l'on dépose une application dans de répertoire Applications de l'iPhone, il est nécessaire de rebooter l'IPhone pour que celle-ci soit prise en compte par le SpringBoard. Ceci peut s'avérer rébarbatif dans une phase de développement où cette opération doit être répétée un grand nombre de fois.

Plusieurs solutions existent pour éviter de redémarrer l'IPhone :

Utiliser SummerBoard qui propose une option de redémarrage du SpringBoard.

Installer les EricaUtilities pour bénéficier de la commande en ligne restart et redémarrer le SpringBoard en 1 ligne de commande via une connexion ssh :
restart /System/Library/CoreServices/SpringBoard.app/SpringBoard

Une copie est disponible de la version 0.30 ici.

Personnellement, j'utilise la méthode en ligne de commande associée à un alias zsh, c'est plus rapide quand on a une console ssh ouverte.

Configurer le Shell du IPhone

Vous avez débridé votre IPhone. Vous vous connectez dessus en ssh dès que vous pouvez ? Alors, forcément vous souhaitez personnaliser votre shell.

Le shell livré avec votre Iphone est SH (ZSH) dont voici le manuel.

Pour configurer le Shell au niveau utilisateur, il s'agit d'éditer un fichier ~/.zsh et d'ajouter la ligne suivante dans /etc/profile :
[ -r ~/.zsh ] && . ~/.zsh

le /etc/profile doit donc ressembler à :
# System-wide .profile for sh(1)

PATH="/bin:/sbin:/usr/bin:/usr/local/bin:/usr/sbin"
export PATH

TERM="vt102"
export TERM

if [ "${BASH-no}" != "no" ]; then
[ -r /etc/bashrc ] && . /etc/bashrc
fi

[ -r ~/.zsh ] && . ~/.zsh

Un alias bien pratique pour redémarrer le SpringBoard en utilisant EricaUtils (à placer dans ~/.zsh) :
alias sr='/usr/local/bin/restart \
/System/Library/CoreServices/SpringBoard.app/SpringBoard