I use UILocalNotification in one app and in iOS 7 or earlier is working fine, but in iOS 8 didReceiveLocalNotification is not being called at all.
After some research I found out that in iOS 8 we have to use handleActionWithIdentifier instead, and so I tried it but also this void is not being called when LocalNotification run.
Here is my code:
I've got this code in didFinishLaunchingWithOptions and it works ok, first time I launched the app I've been asked permission to give notifications etc.
if ([UIApplication instancesRespondToSelector:#selector(registerUserNotificationSettings:)]){
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}
Then I got:
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
//register to receive notifications
[application registerForRemoteNotifications];
}
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification
completionHandler:(void(^)())completionHandler
{
NSLog(#"handleAction");
}
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
NSLog(#"didReceive");
}
When the localNotification run and I slide my finger on the message that appears on the screen nothing happens... logs are not called at all...
I also noticed that if the app is active and running, when the localNotification run, it get called the method didReceiveLocalNotification
Anyone know what am I doing wrong? Thanks for any help
add this to your didFinishLaunchingWithOptions:
if ([[UIApplication sharedApplication]respondsToSelector:#selector(isRegisteredForRemoteNotifications)])
{
// iOS 8 Notifications
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
else
{
// iOS < 8 Notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
}
You forgot to add this line:
[[UIApplication sharedApplication] registerForRemoteNotifications];
According to the Apple documentation of application:handleActionWithIdentifier:forLocalNotification:completionHandler::
Your implementation of this method should perform the action associated with the specified identifier and execute the block in the completionHandler parameter as soon as you are done. Failure to execute the completion handler block at the end of your implementation will cause your app to be terminated.
Your implementation above is missing the completion handler block.
To make it work, modify your application:handleActionWithIdentifier:forLocalNotification:completionHandler: to be as follows:
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void(^)())completionHandler
{
NSLog(#"handleAction");
if (completionHandler) {
completionHandler();
}
}
This method calle when the user taps a custom action in the alert for a remote or local notification’s.
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandle
{
//some action
}
When you slide finger on screen called this method
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
}
While I see you are handling the "forRemoteNotification:" case,
I don't see this being defined in your original block of code:
application:handleActionWithIdentifier:forLocalNotification:completionHandler:
Related
Usually, I set UIUserNotificationSettings in Appdelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//some codes
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert
| UIUserNotificationTypeBadge
| UIUserNotificationTypeSound
categories:nil];
[application registerUserNotificationSettings:settings];
[application registerForRemoteNotifications];
return YES;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(#"Register Remote Notifications error:{%#}",[error localizedDescription]);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(#"Receive remote notification : %#",userInfo);
}
but now I want to use it in a UIViewcontroller, such as there's a UIButton in a UIViewcontroller, when I click it, it will call this function, any ideas?
Try this one:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(#"Receive remote notification : %#",userInfo);
YourViewController *login=[storyboard instantiateViewControllerWithIdentifier:#"YourViewContollerIDName"];
MainNavigationViewController *mainNavigation=[storyboard instantiateViewControllerWithIdentifier:#"MainNavigationViewController"];
[mainNavigation setViewControllers:#[login] animated:NO];
self.window.rootViewController=mainNavigation;
}
OR
Appdelegate.m
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(#"Receive remote notification : %#",userInfo);
[[NSNotificationCenter defaultCenter]postNotificationName:#"Notification" object:self userInfo:userInfo];
}
YourViewContoller.m
-(void)viewWillAppear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:)
name:#"Notification"
object:nil];
}
- (void)receiveNotification:(NSNotification *) notification{
if ([[notification name] isEqualToString:#"Notification"]) {
//call your function
}
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
You do basically the same thing as a reaction to pressing the button, just use UIApplication.shared instead of using application provided by AppDelegate, so e.g. (Swift syntax):
UIApplication.shared.registerForRemoteNotifications()
Moreover, I would recommend implementing your own custom UserNotificationManager :
class UserNotificationManager: NSObject, UNUserNotificationCenterDelegate { ... }
I hope below code helps you,
create a new class called UIUserNotifications, and add the following code to the .h file
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface UIUserNotificationsHandler : NSObject
+ (void)registerUserNotifications;
#end
and following code to the .m file. Then call that function from your ViewController class
#import "UIUserNotificationsHandler.h"
#implementation UIUserNotificationsHandler
+ (void)registerUserNotifications{
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert
| UIUserNotificationTypeBadge
| UIUserNotificationTypeSound
categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
#end
In my app, I have the following process for APNs:
Register the device in didFinishLaunchingWithOptions;
Receive the token with didRegisterForRemoteNotificationsWithDeviceToken;
Send it to my Notification server;
My server sends the notification;
PROBLEM: My device don't receive it (didReceiveRemoteNotification never called on Debug);
Already checked the App Id on the server and certificate.
Anyone can point what am I doing wrong?
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Checking if app is running iOS 8
if ([application respondsToSelector:#selector(registerForRemoteNotifications)]) {
// Register device for iOS8
UIUserNotificationSettings *notificationSettings = [UIUserNotificationSettings
settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge |
UIUserNotificationTypeSound categories:nil];
[application registerUserNotificationSettings:notificationSettings];
[application registerForRemoteNotifications];
} else {
// Register device for iOS7
[application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge];
}
//...
return YES;
}
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSLog(#"Registration successful, bundle identifier: %#, device token: %#",
[NSBundle.mainBundle bundleIdentifier], deviceToken);
// Receive the token and send it to my Server
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSLog(#"Error in registration. Error: %#", err);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// Handle notification
}
Lefteris and Rajat are right, my problem was the wrong certificate for the enviroment.
I am using following code to handle push notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
if(application.applicationState == UIApplicationStateInactive)
{
//************************************************************
// I only want this called when user click on notification.
//************************************************************
NSLog(#"Inactive");
if ([[userInfo valueForKey:#"noty_type"] isEqualToString:#"web"])
{
if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:[userInfo valueForKey:#"url"]]])
{
dispatch_async(dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[userInfo valueForKey:#"url"]]];
});
}
}
}
if((application.applicationState == UIApplicationStateActive)
{
// I am useing local notification when app in Forground
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.soundName = #"Default";
localNotification.alertBody = [userInfo valueForKey:#"msg"];
localNotification.userInfo = userInfo;
[[UIApplication sharedApplication] scheduleLocalNotification: localNotification];
}
}
This code open the url in safari browser. this code work fine When my app in background and notification come and I click on notification check the applicationState and open the url with [[UIApplication sharedApplication] openURL.
now the scenario that generate the problem.
I open my app .
and Down the notification UI
now Send the notification from server
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler method get called.
Now I get the ApplicationState == UIApplicationStateInactive .
"It open into the safari browser without any user interaction".
I only want this called when user click on notification.
So, How can I handle this condition ?
Try this.
if (application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground)
{
// do something when app open with notification
}
You have to know why the app is inactive. The two possibilities are that the app was in the background and the user is bringing it to the foreground (by tapping on the notification banner), or something like the notification center was pulled down or the user got a system alert.
To tell the difference, keep track of when the user enters the background. Just set a boolean in the applicationDidEnterBackground: delegate method, and clear it when the app is resigning active.
static BOOL didEnterBackground;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Launching the app is kind of like coming from background.
didEnterEnterBackground = YES;
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
didEnterBackground = NO;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
didEnterBackground = YES;
}
Now you can check the variable didEnterBackground to determine how the app got to the inactive state when you're handling a notification.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
if (application.applicationState == UIApplicationStateInactive) {
if (didEnterBackground) {
// The user tapped the notification
}
else {
// The app was inactive, but not in the background.
// Ignore notification, or do whatever the app does
// when receiving a notification while active.
}
}
}
Hope this help you
-(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
}//iOS below 9
- (void)application:(UIApplication *)application
handleActionWithIdentifier:(nullable NSString *)identifier
forLocalNotification:(nonnull UILocalNotification *)notification
completionHandler:(nonnull void (^)())completionHandler {
// handling local and interactive notifcation
} // iOS 9 and above
Which is used to trigger the notification in background state.
I know this question already asked previously and also have some solution for it,i tried all the solution available ,but nothing is working for me. Code is working perfectly on my side but when i submit the App store they reject it (till now i got 3 rejections from App store).
I try the the code from the following link:-
why didRegisterForRemoteNotificationsWithDeviceToken is not called
Get Device Token in iOS 8
https://developer.apple.com/library/ios/technotes/tn2265/_index.html
I also check provisional profile and certificates they all are fine.
Anyone please help
Push notification registration process has been changed in iOS 8, Make sure you have added this
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
I have used this way. I didn't get any issue from app store.
#ifdef __IPHONE_8_0
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
//register to receive notifications
[application registerForRemoteNotifications];
}
#endif
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier
forRemoteNotification:(NSDictionary *)notification completionHandler:(void(^)())completionHandler
{
NSLog(#"Received push notification: %#, identifier: %#", notification, identifier); // iOS 8 s
completionHandler();
}
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken
{
NSString *newToken = [devToken description];
newToken = [newToken stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"<>"]];
newToken = [newToken stringByReplacingOccurrencesOfString:#" " withString:#""];
NSLog(#"NotificationToken: %#",newToken);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
NSLog(#"Error while registering for notifications: %#", error);
}
Just wanted a confirmation. Does the app ask for user permission if i have used silent push notification service like it use to ask when push notification was used. Any help would be appreciated
No. It's silent, meaning it works in the background, without user confirmation at the time of the notification.
At app install it asks for confirmation like a normal push notification.
For silent push you have to set JSON like this (php file),
$body['aps'] = array(
'sound' => '',
'content-available' => 1
);
don't send alert and badge.
In xcode file select target -> capabilities and enable background modes and tick remote notification
in appdelegate.m file just use this message to receive silent push
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler
{
//Success this method will automatically call when device receives push notification
handler(UIBackgroundFetchResultNewData);
}
// eg code to register for apps
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)]) {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIRemoteNotificationTypeBadge
|UIRemoteNotificationTypeSound
|UIRemoteNotificationTypeAlert) categories:nil];
[application registerUserNotificationSettings:settings];
} else {
UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
[application registerForRemoteNotificationTypes:myTypes];
}
return YES;
}
#ifdef __IPHONE_8_0
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
//register to receive notifications
[application registerForRemoteNotifications];
}
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler
{
//handle the actions
if ([identifier isEqualToString:#"declineAction"]){
}
else if ([identifier isEqualToString:#"answerAction"]){
}
}
#endif
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
NSLog(#"My token is: %#", deviceToken);
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(#"Failed to get token, error: %#", error);
}