objective C FCM how to get remote message when app in background - objective-c

my code can get remote notification and remote message, the last problem is can not getting remote message when app in background ( just open app then got it)
When i push remote notification and app in background, it's seem notification message show like expect, click to this notification then it bring me to my app. I dont know why remote message does not have some behavior like that( I using postman and "https://fcm.googleapis.com/fcm/send" to send remote message)
. Plz someone help me
Here is my code
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Register for remote notifications
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
// iOS 7.1 or earlier. Disable the deprecation warnings.
UIRemoteNotificationType allNotificationTypes =
(UIRemoteNotificationTypeSound |
UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeBadge);
[application registerForRemoteNotificationTypes:allNotificationTypes];
} 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
UNAuthorizationOptions authOptions =
UNAuthorizationOptionAlert
| UNAuthorizationOptionSound
| UNAuthorizationOptionBadge;
[[UNUserNotificationCenter currentNotificationCenter]
requestAuthorizationWithOptions:authOptions
completionHandler:^(BOOL granted, NSError * _Nullable error) {
}
];
// For iOS 10 display notification (sent via APNS)
[[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
// For iOS 10 data message (sent via FCM)
[[FIRMessaging messaging] setRemoteMessageDelegate:self];
}
[[UIApplication sharedApplication] registerForRemoteNotifications];
// [END register_for_notifications]
}
// [START configure_firebase]
[FIRApp configure];
// [END configure_firebase]
// Add observer for InstanceID token refresh callback.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(tokenRefreshNotification:)
name:kFIRInstanceIDTokenRefreshNotification object:nil];
return YES;
}
// [START receive_message]
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// Print message ID.
NSLog(#"didReceiveRemoteNotification1 ID: %#", userInfo[#"gcm.message_id"]);
// Print full message.
NSLog(#"didReceiveRemoteNotification1 %#", userInfo);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// Print message ID.
NSLog(#"didReceiveRemoteNotification2 ID: %#", userInfo[#"gcm.message_id"]);
// Print full message.
NSLog(#"didReceiveRemoteNotification2 %#", userInfo);
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
// Print message ID.
NSDictionary *userInfo = notification.request.content.userInfo;
NSLog(#"willPresentNotification: %#", userInfo[#"gcm.message_id"]);
// Print full message.
NSLog(#"willPresentNotification %#", userInfo);
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)())completionHandler {
NSDictionary *userInfo = response.notification.request.content.userInfo;
NSLog(#"didReceiveNotificationResponse: %#", userInfo);
}
- (void)applicationReceivedRemoteMessage:(FIRMessagingRemoteMessage *)remoteMessage {
NSLog(#"%#", [remoteMessage appData]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert" message:[NSString stringWithFormat:#"%#", [remoteMessage appData]] delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Ok", nil];
[alert show];
}
- (void)tokenRefreshNotification:(NSNotification *)notification {
NSString *refreshedToken = [[FIRInstanceID instanceID] token];
NSLog(#"InstanceID token: %#", refreshedToken);
[self connectToFcm];
}
- (void)connectToFcm {
[[FIRMessaging messaging] connectWithCompletion:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Unable to connect to FCM. %#", error);
} else {
NSLog(#"Connected to FCM.");
}
}];
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(#"Unable to register for remote notifications: %#", error);
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSLog(#"APNs token retrieved: %#", deviceToken);
[[FIRMessaging messaging] setAPNSToken:deviceToken];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[self connectToFcm];
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[FIRMessaging messaging] disconnect];
NSLog(#"Disconnected from FCM");
}

For other people who face same problem.
Finally after a lot of searching, i found the solution, very simple, u need to follow the content of firebase app message to make it readable by push notification service. U can see here
and here
this is sample to make it show to device when in background mode :)
{
"condition": "'condition1' in topics && 'condition2' in topics",
"notification": {
"category": "notification_category",
"title_loc_key": "notification_title",
"body_loc_key": "notification_body",
"badge": 1
},
"data": {
"data_type": "notification_data_type",
"data_id": "111111",
"data_detail": "FOO",
"data_detail_body": "BAR"
}
}
Now everything work like expect, then the second job is just modify message content like whatever u want :)

Related

Push notification not received when App is in Background in iOS 11

I'm using UNUserNotificationCenter for sending push notifications in iOS.
I'm able to receive the notification when App is in foreground state. But when the App is in the background state, the notification is not received. Whenever the application will come to foreground state, only then will the notification be received.
For register Remote Notification:
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"10.0")) {
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error){
if( !error ){
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] registerForRemoteNotifications];
});
}
else{
NSLog( #"Push registration FAILED" );
NSLog( #"ERROR: %# - %#", error.localizedFailureReason, error.localizedDescription );
NSLog( #"SUGGESTIONS: %# - %#", error.localizedRecoveryOptions, error.localizedRecoverySuggestion );
}
}];
}
else {
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
when the app is in the foreground mode, this method is called:
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
But this method is not working in background mode.
I referred to some StackOverflow questions but wasn't able to solve the issue.
Is there anything to add in iOS version 11?
If its a remote notification, this method is called in the app delegate:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
//Handle notification here!
}

How to detect Remote notification in didFinishLaunchingWithOption application method in objective c?

when app in not in background mode ,inactive mode and app is completely closed. than how to detect is their any notification using application's delegate "didFinishLaunchingWithOption" method. i have searched a lot about it but not get anything. please help .
Thanks
Below methods is used for notifiaction
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (notification)
{
}
}
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *token = [[[[deviceToken description]
stringByReplacingOccurrencesOfString:#"<"withString:#""]
stringByReplacingOccurrencesOfString:#">" withString:#""]
stringByReplacingOccurrencesOfString: #" " withString: #""];
NSLog(#"Token:%#",token);
}
//app is forground this method will access
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
}
//need to on teh background fetch option in info plist
//app is background state this below mthod will call while notification receives
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(#"Background mode working%#",userInfo);
if([userInfo[#"aps"][#"content-available"] intValue]== 1) //it's the silent notification when recive preferences and text messages
{
}
}
//handling interactive notification
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(nonnull UILocalNotification *)notification completionHandler:(nonnull void (^)())completionHandler {
}
You can do this in the didFinishLaunchingWithOption method
let launchedFromRemoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] != nil
You can get Notification in the didFinishLaunchingWithOption in this way :
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification) {
NSLog(#"app recieved notification from remote%#",notification);
}else{
NSLog(#"app did not recieve notification");
}
}
Try this it may help you.
If the App was terminated and is starting again, you can detect the Remote Notification only if the App is being launched because the user tapped on the remote notification in the notifications tray.
You can detect it in the didFinishLaunchingWithOptions method
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSDictionary *notificationDict = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notificationDict) {
//Your App received a remote notification
}else{
//Your App did not receive a remote notification
}
}

Push Not Coming in Production

I am not getting push in production Mode . while it work fine in developer mode.Here is my code I am newer in iOS and i am first time implementation APN. Please help. I am stuck in lot of time.
if (iOSversion >=8) {
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[[UIApplication sharedApplication]registerForRemoteNotifications];
}
if ([UIApplication instancesRespondToSelector:#selector(registerUserNotificationSettings:)]){
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}
[[UIApplication sharedApplication] registerForRemoteNotifications];
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)tokenss
{
NSUInteger rntypes;
NSString *device=[[UIDevice currentDevice]systemVersion];
int ar=[device intValue];
if (ar>=8) {
rntypes = [[[UIApplication sharedApplication] currentUserNotificationSettings] types];
}
NSString *deviceToken =[self stringWithDeviceToken:tokenss];
NSLog(#"Device token: %#", deviceToken);
callBackToken =deviceToken;
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err
{
NSString *errorString = [NSString stringWithFormat: #"Error: %#", err];
NSLog(#"%#",errorString);
}
- (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"]){
}
}
Such problems are due to current Provisioning Profile does not contain APNS information, as the Provisioning Profile is created BEFORE creating the APNS certificate.
Therefore, to solve the problem, create a new Provisioning Profile & select the Provisioning Profile in Xcode will clear the error.
Also, when you add push, I believe you have updated the certificates in keychain too.

Detecting phone calls when the app is asleep

What i'm trying to do is an app that runs a code when a call is incoming. I know I cannot get any details of the caller and that is fine.
My issue so far is that it's only working when the app is in foreground.
This is my code:
#import <CoreTelephony/CoreTelephonyDefines.h>
#import <CoreTelephony/CTCallCenter.h>
#import <CoreTelephony/CTCall.h>
CTCallCenter *callCenter = [[CTCallCenter alloc] init];
[callCenter setCallEventHandler:^(CTCall *call) {
ONLog(#"Event handler called");
if ([call.callState isEqualToString: CTCallStateConnected]) {
ONLog(#"Connected");
} else if ([call.callState isEqualToString: CTCallStateDialing]) {
ONLog(#"Dialing");
} else if ([call.callState isEqualToString: CTCallStateDisconnected]) {
ONLog(#"Disconnected");
} else if ([call.callState isEqualToString: CTCallStateIncoming]) {
ONLog(#"Incomming");
}
}];
Can someone help me with making this run as a background task?
EDIT:
I used Richas' code like this:
__block UIBackgroundTaskIdentifier yourBackgroundTaskName;
yourBackgroundTaskName = [application beginBackgroundTaskWithExpirationHandler:^{
// CODE FOR EXPIRATION HANDLER BLOCK
[application endBackgroundTask: yourBackgroundTaskName];
yourBackgroundTaskName = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// DO YOUR STUFF HERE. START OF BACKGROUND TASK.
NSLog(#"Background time Remaining: %f",[[UIApplication sharedApplication] backgroundTimeRemaining]);
self.callCenter = [[CTCallCenter alloc] init];
[self.callCenter setCallEventHandler:^(CTCall *call) {
ONLog(#"Event handler called");
if ([call.callState isEqualToString: CTCallStateConnected]) {
ONLog(#"Connected");
} else if ([call.callState isEqualToString: CTCallStateDialing]) {
ONLog(#"Dialing");
} else if ([call.callState isEqualToString: CTCallStateDisconnected]) {
ONLog(#"Disconnected");
} else if ([call.callState isEqualToString: CTCallStateIncoming]) {
ONLog(#"Incomming");
}
}];
//WHEN YOU ARE DONE WITH YOUR TASK, TELL THAT TO SYSTEM
[application endBackgroundTask: yourBackgroundTaskName];
yourBackgroundTaskName = UIBackgroundTaskInvalid;
});
It only buys me 180 seconds of background running...
It's not working :) The call is not detected
You should check for following two methods for your problem:
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(NSString *)taskName expirationHandler:(void (^)(void))handler`
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void (^)(void))handler
You can implement any of them in applicationDidEnterBackground & that can buy you some time (5-10 minutes). Code might be something like following:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIBackgroundTaskIdentifier yourBackgroundTaskName;
yourBackgroundTaskName = [application beginBackgroundTaskWithExpirationHandler:^{
// CODE FOR EXPIRATION HANDLER BLOCK
[application endBackgroundTask: yourBackgroundTaskName];
yourBackgroundTaskName = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// DO YOUR STUFF HERE. START OF BACKGROUND TASK.
//WHEN YOU ARE DONE WITH YOUR TASK, TELL THAT TO SYSTEM
[application endBackgroundTask: yourBackgroundTaskName];
yourBackgroundTaskName = UIBackgroundTaskInvalid;
});
}
Hope, this should at least get you started.

NSUserNotification - How open the app when clicked

I'm using NSUserNotification to display notifications. This is working fine. The problem is that when you click on a notification:
The apps notifications are not removed from the notification center.
The app (when minimized) does not open.
Anyone familiar with the NSUserNotification who can offer some pointers?
notice.m
#import "Notice.h"
#implementation Notice
- (void) notify:(NSDictionary *)message {
NSLog(#"Notification - Show it");
NSUserNotification *notification = [[NSUserNotification alloc] init];
[notification setTitle:[message valueForKey:#"title"]];
[notification setInformativeText:[message valueForKey:#"content"]];
[notification setDeliveryDate:[NSDate dateWithTimeInterval:0 sinceDate:[NSDate date]]];
[notification setSoundName:NSUserNotificationDefaultSoundName];
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
[center scheduleNotification:notification];
}
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
{
NSLog(#"Notification - Clicked");
notification=nil;
[center removeDeliveredNotification: notification];
}
#pragma mark WebScripting Protocol
+ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector
{
if (selector == #selector(notify:))
return NO;
return YES;
}
+ (NSString*) webScriptNameForSelector:(SEL)selector
{
id result = nil;
if (selector == #selector(notify:)) {
result = #"notify";
}
return result;
}
// right now exclude all properties (eg keys)
+ (BOOL) isKeyExcludedFromWebScript:(const char*)name
{
return YES;
}
#end
Thank you
Just implement the NSUserNotificationCenterDelegate and define this method:
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
Example:
This is what I did in a "notifier" application.
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
{
NSRunAlertPanel([notification title], [notification informativeText], #"Ok", nil, nil);
}
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didDeliverNotification:(NSUserNotification *)notification
{
notifications=nil;
[tableView reloadData];
[center removeDeliveredNotification: notification];
}
When the notification is activated (click by the user) I just inform the user with a panel (I could use a hud window).In this case I immediately remove the delivered notification, but this is not what happens usually.The notification could stay there some time and be removed after 1/2 hours (it depends on the application that you are developing).