I have integrated push notification through GCM everything is working fine. But I am not getting notification message and sound. And the function didReceiveNotification: called in app delegate. And also not getting in background state.
Before making any comment or downvote consider following things.
I assume you have configured App Identifier in Developer portal, if not visit Apple Developer center
You have generated required provisional Profile & Certificate from Apple Developer Portal. If not visit App Distribution Guide
Make sure you have configured your bundle identifier correctly as defined in Apple Developer portal.
Following answer guides to configure APNS using your custom backend to send Push Notifications not for FireBase/GCM. To configure it using Firebase or GCM(As Firebase Cloud Messaging (FCM) is the new version of GCM) follow Google documentation
If all the above things are configured correctly then follow below steps:
Step 1: Register for APNS with Appropriate settings in didFinishLaunchingWithOptions inside AppDelegate file
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let notificationTypes: UIUserNotificationType = [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound]
let pushNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: nil)
application.registerUserNotificationSettings(pushNotificationSettings)
application.registerForRemoteNotifications()
return true
}
Step 2: Add delegate methods to handle success or failure for APNS registration by adding following delegate methods
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
// Convert binary Device Token to a String (and remove the <,> and white space charaters).
var deviceTokenStr = deviceToken.description.stringByReplacingOccurrencesOfString(">", withString: "", options: nil, range: nil)
deviceTokenStr = deviceTokenStr.stringByReplacingOccurrencesOfString("<", withString: "", options: nil, range: nil)
deviceTokenStr = deviceTokenStr.stringByReplacingOccurrencesOfString(" ", withString: "", options: nil, range: nil)
print(deviceTokenStr);
// *** Store device token in your backend server to send Push Notification ***
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
print(error)
}
Step 3: Now you have configured your APNS on device end, You can fire Push Notification from your server/backend, When Push Notification is received following method will be called when your app is in Foreground. Implement it into AppDelegate.
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
print(userInfo)
}
To handle Push Notification while your application is in background (but not killed by removing from multitask) you need to take care of following things.
Make sure you have enabled Background Modes in Project Navigation->Targets->Capabilities->Turn on Background Modes and select Remote Notifications.
Now implement following method to handle Push Notification while in background. Make sure you handle UIBackgroundFetchResult properly.
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
}
Note: If func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) method is implemented func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) method will not be called.
Read more about APNS in Apple Documentation.
Usually, iOS apps can receive push notifications via APNS not GCM and could not get any data when app is in background state. If iOS app gets push notification via APNS and it is in background state, the push notifications just shown in notification center & top of the screen with app's icon. If you see the notification, there's no problem with the server.
And there's no data arrived when app is in the background state, you should make your server api for the notifications data when the app is back on foreground state.
Related
I'm developing an Swift iOS 14 app that send and recieves push notifications from Firebase Cloud Messaging.
From FCM I send a message with a payload that must be treated by the app, updating an internal SQLite database with the payload data for later, show items in a view.
When the app is in Foreground, I recieved the notification in the didReceiveRemoteNotification method and update the database but when the app is in Background or killed, the notification is recieved but no one method is called to handle the payload and update de database.
I've read many topics about this problem but in none have I come to find a solution.
At the moment I don't want to use an external database to insert the data, and later read the external database, but if there is no other options i will change the app (the reason is that i don't want to store any information out of the user application).
My AppDelegate.swift is the following:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//Firebase Auth + APNs
FirebaseApp.configure()
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
application.registerForRemoteNotifications()
Messaging.messaging().delegate = self
return true
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
UserDefaults.standard.set(fcmToken, forKey: UserConstants.MESSAGING_TOKEN)
let dataDict:[String: String] = ["token": fcmToken]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
if(userInfo["name"] != nil) {
ContactsService.sharedInstance.addAlert(phoneNumber: userInfo["phone"] as! String, name: userInfo["name"] as! String, isLocalized: Bool(userInfo["isLocalized"] as? String), longitude: (userInfo["longitude"] as! NSString).doubleValue, latitude: (userInfo["latitude"] as! NSString).doubleValue)
}
}
Can someone help me, telling me if it's possible to do in that way or it's necessary to store the data externally to later retrieve it?
Thank you!
There are two types of push notifications, alert notifications and background notifications. Alert notifications allow you to deliver visible alerts that can be interacted with in ways that your app can customize.Background notifications allow your application to fetch data from the background, upon receiving push notifications. Background notification should be used to keep your application up to date, even if the application isn't running. Also as of ios 10(and above)instead of using the didReceiveRemoteNotification method you can use didReceive method for handling the alert notifications.
Now coming back to your question in case of the alert notification the didReceive/didReceiveRemoteNotification method is called when the application is in the foreground or when the user taps on the application. Since, you want to update the database you can use the background notifications instead of the alert notification as it will automatically raise your application even when it is in background and will also call the didReceiveRemoteNotification:fetchCompletionHandler. while sending a background push notification make sure you :
Edit Info.plist and check the "Enable Background Modes" and "Remote notifications" check boxes.
Add "content-available":1 to your push notification payload, otherwise the app won't be woken if it's in the background
The notification’s POST request should contain the apns-push-type header field with a value of background, and the apns-priority field with a value of 5.
For more info please refer :
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app
I am currently developing and iOS app using Swift, which I am new to, and the code generated from AWS Mobile Hub, with AWS SNS to register devices and send notifications.
On my class AWSMobileClient I have the following code:
func didFinishLaunching(_ application: UIApplication, withOptions launchOptions: [AnyHashable: Any]?) -> Bool {
print("didFinishLaunching:")
// Register the sign in provider instances with their unique identifier
AWSSignInProviderFactory.sharedInstance().register(signInProvider: AWSFacebookSignInProvider.sharedInstance(), forKey: AWSFacebookSignInProviderKey)
var didFinishLaunching: Bool = AWSIdentityManager.default().interceptApplication(application, didFinishLaunchingWithOptions: launchOptions)
didFinishLaunching = didFinishLaunching && AWSPushManager(forKey: ServiceKey).interceptApplication(application, didFinishLaunchingWithOptions: launchOptions)
if (!isInitialized) {
AWSIdentityManager.default().resumeSession(completionHandler: { (result: Any?, error: Error?) in
print("Result: \(result) \n Error:\(error)")
}) // If you get an EXC_BAD_ACCESS here in iOS Simulator, then do Simulator -> "Reset Content and Settings..."
// This will clear bad auth tokens stored by other apps with the same bundle ID.
isInitialized = true
}
return didFinishLaunching
}
Which is called normally.
On my AppDelegate, I have the following:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
AWSMobileClient.sharedInstance.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
NotificationCenter.default.post(name: Notification.Name(rawValue: AWSMobileClient.remoteNotificationKey), object: deviceToken)
print("###--- DID REGISTER FOR REMOTE NOTIFICATION ---###")
}
Which is also called.
However, when I try sending a notification using AWS SNS, my function:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("###--- DID RECEIVE REMOTE NOTIFICATION ---###")
AWSMobileClient.sharedInstance.application(application, didReceiveRemoteNotification: userInfo , fetchCompletionHandler: completionHandler)
// This is where you intercept push notifications.
if (application.applicationState == .active) {
UIAlertView.init(title: "Notification Received", message: userInfo.description, delegate: nil, cancelButtonTitle: "OK").show()
}
}
Is never called.
Looking for a solution I read that since iOS 10 there are some chances that need to be made to deal with push notification, but I'm not sure about the correct ways.
How should I implement the code to receive the notifications?
for testing I use OneSignal service for send push notification on my device and I handle it in AppDelegate in this way:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
OneSignal.initWithLaunchOptions(launchOptions, appId: “[app ID]”)//this method I register device on apple server
return true
}
func application(application: UIApplication,
didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void){
print(“ARRIVED")
handleNotificationContent()// it’s not important for my question
}
My problem is that when I receive a notification and the app is in foreground , alert shows automatically and I don’t want to show it.
How do I solve this problem?
This code worked for me.
This is applicable for Swift 2.2 and Xcode 7.3.1
//Initialize One Signal using this code
OneSignal.initWithLaunchOptions(launchOptions, appId: oneSignalId, handleNotificationReceived: { (notification) in
//Put your business logic here like adding an alert controller or posting an NSNotification.
}, handleNotificationAction: { (nil) in
// This block gets called when the user reacts to a notification received
}, settings: [kOSSettingsKeyAutoPrompt : false, kOSSettingsKeyInAppAlerts: false])
//set kOSSettingsKeyAutoPrompt to false
You need to set the kOSSettingsKeyInFocusDisplayOption to None in initWithLaunchOptions, to disable the automatic display of inapp alerts.
OneSignal Api Reference
I have a Swift 2 iOS8+ app where I need to make a request to fetch JSON data when my app receives a push notification.
When the user clicks on the notification the app will go and fetch the data but I really need the data to be fetched as soon as the notification is received. This looks to be possible, is this the case?
I've implemented:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)){
and checking the launch options in:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
I've also enabled:
background fetch
remote notifications
None of this seems to help. If this is possible I'd be grateful for any pointers/tutorials on this.
As of iOS 9, instead of a normal push, you can use silent push notifications. When your app receives a silent push, the user is not notified, but your app can perform actions based on this notification. Then, when your background actions is finished, you create a local notification for the user.
Check out this tutorial for info on how to use silent notifications:
https://www.raywenderlich.com/123862/push-notifications-tutorial
I'm writing a Swift app with CloudKit. When a record is modified in CloudKit by a device, I want the corresponding records to be updated in the local storage of the other devices without displaying a push notification.
Do I need to call registerUserNotificationSettings in didFinishLaunchingWithOptions (meaning that the user has to accept the notifications for my app) even if I don't plan to display any push notification?
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: .Alert, categories: nil))
In this case you do not need to call registerUserNotificationSettings.
You need to add the Info.plist setting "Required background mode" (UIBackgroundModes), "App downloads content in response to push notifications" (remote-notification). And also call registerForRemoteNotifications. Finally, set notificationInfo.shouldSendContentAvailable = YES; on your subscription.
Now since your app is being run to respond to all notifications you need to be careful to handle the case where a notification is missed, you can use airplane mode to test that, only the last is delivered.
Note, once you have created your subscription from any device, application:didReceiveRemoteNotification:fetchCompletionHandler: will be called on all devices that are using the same iCloud account and have the app installed.
Yes you do need to call registerUserNotificationSettings even all you need is background remote notification. So user will be prompt for notifications permission. It makes no sense as users will not be seeing the notifications but that's how it is.
I use this to set it up:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let settings = UIUserNotificationSettings(forTypes: .None , categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
}
Make sure when you call CloudKit saveSubscription you provide shouldSendContentAvailable = true. The following code is for subscription for a custom zone:
let subscription = CKSubscription(zoneID:zoneID, options: CKSubscriptionOptions(rawValue: 0))
let notificationInfo = CKNotificationInfo()
notificationInfo.shouldSendContentAvailable = true
subscription.notificationInfo = notificationInfo
CKContainer.defaultContainer().privateCloudDatabase.saveSubscription(subscription) { subscription, error in
}
You also need to enable Background Modes capability under Xcode for your project, and tick the box Remote Notifications.
User can go to Settings app to disable notifications for your app. But you will still receive remote notification trigger by CloudKit server.
Implement the following functions in your AppDelegate to receive remote notifications:
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {}