Push Notifications und der Device Token

Terrorkeks

Terrorkeks

Aktives Mitglied
Thread Starter
Dabei seit
31.01.2012
Beiträge
2.222
Reaktionspunkte
350
Hallo Community

Ich bin nun mit unserer App soweit, dass wir Push Notifications erhalten. Allerdings wirft das ganze zwei Fragen auf:

1. Ist es normal, dass man trotz ausgeschalteter Push Notifications (Im Mitteilungsmenü) noch einen Device Token bekommt? Irgendwie wäre das ja dann völlig unnütz, da ich den Device Token ja jedes Mal an unseren Server sende. Der Feedback-Dienst gibt unserem Server also an, dass er einen nicht genutzen Token rauswerfen kann, und ich trag ihn mit dem Start der App jedes mal wieder ein??? Irgendwie kommt mir das sehr unlogisch vor.

2. Ich weiss dass es den Feedback-Dienst gibt, um nicht mehr gültige Tokens abzugleichen, aber kann ich es irgendwie bewerkstelligen, dass die App selbst unserem Server mitteilt, dass der User keine PN mehr empfangen will?

Wäre da für Antworten dankbar, da ich bei all der Fülle an verschiedenen Informationen im Web echt nicht mehr durchblicke. Ganz nebenbei scheitere ich bei solch spezifischen Anfragen auch zuverlässig mit Google... :(
 
1) Das Device Token wird immer generiert wenn Du registerForRemoteNotificationTypes: aufrufst und der Benutzer Push erlaubt (hat).

Das korrekte Vorgehen ist, das Token lokal zu speichern und zu vergleichen.
Du wirst sehen dass es sich nur selten ändert.

2)

Wenn Du nicht pushen möchtest, musst Deine App das Deinem Server seperat mitteilen. Über HTTP oder sonst wie.
Das hat ja nichts mit der Erlaubnis zum pushen oder dem Notification Center zu tun.

Tokens an die nicht gepusht wird, fliegen beim Feedback Dienst immer automatisch raus.
 
Tokens an die nicht gepusht wird, fliegen beim Feedback Dienst immer automatisch raus.

Soweit ist mir das klar. Aber irgendwie ist das ja dann unnützt, wenn ich meinen Token immer wieder an die Datenbank sende. Wie müsste denn der Code aussehen, wenn ich auslesen möchte, ob der User Push akzeptiert bzw. aktiviert hat, und falls nein, die entsprechende Unregister URL aufrufen? Mein Serveradmin hat mir dafür bereits eine entsprechende URL mitgeteilt...

1) Das Device Token wird immer generiert wenn Du registerForRemoteNotificationTypes: aufrufst und der Benutzer Push erlaubt (hat).

Ich habe das Testweise in den Settings abgeschaltet, und bekomme dennoch einen Token. Ich sage der App also, dass sie keine Push Notifications erhalten soll, der Token wird aber trotzdem generiert...

Hier ist mal der Code meiner AppDelegate.m:

Code:
//
#import "Apfeltalk_MagazinAppDelegate.h"
#import "RootViewController.h"
#import "DetailViewController.h"
#import "DetailNews.h"
#import "DetailGallery.h"
#import "DetailLiveticker.h"
#import "User.h"
#import "NewsController.h"


@implementation Apfeltalk_MagazinAppDelegate

@synthesize window;
@synthesize tabBarController;

#pragma mark - Push Notifications

//These are the methods for push notifications and it's registration

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
    NSLog(@"Eine Nachricht ist angekommen, während die App aktiv ist");
    
    NSString* alert = [[userInfo objectForKey:@"aps"] objectForKey:@"id"];

    NSLog(@"Nachricht: %@", alert);
    
    //This is to inform about new messages when the app is active
    
    //UIApplicationState state = [[UIApplication sharedApplication] applicationState];
    //if (state == UIApplicationStateActive) {
    //    UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Neuer Artikel" message:@"Nachricht" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
    //    [alertView show];
    //    }
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSLog(@"Device Token=%@", deviceToken);
    
    NSUInteger theCount = [deviceToken length];
    NSMutableString *theString = [NSMutableString stringWithCapacity:2 * theCount];
    unsigned char const *theBytes = [deviceToken bytes];
    
    for(NSUInteger i = 0; i < theCount; ++i) {
        [theString appendFormat:@"%2.2x", theBytes[i]];
    }
    
    NSString* url = [NSString stringWithFormat:@"http://xxx.xx (HIER STEHT DIE URL FÜR DIE REGISTRIERUNG DRIN)",theString,theString];
    NSLog(@"APNS URL : %@",url);
    
    NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:[url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
    
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *urlResponse, NSData *data, NSError *error) {
        if (error) {
            NSLog(@"Error: %@", error);
        }
        else
            NSLog(@"Status: %@", urlResponse);
    }];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
    NSLog(@"Error bei der Registrierung");
}
//This is the end of the methods for push notifications

