[iOS] Demande de device token chez apple depuis notre application

mardi 31 mai 2016

Selon la doc d’Apple, il faut rajouter dans la fonction didFinishLaunchingWithOptions, la demande d’enregistrement pour recevoir les notifications push ou RemoteNotifications.

    // IF IOS 8 and greater
    if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
        UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
        [application registerForRemoteNotifications];
    }else{
        [[UIApplication sharedApplication]
         registerForRemoteNotificationTypes:
         (UIRemoteNotificationTypeAlert |
          UIRemoteNotificationTypeBadge |
          UIRemoteNotificationTypeSound)];
    }

Ce code permet donc de définir le type de notification souhaitez et la demande d’enregistrement auprès d’Apple pour recevoir les notifications push. Et donc trois fonctions delegate peut être utilisée:

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
}

Cette première fonction delegate permet de connaître le choix de l’utilisateur lorsqu’il reçoit le popup si il accepte ou non les notifications. L’attribut notificationSettings.types retournent le choix de l’utilisateur des réglages. Il est par exemple possible de déplacer la commande [application registerForRemoteNotifications] dans cette fonction pour faire la demande chez Apple du deviceToken uniquement si l’utilisateur a accepté les notifications. mais attention cette fonction sera toujours appelé même si l’utilisateur n’a pas changé les settings et laissé la même configuration concernant les notifications. Malheureusement cette fonction ne tient pas compte si les réglages concernant les notifications ont changé lorsque l’utilisateur va par après dans les réglages du téléphone pour les changer. Donc dans mon cas, je n’utilise pas cette fonction mais juste les deux fonctions suivantes:

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
    const void *devTokenBytes = [devToken bytes];
    self.registered = YES;
    [self sendProviderDeviceToken:devTokenBytes]; // custom method
}

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
    NSLog(@"Error in registration. Error: %@", err);
}

La méthode didRegisterForRemoteNotificationsWithDeviceTokenpermet de retourner le device token retourné par Apple et qui permet d’identifier le téléphone pour l’envoi des notifications push depuis un serveur. la deuxième méthode permet de gérer le cas ou il y a eux un problème avec la demande de device_token chez Apple.

En conclusion, en se basant sur les deux méthodes ci dessous et le code fourni par Apple dans la fonction didFinishLaunchingWithOptions de l’AppDelegate, il semblerait que Apple souhaite qu’on fait appel à la fonction registerForRemoteNotifications à chaque lancement de l’application. Mais attention cela ne fait pas la demande au près d’Apple pour recevoir un device Token! En effet celui-ci peut changer lors de la restauration du téléphone ou autre et donc Apple nous renverra un nouveau device token sinon le téléphone retournera le même device token. Donc en gros, cette méthode est toujours appelée et retourne toujours le token mais on ne sait pas si il vient de chez Apple ou si c’est le téléphone qui renvoie le même device token. Il est impératif de faire de cette manière car si l’utilisateur change les settings du téléphone pour les notifications, si il les désactive il ne fait pas la demande chez Apple, par contre si il les réactive la fonction de demande de Token sera appelé automatiquement. C’est aussi pourquoi il ne faut pas sauver le token dans le téléphone car on ne sait pas détecter si l’utilisateur a désactivé les notifications car aucune fonction delegate ne semble être appelée. Par contre si on sauve dans la fonction didRegisterForRemoteNotificationsWithDeviceToken le token via webservice il sera appelé uniquement quand l’utilisateur aura à nouveau accepté les notifications.

En résumé, voici le code fonctionnel, ni plus ni moins:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // IF IOS 8 AND GREATER
    if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
        UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
        [application registerForRemoteNotifications];
    }else{
        [[UIApplication sharedApplication]
         registerForRemoteNotificationTypes:
         (UIRemoteNotificationTypeAlert |
          UIRemoteNotificationTypeBadge |
          UIRemoteNotificationTypeSound)];
    }
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSLog(@"didRegisterForRemoteNotificationsWithDeviceToken called");
        NSString *device = [[[[deviceToken description]
                              stringByReplacingOccurrencesOfString: @"<" withString: @""]
                             stringByReplacingOccurrencesOfString: @">" withString: @""]
                            stringByReplacingOccurrencesOfString: @" " withString: @""];
        self.registered = YES;
        [self sendProviderDeviceToken:device]; // custom method

}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
    NSLog(@"didFailToRegisterForRemoteNotificationsWithError called");
    NSString *str = [NSString stringWithFormat: @"Error: %@", err];
    NSLog(@"%@",str);   
}

Tags: Notifications , token