Unexpected behaviour from registerUserNotificationSettings: and registerForRemoteNotifications - cocoa-touch

I am getting what I believe is an expected behaviour with Push Notifications in iOS 8 in terms of what kind of UIUserNotificationType I should received.
The test I have run is the following:
UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
UIUserNotificationSettings *mySettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
UIApplication *sharedApplication = [UIApplication sharedApplication];
[sharedApplication registerUserNotificationSettings:mySettings];
[sharedApplication registerForRemoteNotifications];
I get the expected UIApplicationDelegate calls and when I send a Push Notification, I receive an alert as expected. All fine until here.
Then, I unregister for remote notifications:
[[UIApplication sharedApplication] unregisterForRemoteNotifications];
And I ran the same code as above but in this case, I do not call registerUserNotificationSettings:
UIApplication *sharedApplication = [UIApplication sharedApplication];
[sharedApplication registerForRemoteNotifications];
I again get all the expected UIApplicationDelegate calls but when I send the same Push Notification, I get the alert on my device and I believe that is not correct. I think I should not get any alert, sound or badge as the the documentation says:
If you want your app’s remote notifications to display alerts, play sounds, or perform other user-facing actions, you must call the registerUserNotificationSettings: method to request the types of notifications you want to use. If you do not call that method, the system delivers all remote notifications to your app silently.
To double check that, I have run just the second snippet on a different device:
UIApplication *sharedApplication = [UIApplication sharedApplication];
[sharedApplication registerForRemoteNotifications];
And in that case I did not get any alert as expected.
Is that the normal behaviour? I would expect that after unregistering, the preferences expressed in the next registration (no preferences in this case) would take precedence but it seems that when registerUserNotificationSettings: is not called, the previous settings are cached somewhere and used to decide what kind of notifications are delivered to the app.

In order to achieve the behavior you want, you should call to registerUserNotificationSettings with a setting configured with no type. This way you will override the cached settings. Like this:
UIUserNotificationType types = UIUserNotificationTypeNone;
UIUserNotificationSettings *mySettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
UIApplication *sharedApplication = [UIApplication sharedApplication];
[sharedApplication registerUserNotificationSettings:mySettings];
[sharedApplication registerForRemoteNotifications];
If you don't reconfigure the user notification settings, the cached value (that, as you have noticed, persists application reinstalls) will be used.

Related

Local Notifications - asking for permission again after initially rejected

When an app launches for the first time, it will ask the user for permission to send local notifications.
If the user denies the permission at launch, how do we ask for permission again in the future?
For example, is there a way that on a button click, I can request permission again?
Here is my code to initially ask for permission at launch:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
// are you running on iOS8?
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)])
{
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound) categories:nil];
[application registerUserNotificationSettings:settings];
}
else // iOS 7 or earlier
{
UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
[application registerForRemoteNotificationTypes:myTypes];
}
}
If for the first time you have disallowed local notification and on the second time use the blow mentioned code:
if ([[UIApplication sharedApplication] respondsToSelector:#selector(currentUserNotificationSettings)]
{
UIUserNotificationSettings *grantedSettings = [[UIApplication sharedApplication] currentUserNotificationSettings];
if (grantedSettings.types == UIUserNotificationTypeNone)
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"app-settings:"]];
}
}
This will open your application settings where you can find the settings to enable/disable local notification and other settings.
Hope this helps!
You can not request the system prompt again. You can detect a situation in which the access was denied and show an alert yourself or show the button that will open settings app to make the process of changing the setting easier for the user.

Call a function once user handles push notification registration alert