- (id)init {
    self = [super init];
    if (self) {
    }
    return self;
}

+ (Apfeltalk_MagazinAppDelegate*)sharedAppDelegate {
    return (Apfeltalk_MagazinAppDelegate *)[[UIApplication sharedApplication] delegate];
} 

- (void)setApplicationDefaults {
	// !!!:below:20091018 This is not the Apple recommended way of doing this!
	if ([[NSUserDefaults standardUserDefaults] objectForKey:@"showIconBadge"] == nil)
	{
		// no default values have been set, create them here based on what's in our Settings bundle info
		[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"showIconBadge"];
		[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"shakeToReload"];
		[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"vibrateOnReload"];
        [[NSUserDefaults standardUserDefaults] setFloat:12 forKey:@"fontSize"];
	} 

    if ([[NSUserDefaults standardUserDefaults] floatForKey:@"fontSize"] == 0) {
        [[NSUserDefaults standardUserDefaults] setFloat:12 forKey:@"fontSize"];
    }
}

- (void)login {
    [[User sharedUser] login];
}

- (void)deleteCookies {
    NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[NSURL URLWithString:@"http://.mtb-news.de"]];
    for (NSHTTPCookie *c in cookies) {
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:c];
    }
}

/*- (void)applicationDidFinishLaunching:(UIApplication *)application {
 [self setApplicationDefaults];
 // Add the tab bar controller's current view as a subview of the window
 [window addSubview:tabBarController.view];
 [self login];
 }*/

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window.frame = [[UIScreen mainScreen] bounds];
    [self setApplicationDefaults];
    [[UIApplication sharedApplication] setStatusBarHidden:NO];
	[self.window makeKeyAndVisible];
    
    //This is the start of the general push notification settings
	// Let the device know we want to receive push notifications
	[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
     (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
    
    //Clear the notification center when the app has been launched
    
    [[UIApplication sharedApplication] cancelAllLocalNotifications];

    
    // Add the tab bar controller's current view as a subview of the window
    
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        NSMutableArray *viewControllers = (NSMutableArray *)tabBarController.viewControllers;
        
        UISplitViewController *splitviewController = [[UISplitViewController alloc] init];
        splitviewController.delegate = [newsController.viewControllers objectAtIndex:0];
        splitviewController.tabBarItem = newsController.tabBarItem;
        DetailNews *detailNews = [[DetailNews alloc] initWithNibName:[(NewsController *)splitviewController.delegate detailNibName] bundle:nil story:nil];
        
        splitviewController.viewControllers = [NSArray arrayWithObjects:newsController, detailNews,nil];
        [viewControllers replaceObjectAtIndex:0 withObject:splitviewController];
        [splitviewController release];
        [detailNews release];
        

        
        tabBarController.viewControllers = viewControllers;
    }
    
    window.rootViewController = tabBarController;
    return YES;
}


- (void)applicationDidBecomeActive:(UIApplication *)application {
    [self deleteCookies];
    [self login];
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [self deleteCookies];
    [[User sharedUser] setLoggedIn:NO];
}

- (void)applicationWillTerminate:(UIApplication *)application {
    [self deleteCookies];
    [[User sharedUser] setLoggedIn:NO];
}
/*
 // Optional UITabBarControllerDelegate method
 - (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
 }
 */

/*
 // Optional UITabBarControllerDelegate method
 - (void)tabBarController:(UITabBarController *)tabBarController didEndCustomizingViewControllers:(NSArray *)viewControllers changed:(BOOL)changed {
 }
 */


- (void)dealloc {
    [tabBarController release];
    [window release];
    [super dealloc];
}

@end
 
Zuletzt bearbeitet:
Es ist früh, wir reden ein bisschen aneinander vorbei.

Du hast eine App und einen Server, der das Pushen an Apple übernimmt.
Jedesmal beim Start in Deiner App rufst Du

Code:
    //This is the start of the general push notification settings
	// Let the device know we want to receive push notifications
	[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
     (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];

Und danach rufst Du immer den code auf, der das Token an den Server schickt.

Was Du brauchst ist:

a) Nach dem erhalt des Tokens in "didRegisterForRemoteNotificationsWithDeviceToken" musst Du nachschauen, ob es dasselbe Token ist dass Du das letzte mal erhalten hast. Ist das der Fall musst Du es ja nicht per HTTP an den server schicken.

b)
In Deiner App muss Du einen Schalter einbauen, der dem Benutzer die Wahl lässt ob er weiter Pushes erhalten möchte.
Das ist unabhängig davon, ob er vorher Push erlaubt hat oder die App im Notification Center ist.

Will der Benutzer keine Pushes mehr, brauchst Du eine weitere URL auf Deinem HTTP Dienst, die Dein Token löscht und keine Pushes mehr an das Gerät mit dem Token schickt. Es gibt keine andere Möglichkeit die ich kenne. Du musst ja dem HTTP Dienst sagen dass er nicht mehr pushen soll. Wer sollte das sonst wissen, wenn nicht Deine App und der HTTP Dienst.

