Push notification when app is terminated - ios

My app works fine with push notifications if the app was in the background and/or if the app is in the foreground.
The problem I have is if the app is terminated (which I force by double-click on the home button, find the app, and swipe up).
I am using ios 9 and swift 2.
In app delegate, didFinishLaunchingWithOptions, I do:
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
Then:
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
application.registerForRemoteNotifications()
}
Followed by didRegisterForRemoteNotificationsWithDeviceToken & didFailToRegisterForRemoteNotificationsWithError.
Then, I am using the relatively new method:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {...}
According to the documentation and this link, as oppose to the old version of didReceiveRemoteNotification, this method is called if the app was terminated (as oppose to calling will/did finishLaunchingWithOptions).
However, if there was a push (which was received - I can see it on the screen) and I launch the app after it has been terminated, this method does not seem to be called as the code that handles the push (simply post a notification so it is picked up by the respective ViewController) does not get called.
What am I missing? Is there an additional check I need to do in didFinishLaunchingWithOptions? Somewhere else?

Managed to solve the problem of intercepting a Remote Push when the app is terminated for ios 9.1 with the following but it failed on 9.2 (random failure?):
Register for remote:
if #available(iOS 9, *) {
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
// UIApplication.sharedApplication().registerUserNotificationSettings(settings)
//
// UIApplication.sharedApplication().registerForRemoteNotifications()
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
} else if #available(iOS 8.0, *){
register for 8...
} else { //ios 7
register for 7...
}
if let _ = launchOptions {
if let _ = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary {
handleRemotePush()
} else if let _ = launchOptions?[UIApplicationLaunchOptionsLocalNotificationKey] as? UILocalNotification {
handleLocalNots()
} else {
handleElse()
}
}

Related

Sending a push notification to iOS through a CLI function

I am attempting to use a CLI function to send a push notification to both android and iOS devices. When I use the iOS version, no notification is received when sent from my function. However, when I send them from the Firebase console, it will receive the notification but only while the application is open. I am thinking I am missing either one or more crucial steps in setup or my function does not have all the needed data in the payload.
My function is sending as follows:
return Promise.all([token]).then(result=>{
const payload = {
notification: {
title : likename + " liked your post!",
"priority" : "high"
}
};
console.log(token);
return admin.messaging().sendToDevice(token,payload);
});
I have my iOS application set up with a certificate and have implemented my APP delegate as follows:
import UIKit
import Flutter
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Any help is greatly appreciated and please let me know if you need additional information.
After hours of reflection, I realized I had only implemented code to respond to the onLaunch or onResume versions. I had to implement those methods to my code and now have success.

How to handle Flutter FCM push notification when app in foreground for iOS?

I'm using local notification when app in foreground, on iOS still cannot get notification when app in foreground but on Android it works perfectly.
The problem is how to handle push notification when app in foreground for iOS ?
This my AppDelegate.swift :
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
FirebaseApp.configure()
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
I assume you're using the flutter_local_notifications plugin for local notifications and firebase_messaging for push notifications. As of right now, these two plugins do not work together. This is documented in the readme of the first plugin, and the issue is being tracked on both plugins. You'll just have to wait for the pull request on firebase_messaging to be merged.
See this issue for more details.

Payload data (Push notification FCM) coming nil when directly open app from app Icon not from notification tap

I am getting notification from FCM with data. When app is in foreground everything is working fine.When I closed(killed) the app and got notification, by tap on notification than also I am getting data. My problem is when I closed the app and get notification, Instead of tapping notification I am opening the app directly from app icon. I am not getting any data in launchOptions in didFinishLaunchingWithOptions function.
Here is my code to take data when app is launching from app Icon:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary {
self.handleNotification(remoteNotification as [NSObject : AnyObject])
}
FIRApp.configure()
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
// Add observer for InstanceID token refresh callback.
NSNotificationCenter
.defaultCenter()
.addObserver(self, selector: #selector(AppDelegate.tokenRefreshNotificaiton),
name: kFIRInstanceIDTokenRefreshNotification, object: nil)
return true
}
I am getting launchOptions always as nil, although there is notification having data.
I am using swift2 and Xcode7. Please suggest me on this why my launchOptions is coming nil?
I searched in google There its saying that if I will open app using app icon launchOption will come nil only.