These codes will be called when a page loads.
UIUserNotificationType allNotificationTypes = (UIUserNotificationTypeSound | UIUserNotificationTypeAlert);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
Now I would like to present the next view controller as soon as the user handles the alert. Is it possible? Any help will be greatly appreciated.
Thanks.
Update
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(go)
name:UIApplicationDidBecomeActiveNotification
object:nil];
}
- (IBAction)buttonPressed:(id)sender
{
UIUserNotificationType allNotificationTypes = (UIUserNotificationTypeSound | UIUserNotificationTypeAlert);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
- (void)go
{
TutorialViewController *tvc = [[TutorialViewController alloc] init];
[self presentViewController:tvc animated:YES completion:nil];
}
This seems to work. I'm wondering if the code will be efficient?
It's a bit tricky, but it's possible. The alert for notification permissions is a system alert, which means your app resigns active when it's shown, and you get a application:didBecomeActive call when the user dismisses it.
So the basic technique is to set a flag in your app delegate when you're about to trigger the alert. In your application:didBecomeActive implementation, check the flag and perform whatever work you need to do.
This is not 100% foolproof, as the app might be resigning active for a different reason. You can mitigate some of this by also tracking whether the app went to the background after resigning active. You should also be sure that the alert will be shown when you ask for permissions. If the user has previously answered, no alert is shown.
When The App is brought into running state via Notifications..This method is fired
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
You can then retrieve the notification received from the launchOptions dictionary and open the appropriate screen.
Hope this helps.

Some time apple push notification not getting

I am developing an iOS application in iOS 8 .That has one module called message sending. This module developed with help of Apple push notification. My issue is some time we are not getting Push message to iOS device .The server successfully sent the message to APNS. Is it any APNS reliability issue?
i am using the following steps:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if([[UIApplication sharedApplication] respondsToSelector:#selector(registerUserNotificationSettings:)])
{
UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
return YES;
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
[application registerForRemoteNotifications];
}
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
}
APNs are not reliable, they are not 100% guaranteed to reach the client.
As of Apple's documentation, APNs are best effort, so many times they might not reach.
Via answer
Samraan is not wrong, Apple does not guarantee delivery, however it is pretty reliable in my experience. What I do notice from the code you have posted here is that you have an empty implementation for didReceiveRemoteNotification. When your app is active, and it receives a push notification, there is no system banner or alert shown. Instead the notification is delivered to the didReceiveRemoteNotification callback for your app to handle directly. If you have an empty definition of this function and you send a notification to that device, it may appear like the notification never arrived, but instead it was just hidden.
You could try adding a UIAlertView popup to this callback to find out if this is what is happening in your case.

IOS 8 device token not return when turn off notification setting

Im developing IOS push notification, and im trying to grab device token. I able to get device token when OS notification setting is turn on. When it turn off, my didRegisterForRemoteNotificationsWithDeviceToken is no longer called, and hence, i unable to get device token.
here is my code
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#ifdef __IPHONE_8_0
//Right, that is the point
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge
|UIUserNotificationTypeSound
|UIUserNotificationTypeAlert) categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
#else
//register to receive notifications
UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound;
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:myTypes];
#endif
return YES;
}
and i do also added
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler
However, when turn off OS notification setting,
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
will not be called. I've debug this for many hour and found no luck.
I've encounter the same problem.
Managed to solve it by enabling "Remote notifications" in project's Capabilities section (see screenshot below).
Background mode
My opinion on this issue:
If user has explicitly forbid notifications from your application and application has turned off "Remote notifications", you have no way to deliver notification to user. That's why there is no need to return token for your application.
If user has turned off notifications, but you enabled "Remote notifications", means that you still have opportunity to send silent notifications and iOS provides token for you.

Local Notification: No Permission to Play Sound Even After Registering fo UIUserNotificationTypeSound

"Attempting to schedule a local notification UIConcreteLocalNotification: with a sound but haven't received permission from the user to play sounds"
- (void)registerForRemoteNotifications
{
if ([[UIApplication sharedApplication] respondsToSelector:#selector(isRegisteredForRemoteNotifications)]) {
// iOS 8 Notifications
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert|UIUserNotificationTypeSound|UIUserNotificationTypeBadge) categories:nil]];
} else{
// iOS < 8 Notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIUserNotificationTypeAlert)];
}
}
//added for ios8
- (void)successfullyRegisteredUserNotificationSettings
{
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
I followed the guide of other users in stackoverflow to use registerUserNotificationSettings for ios8. After invoking the function, I wait for the callback in AppDelegate:
- (void)application:didRegisterUserNotificationSettings:
In the function, I call my successfullyRegisteredUserNotificationSettings method above to formally register.
Even after doing this, I still get the error. Can someone tell me why? Or has anyone encountered the same issue? How can this be solved?