How to show local notification always, even in foreground, using new (from iOS 10) notification framework UserNotifications https://developer.apple.com/reference/usernotifications?language=objc ?
#import <UserNotifications/UserNotifications.h>
#define SYSTEM_VERSION_GRATERTHAN_OR_EQUALTO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
//interface
#interface AppDelegate : UIResponder <UIApplicationDelegate,UNUserNotificationCenterDelegate>
#end
//implementation
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[self registerForRemoteNotifications];
return YES;
}
- (void)registerForRemoteNotifications {
if(SYSTEM_VERSION_GRATERTHAN_OR_EQUALTO(#"10.0")){
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
if(!error){
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
}];
}
else {
// Code for old versions
}
}
////...........Handling delegate methods for UserNotifications........
//Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
NSLog(#"User Info : %#",notification.request.content.userInfo);
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
}
//Called to let your app know which action was selected by the user for a given notification.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
NSLog(#"User Info : %#",response.notification.request.content.userInfo);
completionHandler();
}
May this will help you. :)
You can do this way.
//in Appdelegate
-(void)application:(UIApplication *)application didReceiveLocalNotification(UILocalNotification *)notification
{
dispatch_async(dispatch_get_main_queue(),^{
NSLog(#"alertbody ..%#", notification.alertBody);
NSLog(#"title ..%#", notification.alertTitle);
NSLog(#"action ..%#", notification.alertAction);
NSLog(#"userinfo..%#", notification.userInfo);
[[NSNotificationCenter defaultCenter]postNotificationName:#"NotificationReceived" object:nil userInfo:notification.userInfo];
});
}
//in present view controller
-(void)viewDidLoad
{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(notificationReceivedMethod:) name:#"NotificationReceived" object:nil];
}
-(void) viewWillDisappear:(BOOL)animated {
{
[[NSNotificationCenter defaultCenter]removeObserver:self name:#"NotificationReceived" object:nil];
}
-(void)notificationReceivedMethod
{
//create you custom popup or view
}
Related
#import "AppDelegate.h"
#import <UserNotifications/UserNotifications.h>
#import "MainViewController.h"
#interface AppDelegate () <UNUserNotificationCenterDelegate>
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
self.viewController = [[MainViewController alloc] init];
[self registerForNotification];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification*)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
// This method are not getting called
completionHandler(UNNotificationPresentationOptionAlert|UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound);
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(nonnull UNNotificationResponse* )response withCompletionHandler:(nonnull void (^)(void))completionHandler {
// This method are not getting called
NSDictionary *userInfo = response.notification.request.content.userInfo;
completionHandler();
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSLog(#"DEVICE_TOKEN :: %#", deviceToken);
const unsigned *tokenBytes = [deviceToken bytes];
NSString *hexToken = [NSString stringWithFormat:#"%08x%08x%08x%08x%08x%08x%08x%08x",
ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
NSString *apnDeviceToken = hexToken;
NSLog(#"APN_DEVICE_TOKEN :: %#", apnDeviceToken);
}
-(void)registerForNotification
{
if(#available(iOS 10.0, *))
{
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error)
{
if(!error)
{
dispatch_async(dispatch_get_main_queue(), ^ {
[[UIApplication sharedApplication] registerForRemoteNotifications]; // required to get the app to do anything at all about push notifications
NSLog(#"Push registration success." );
});
}
else
{
NSLog(#"Push registration FAILED" );
NSLog(#"ERROR: %# - %#", error.localizedFailureReason, error.localizedDescription );
NSLog(#"SUGGESTIONS: %# - %#", error.localizedRecoveryOptions, error.localizedRecoverySuggestion );
}
}];
}
}
#end
The didReceiveNotificationResponse and willPresentNotification did not trigger. I'm not able to handle Other APNS notification which is not related to one signal Cordova plugin SDK notification.
Is there any way that my app delegate methods for UserNotifications delegate methods will trigger in Cordova ios when one signal plugin used?
I suspect that due to swizzling the app delegate methods by one signal callbacks are not triggered in the original Appdelegate file.
Please help on this if we have any other way to get my app delegate
UserNotifications delegate methods trigger.
As one signal uses the static frameworks in Cordova there is no way to change the code inside the plugin.
This is the one signal plugin for Cordova github https://github.com/OneSignal/OneSignal-Cordova-SDK
In my app I enabled remote notifications,
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"10.0")){
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
if( !error ){
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
}];
}else{
UIUserNotificationType userNotificationTypes = (UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:userNotificationTypes categories:nil];
[application registerUserNotificationSettings:settings];
[application registerForRemoteNotifications];
}
And I implemented the delegate methods as follows,
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
NSLog(#"Failed!!");
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// Print message.
if (userInfo) {
NSLog(#"Message ID: %#", userInfo);
}
completionHandler(UIBackgroundFetchResultNoData);
}
But when the app is in foreground and receiving a notification, I got a UIAlertView with the notification title and message. I want to
//Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
NSLog(#"User Info : %#",notification.request.content.userInfo);
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionBadge);
}
//Called to let your app know which action was selected by the user for a given notification.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
NSLog(#"User Info : %#",response.notification.request.content.userInfo);
completionHandler();
}
I debugged on willPresentNotification: and after this triggers I got the alert. And I tested by removing this method as well. But still this alert is showing when receiving a notification.
How may I disable this alert view? I'm using 10.2 iOS in my iPhone
I don't think the UIAlertController comes from notifications. Are you sure you are not creating one elsewhere ?
Your notifications' implementation seems ok.
Can you search in your project and using breakpoints to see if any of your UIAlertControllers get hit?
Use UNNotificationPresentationOptionNone in the completionHandler
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
NSLog(#"User Info : %#",notification.request.content.userInfo);
completionHandler(UNNotificationPresentationOptionNone);
}
I am implementing Apple push notification in my native iOS app.
Push notification is implemented via FireBase.
It's working perfect in iOS 9 & earlier.
I am facing one issue in iOS 10. Push notification is working fine for in iOS 10 with other state but When app is in background, sound of my push notification is not playing.
For other state of app , it's all ok.
Only issue with background mode.
Below is my code for Implement push notification.
Insdie
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
Below is Registration code:
////////// FireBase////////////
// Register for remote notifications
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
// iOS 7.1 or earlier. Disable the deprecation warnings.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
UIRemoteNotificationType allNotificationTypes =
(UIRemoteNotificationTypeSound |
UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeBadge);
[application registerForRemoteNotificationTypes:allNotificationTypes];
#pragma clang diagnostic pop
} else {
// iOS 8 or later
// [START register_for_notifications]
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max) {
UIUserNotificationType allNotificationTypes =
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
} else {
// iOS 10 or later
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
if( !error ){
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
}];
[[FIRMessaging messaging] setRemoteMessageDelegate:self];
#endif
}
[[UIApplication sharedApplication] registerForRemoteNotifications];
// [END register_for_notifications]
}
[FIRApp configure];
// [END configure_firebase]
// Add observer for InstanceID token refresh callback.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(tokenRefreshNotification:)
name:kFIRInstanceIDTokenRefreshNotification object:nil];
Below are the delegate(s) for manage received notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
NSLog(#"Message ID: %#", userInfo[#"gcm.message_id"]);
NSLog(#"%#", userInfo);
[self manageAppAfterReceiveNotific: userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
NSDictionary *userInfo = response.notification.request.content.userInfo;
[self manageAppAfterReceiveNotific: userInfo];
}
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
completionHandler(UNNotificationPresentationOptionAlert);
}
- (void)applicationReceivedRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage {
NSLog(#"%#", [remoteMessage appData]);
[self manageAppAfterReceiveNotific: [remoteMessage appData]];
}
#endif
Below is my PayLoad :
{
aps = {
alert = {
body = "any text";
title = "New Notification";
};
badge = 1;
"content-available" = 1;
sound = default;
};
extra = "{\"childrenId\":\"48\",\"timestamp\":\"1479724388\"}";
"gcm.message_id" = "Message ID";
noteType = "CHECK_OUT";
}
According to firebase document, https://firebase.google.com/docs/cloud-messaging/http-server-ref, you should put "sound" filed into notification message, please refer Table 2a
For iOS 8 and 9, when the application is in the background, when a push notification is received, I am able to store the information it in the app. But for iOS 10, I cannot retrieve the information when the app is in the background. But only if I open/click on the notification, userNotification centerDidReceiveNotificationResponse is invoked.
For iOS 8 & 9, this works fine.
-(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
// iOS 10 will handle notifications through other methods
if( SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO( #"10.0" ) )
{
NSLog( #"iOS version >= 10. Let NotificationCenter handle this one." );
// set a member variable to tell the new delegate that this is background
return;
}
NSLog( #"HANDLE PUSH, didReceiveRemoteNotification: %#", userInfo );
// custom code to handle notification content
if( [UIApplication sharedApplication].applicationState == UIApplicationStateInactive )
{
NSLog( #"INACTIVE" );
completionHandler( UIBackgroundFetchResultNewData );
}
else if( [UIApplication sharedApplication].applicationState == UIApplicationStateBackground )
{
NSLog( #"BACKGROUND" );
completionHandler( UIBackgroundFetchResultNewData );
}
else
{
NSLog( #"FOREGROUND" );
completionHandler( UIBackgroundFetchResultNewData );
}
}
For iOS 10 the method is not invoked,
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
NSLog( #"Handle push from foreground" );
// custom code to handle push while app is in the foreground
NSLog(#"%#", notification.request.content.userInfo);
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)())completionHandler
{
NSLog( #"Handle push from background or closed" );
// if you set a member variable in didReceiveRemoteNotification, you will know if this is from closed or background
NSLog(#"%#", response.notification.request.content.userInfo);
}
I hope you have follow Below Steps.
Step 1 : Import "UserNotifications" framework.
#import <UserNotifications/UserNotifications.h>
Step 2 : And your AppDelegate confirming "UNUserNotificationCenterDelegate" delegate
#interface AppDelegate : UIResponder <UIApplicationDelegate,UNUserNotificationCenterDelegate>
Step 3 : For iOS10, You can ask for the permission like this
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
if(!error){
// Permission for notifications is granted. Do the other code
}
}];
Now I think the problem you are having in your code in Handling
delegate methods for UserNotifications.
//Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
NSLog(#"User Info : %#",notification.request.content.userInfo);
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
}
//Called to let your app know which action was selected by the user for a given notification.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
NSLog(#"User Info : %#",response.notification.request.content.userInfo);
completionHandler();
}
Your code is missing below line of codes
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
And
completionHandler();
In willPresentNotification and didReceiveNotificationResponse respectively.
I'm trying to be notified in background, I followed the documentation Firebase and Apple but I can´t solve my problem.
Problem: When I send a notification from the console Firebase I receive notification perfectly foreground, but sending the same notification from Firebase and my application is in background I do not receive any data, however if I open the application, the application shows me notification, but never in background. And the funny thing is that the next day I receive all notifications in the background with the closed application.
Device: iPhone 6 - v10.0.1
EDIT: My payload:
When I send a notification in Firebase, I receive this payload, I selected high priority in Firebase but I don´t receive any priority in the payload.
My code:
#define SYSTEM_VERSION_GRATERTHAN_OR_EQUALTO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#interface AppDelegate ()
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self registerForRemoteNotifications];
[FIRApp configure];
[self connectToFcm];
return YES;
}
- (void)registerForRemoteNotifications {
if(SYSTEM_VERSION_GRATERTHAN_OR_EQUALTO(#"10.0")){
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
if(!error){
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
}];
NSLog(#"Version >= 10");
}
else {
NSLog(#"version < 10");
// Code for old versions
}
}
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
NSLog(#"MODO 1: User Info: %#",notification.request.content.userInfo);
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
}
//Called to let your app know which action was selected by the user for a given notification.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
NSLog(#"MODO 2: User Info: %#",response.notification.request.content.userInfo);
completionHandler();
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
}
- (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);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
for (NSString *key in userInfo) {
NSLog(#"key value: %#", key);
if ([key isEqualToString:#"notification"]) {
NSString *body = [[userInfo valueForKeyPath:key] objectForKey:#"body"];
NSLog(#"message content: %#", body);
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:5];
notification.repeatInterval = NSDayCalendarUnit;
notification.alertBody = body;
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.soundName = UILocalNotificationDefaultSoundName;
notification.applicationIconBadgeNumber = 0;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
}
NSLog(#"Message ID: %#", userInfo[#"gcm.message_id"]);
if( [UIApplication sharedApplication].applicationState == UIApplicationStateInactive )
{
NSLog( #"INACTIVE" );
completionHandler( UIBackgroundFetchResultNewData );
}
else if( [UIApplication sharedApplication].applicationState == UIApplicationStateBackground )
{
NSLog( #"BACKGROUND" );
completionHandler( UIBackgroundFetchResultNewData );
}
else
{
NSLog( #"FOREGROUND" );
completionHandler( UIBackgroundFetchResultNewData );
}
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(#"enter in background");
}
- (void)connectToFcm {
[[FIRMessaging messaging] connectWithCompletion:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Unable to connect to FCM. %#", error);
} else {
NSLog(#"Connected to FCM.");
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"registeredToFCM"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}];
}