Parse.com register for Push Notifications

I'm trying to add push notifications to my iOS app using Parse.com push notification service, but I'm running into problems with some of my devices not receiving notifications.
Current code
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
Parse.setApplicationId("*****", clientKey: "*****")
// Register for Push Notitications
if application.applicationState != UIApplicationState.Background {
// Track an app open here if we launch with a push, unless
// "content_available" was used to trigger a background push (introduced in iOS 7).
// In that case, we skip tracking here to avoid double counting the app-open.
let preBackgroundPush = !application.respondsToSelector("backgroundRefreshStatus")
let oldPushHandlerOnly = !self.respondsToSelector("application:didReceiveRemoteNotification:fetchCompletionHandler:")
var pushPayload = false
if let options = launchOptions {
pushPayload = options[UIApplicationLaunchOptionsRemoteNotificationKey] != nil
}
if (preBackgroundPush || oldPushHandlerOnly || pushPayload) {
PFAnalytics.trackAppOpenedWithLaunchOptions(launchOptions)
}
}
if application.respondsToSelector("registerUserNotificationSettings:") {
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
}else {
let types : UIRemoteNotificationType = [.Badge, .Alert, .Sound]
application.registerForRemoteNotificationTypes(types)
}
return true
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
// Store the deviceToken in the current Installation and save it to Parse
let installation = PFInstallation.currentInstallation()
installation.setDeviceTokenFromData(deviceToken)
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
if error.code == 3010 {
print("Push notifications are not supported in the iOS Simulator.")
} else {
print("application:didFailToRegisterForRemoteNotificationsWithError: %#", error)
}
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
if application.applicationState == UIApplicationState.Inactive {
PFAnalytics.trackAppOpenedWithRemoteNotificationPayload(userInfo)
}
}
This seems to work on some devices (tested it on coworker's iPhone 5 - worked, tested on my boss' iPhone 6 - didn't work)
The code I currently use also gives me 2 warnings, which is (what I suspect to be) the cause of push notifications not working on every iDevice.
Warning 1:
/Users/ds/code/rp-iOS/rp/AppDelegate.swift:43:25: 'UIRemoteNotificationType' was deprecated in iOS 8.0: Use UIUserNotificationType for user notifications and registerForRemoteNotifications for receiving remote notifications instead.
Line 43:
let types : UIRemoteNotificationType = [.Badge, .Alert, .Sound]
Warning 2:
/Users/ds/code/rp-iOS/rp/AppDelegate.swift:44:25: 'registerForRemoteNotificationTypes' was deprecated in iOS 8.0: Please use registerForRemoteNotifications and registerUserNotificationSettings: instead
Line 44:
application.registerForRemoteNotificationTypes(types)
Now I'm confused about these warnings because I copied the code from the Parse.com documentation - so what am I doing wrong? It seems like this else clause provides backwards compatibility for devices that run older versions of iOS.
In my Parse.com Push console, I also get some errors:
Any help would be greatly appreciated.
In didRegisterForRemoteNotificationsWithDeviceToken try to add this line of code.
installation.saveInBackground()
To get rid of the warnings I suggest using this code (I've put that in static function for convenience and ability to reuse)
static func askForPushNotifications(){
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
}

How to set up push notifications in Swift

I am trying to set up a push notification system for my application. I have a server and a developer license to set up the push notification service.
I am currently running my app in Swift. I would like to be able to send the notifications remotely from my server. How can I do this?
Swift 2:
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
While the answer is given well to handle push notification, still I believe to share integrated complete case at once to ease:
To Register Application for APNS, (Include the following code in didFinishLaunchingWithOptions method inside AppDelegate.swift)
IOS 9
var settings : UIUserNotificationSettings = UIUserNotificationSettings(forTypes:UIUserNotificationType.Alert|UIUserNotificationType.Sound, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
After IOS 10
Introduced UserNotifications framework:
Import the UserNotifications framework and add the UNUserNotificationCenterDelegate in AppDelegate.swift
To Register Application for APNS
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// If granted comes true you can enabled features based on authorization.
guard granted else { return }
application.registerForRemoteNotifications()
}
This will call following delegate method
func application(application: UIApplication,didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
//send this device token to server
}
//Called if unable to register for APNS.
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
println(error)
}
On Receiving notification following delegate will call:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
println("Recived: \(userInfo)")
//Parsing userinfo:
var temp : NSDictionary = userInfo
if let info = userInfo["aps"] as? Dictionary<String, AnyObject>
{
var alertMsg = info["alert"] as! String
var alert: UIAlertView!
alert = UIAlertView(title: "", message: alertMsg, delegate: nil, cancelButtonTitle: "OK")
alert.show()
}
}
To be identify the permission given we can use:
UNUserNotificationCenter.current().getNotificationSettings(){ (setttings) in
switch setttings.soundSetting{
case .enabled:
print("enabled sound")
case .disabled:
print("not allowed notifications")
case .notSupported:
print("something went wrong here")
}
}
So the checklist of APNS:
Create AppId allowed with Push Notification
Create SSL certificate with valid certificate and app id
Create Provisioning profile with same certificate and make sure to add device in case of sandboxing(development provisioning)
Note: That will be good if Create Provisioning profile after SSL Certificate.
With Code:
Register app for push notification
Handle didRegisterForRemoteNotificationsWithDeviceToken method
Set targets> Capability> background modes> Remote Notification
Handle didReceiveRemoteNotification
To register to receive push notifications via Apple Push Service you have to call a registerForRemoteNotifications() method of UIApplication.
If registration succeeds, the app calls your app delegate object’s application:didRegisterForRemoteNotificationsWithDeviceToken: method and passes it a device token.
You should pass this token along to the server you use to generate push notifications for the device. If registration fails, the app calls its app delegate’s application:didFailToRegisterForRemoteNotificationsWithError: method instead.
Have a look into Local and Push Notification Programming Guide.
registerForRemoteNotification() has been removed from ios8.
So you should use UIUserNotification
CODE EXAMPLE:
var type = UIUserNotificationType.Badge | UIUserNotificationType.Alert | UIUserNotificationType.Sound;
var setting = UIUserNotificationSettings(forTypes: type, categories: nil);
UIApplication.sharedApplication().registerUserNotificationSettings(setting);
UIApplication.sharedApplication().registerForRemoteNotifications();
Hope this will help you.
To support ios 8 and before, use this:
// Register for Push Notitications, if running iOS 8
if application.respondsToSelector("registerUserNotificationSettings:") {
let types:UIUserNotificationType = (.Alert | .Badge | .Sound)
let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
} else {
// Register for Push Notifications before iOS 8
application.registerForRemoteNotificationTypes(.Alert | .Badge | .Sound)
}
Swift 4
I think this is the correct way for setup in iOS 8 and above.
Turn on Push Notifications in the Capabilities tab
Import UserNotifications
import UserNotifications
Modify didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if let notification = launchOptions?[.remoteNotification] as? [String: AnyObject] {
// If your app wasn’t running and the user launches it by tapping the push notification, the push notification is passed to your app in the launchOptions
let aps = notification["aps"] as! [String: AnyObject]
UIApplication.shared.applicationIconBadgeNumber = 0
}
registerForPushNotifications()
return true
}
It’s extremely important to call registerUserNotificationSettings(_:) every time the app launches. This is because the user can, at any time, go into the Settings app and change the notification permissions. application(_:didRegisterUserNotificationSettings:) will always provide you with what permissions the user currently has allowed for your app.
Copy paste this AppDelegate extension
// Push Notificaion
extension AppDelegate {
func registerForPushNotifications() {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
[weak self] (granted, error) in
print("Permission granted: \(granted)")
guard granted else {
print("Please enable \"Notifications\" from App Settings.")
self?.showPermissionAlert()
return
}
self?.getNotificationSettings()
}
} else {
let settings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil)
UIApplication.shared.registerUserNotificationSettings(settings)
UIApplication.shared.registerForRemoteNotifications()
}
}
#available(iOS 10.0, *)
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
print("Notification settings: \(settings)")
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { data -> String in
return String(format: "%02.2hhx", data)
}
let token = tokenParts.joined()
print("Device Token: \(token)")
//UserDefaults.standard.set(token, forKey: DEVICE_TOKEN)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register: \(error)")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
// If your app was running and in the foreground
// Or
// If your app was running or suspended in the background and the user brings it to the foreground by tapping the push notification
print("didReceiveRemoteNotification /(userInfo)")
guard let dict = userInfo["aps"] as? [String: Any], let msg = dict ["alert"] as? String else {
print("Notification Parsing Error")
return
}
}
func showPermissionAlert() {
let alert = UIAlertController(title: "WARNING", message: "Please enable access to Notifications in the Settings app.", preferredStyle: .alert)
let settingsAction = UIAlertAction(title: "Settings", style: .default) {[weak self] (alertAction) in
self?.gotoAppSettings()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
alert.addAction(settingsAction)
alert.addAction(cancelAction)
DispatchQueue.main.async {
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
}
}
private func gotoAppSettings() {
guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.openURL(settingsUrl)
}
}
}
Check out: Push Notifications Tutorial: Getting Started
Thanks for the earlier answers. Xcode has made some changes and here's the SWIFT 2 code that passes XCode 7 code check and supports both iOS 7 and above:
if #available(iOS 8.0, *) {
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
} else {
let settings = UIRemoteNotificationType.Alert.union(UIRemoteNotificationType.Badge).union(UIRemoteNotificationType.Sound)
UIApplication.sharedApplication().registerForRemoteNotificationTypes(settings)
}
Swift 4
Import the UserNotifications framework and add the UNUserNotificationCenterDelegate in AppDelegate
import UserNotifications
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate
To Register Application for APNS, (Include the following code in didFinishLaunchingWithOptions method inside AppDelegate.swift)
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization.
}
application.registerForRemoteNotifications()
This will call following delegate method
func application(_ application: UIApplication,didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
//send this device token to server
}
//Called if unable to register for APNS.
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print(error)
}
On Receiving notification following delegate will call:
private func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
print("Recived: \(userInfo)")
//Parsing userinfo:
}
Swift 3:
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization.
}
UIApplication.shared.registerForRemoteNotifications()
Make sure to import UserNotifications at the top of your view controller.
import UserNotifications
You can send notification using the following code snippet:
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
if(UIApplication.sharedApplication().currentUserNotificationSettings() == settings ){
//OK
}else{
//KO
}
I use this code snip in AppDelegate.swift:
let pushType = UIUserNotificationType.alert.union(.badge).union(.sound)
let pushSettings = UIUserNotificationSettings(types: pushType
, categories: nil)
application.registerUserNotificationSettings(pushSettings)
application.registerForRemoteNotifications()
100% Working... You Can read onesignal document and setup properly https://documentation.onesignal.com/docs/ios-sdk-setup
OneSignal below code import in AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
OneSignal.setLogLevel(.LL_VERBOSE, visualLevel: .LL_NONE)
// OneSignal initialization
let onesignalInitSettings = [kOSSettingsKeyAutoPrompt: false, kOSSettingsKeyInAppLaunchURL: false]
OneSignal.initWithLaunchOptions(launchOptions,
appId: "YOUR_ONE_SIGNAL_ID",
handleNotificationAction: nil,
settings: onesignalInitSettings)
OneSignal.inFocusDisplayType = OSNotificationDisplayType.inAppAlert;
// promptForPushNotifications will show the native iOS notification permission prompt.
// We recommend removing the following code and instead using an In-App Message to prompt for notification permission (See step 8)
OneSignal.promptForPushNotifications(userResponse: { accepted in
print("User accepted notifications: \(accepted)")
})
return true
}

Resources