Wird kein Push mehr empfangen trägt der Apple Push Notification Server die ID nach einer Weile selber aus. Das ist dann der Feedback Server, der sagt
"Hey an diese ID gingen keine Pushes, die vergesse ich mal..."
 
Vielen Dank... :)

Dann ist es also tatsächlich so, dass ohne weitere Schalter nur der Feedback Service das an unseren Server mitteilen kann.

Auf der App Seite kann der User dann wie gewohnt in den Einstellungen unter Mitteilungen-->Die App angeben, ob und welche Arten von Push er erhalten will. Ist da alles deaktiviert, dann bemerkt das Apple, da meine App die Notifications stets ablehnt. Das kommt dann in die Feedbackliste.

Es ist also auch normal, dass der Token immer aufgerufen wird, egal ob die Notifications nun deaktiviert sind oder nicht. Verstehe ich das soweit nun alles richtig?

Oder gibt es eine Möglichkeit, diesen Code:

Code:
//This is the start of the general push notification settings
	// Let the device know we want to receive push notifications
	[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
     (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];

Nur dann aufzurufen, wenn die Pushregler in den Einstellungen aktiviert sind? Sprich, dass wenn da alles ausgeschaltet wird, der o.g. Code gar nicht ausgeführt wird?
 
Der Feedback Service sagt nur dass Apple die ID vergisst weil sie lange keine Pushes für diese ID verschickt hat.

Deine App kann keine Pushes ablehnen. Apple interessiert nicht, was mit den Push Nachrichten passiert.
Hat der Benutzer Pushes erlaubt und Du pusht, kommen sie auch an.

EDIT:
Wenn Du unter Einstellungen -> Mitteilungen alles deaktvierst werden die Nachrichten nicht angezeigt.
Das hat aber nichts mit dem Ablehnen einer Pushnachricht zu tun.

Entziehst Du der App die Erlaubnis, bekommt sie halt nzr kein Token beim Start.
EDIT ENDE

Der Feedback Service sagt Dir halt nur dass er lange nichts von Dir gehört hat.
Du registrierst ja auch die ID nicht wirklich bei Apple sondern pusht einfach an diese.

Es ist normal dass Du jedesmal ein Token bekommst, wenn Deine App die Registrierung aufruft.
Das Token bedeutet nur, dass der Benutzer Push zugestimmt hat. Du verstehst das also richtig.

Du kannst natürlich in Deiner App beliebig viele Einstellungen für bestimmte Benachrichtigungen anbieten und nur dann
"registerForRemoteNotificationTypes" aufrufen, wenn eine davon zutrifft.

Dein Token bleibt aber dennoch dasselbe.

Du musst Deinem HTTP Dienst trotzdem mitteilen können, welche Pushes er für Dich verschicken soll.
(Ich habe mich jetzt blöd ausgedrückt aber ich hoffe Du weisst was ich meine)
 
Zuletzt bearbeitet:
Deine App kann keine Pushes ablehnen. Apple interessiert nicht, was mit den Push Nachrichten passiert.
Hat der Benutzer Pushes erlaubt und Du pusht, kommen sie auch an.

Angenommen ich habe in den Einstellungen alle Regler deaktiviert, heisst das dann, dass die Pushes zwar ankommen, dem User aber schlicht nicht angezeigt werden?
 
Ja, siehe Edit oben ;)
 
Ok, dann muss ich jetzt irgendwie auslesen, ob alle deaktiviert sind, und dann falls ja die Erlaubnis entziehen. Falls dies geschen ist, muss ich noch irgendwie dem Server mitteilen, dass er den alten Token rauswerfen kann...

Und ganz ehrlich, ich hab keine Ahnung wie ich das anstellen soll... :p
 
Wer verschickt denn Deine Pushes? Irgendwas schlimmes als OpenSource oder ein Dienst im Netz?
Ich habe meinen Push Server in C geschrieben. Das hört sich jetzt schlimmer an als es ist.
Den OpenSSL Code kann man Googlen.
Du musst nur eine SSL Verbindung mit dem Client Zertifikat Deiner App aufmachen und ein bisschen JSON hinschicken.
Feedback frag ich um ehrlich zu sein gar nicht ab.
Wichtig ist halt nur dass Du Deinem Server sagen kannst, welche pushes er rausschicken soll.

EDIT:

Sorry, noch ein Satz.
Das Token musst Du auf Deinem Server gar nicht rauswerfen.
Das bleibt ja gleich. Du musst halt Deinem Server sagen er soll nicht pushen.

Die Tokens werden irgendwie auch aus der Signatur der App abgeleitet.
Ändert man in der Info.plist die Version und installiert neu, ändert sich auch das App Token.
Ist ja auch logisch, weil es eine andere App ist.
 
Ist ein Communitykollege. Der Server selbst läuft auf Java...
 
Zurück
Oben Unten