I am new to iOS and Swift. I am implementing remote notification in my app. Everything works fine when the app is active or in the background. But my notification does not show up when the app is terminated. All I am getting is the alert sound of the notification.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
if #available(iOS 10.0, *){
}else{
let notification = UILocalNotification()
notification.alertTitle = "my Title"
notification.alertBody = "My Message"
notification.category = "customCategory"
notification.soundName = UILocalNotificationDefaultSoundName
application.scheduleLocalNotification(notification)
}
}
Below AppDelegate method will be called When you receive a notification and application is in killed state
didFinishLaunchingWithOptions
So you should handle it properly from here when app is in killed state.
Below code helps to identify the Remote/push or Local notification in didFinishLaunchingWithOptions method:
if let launchOpts = launchOptions as [UIApplicationLaunchOptionsKey: Any]? {
if let notificationPayload = launchOpts[UIApplicationLaunchOptionsKey.remoteNotification] as? NSDictionary {
//Handle push notification here
}
else if let notification = (launchOpts as NSDictionary).object(forKey: "UIApplicationLaunchOptionsLocalNotificationKey") as? UILocalNotification {
//Handle local notification here
}
Related
IOS 13.7 IPhone Xr, Xcode Version 11.7 (11E801a)
I edited app scheme and set launch mode to "Wait for the executable to be launched". I run app, and send a simple notification on my device.
this notification:
{
"aps":{
"content-available":1
}
}
in xcode status changed from "Waiting to attach to test on iPhone" to "Running test on iPhone", but the notification wasn't received.
i try catch notification in this method:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void)
Next notification I receive successfully. This case can be repeated after application reload.
Can you help me find out why I don't receive the first notification
Please try this payload :
{"aps":{"alert":"","content-available":1}}
If your app wasn’t running, the push notification is passed to your AppDelegate in the launchOptions
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
...
let notificationOption = launchOptions?[.remoteNotification]
if let notification = notificationOption as? [String:AnyObject]{
// received notification
}
...
}
I have a webview ios app that receives notifications and I pass a url so that when the user clicks on the notification it will open the webview to that url.
When the app is in the foreground and background it works fine. If the user gets the notification when the app is closed and not currently running then the app opens but does not go to that url
In my didReceiveRemoteNotification I detect the different states of the app but I thought that .background would work the same as not running but I guess it doesn't. How can I get the notification to open the url coming from when the app is closed?
AppDelegate.swift
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
let data = userInfo as! [String: AnyObject]
let state = UIApplication.shared.applicationState
if state == .background {
// background
//print("==== Active Running ====")
if let aps = data["aps"] {
let url = aps["url"]
viewController?.loadRequestnotification(for: url as! String)
}
}
else if state == .inactive {
// inactive
//print("==== Inactive Running ====")
if let aps = data["aps"] {
let url = aps["url"]
viewController?.loadRequestnotification(for: url as! String)
}
}
}
UPDATE
So with some help I have been able to use didFinishLaunchingWithOptions to call my webview, but the notification when pressed is still not opening to the url.
I use viewController?.loadRequestnotification(for: url as! String) in some other areas of my delegate that works fine. I am suspecting the return true might be conflicting the call.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self
ConnectionManager.sharedInstance.observeReachability()
// Override point for customization after application launch.
FirebaseApp.configure()
registerForPushNotifications()
if launchOptions != nil {
// opened from a push notification when the app is closed
let userInfo = launchOptions?[.remoteNotification] as? [AnyHashable : Any]
if userInfo != nil {
if let object = userInfo?["aps"] as? [String : AnyObject] {
let url = object["url"]
viewController?.loadRequestnotification(for: url as! String)
}
}
}
return true
}
didReceiveRemoteNotification won't be called while app is closed.
Try this code when your app is closed to get notification data.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
if launchOptions != nil {
// opened from a push notification when the app is closed
let userInfo = launchOptions?[.remoteNotification] as? [AnyHashable : Any]
if userInfo != nil {
if let object = userInfo?["aps"] {
let url = object["url"]")
// Now set root controller here
}
}
} else {
// opened app without a push notification.
}
}
There is one scenario like your app is not running and user click on your app's notification then following the way you can get it.
Here is code you can get it
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if let notification = launchOptions?[.remoteNotification] as? [String: Any] {
if let dictionary:NSDictionary = notification as? NSDictionary{
print("Dictionary Print in didFinishLaunching :: \(dictionary)")
}
}
}
Your app can received some notification and it is in notification center but user can not click on any notification but they will open your app as normally then following is a way, you can get all notification which is received by your app.
UNUserNotificationCenter.current().getDeliveredNotifications { (notification) in
print(notification.count)
}
This is the function that called when app receives any notification.
I have used this in my chatting app.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
if application.applicationState == .active {
//Application is currently active and user receive the notification
} else if application.applicationState == .background {
//app is in background, but not killed
} else if application.applicationState == .inactive {
//app is transitioning from background to foreground (user taps notification), do what you need when user taps here
//Load your URL into webView from here
}
}
If app is open and you want to perform some action when notification is received
Use this method
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(UNAuthorizationOptions.alert.rawValue | UIUserNotificationType.sound.rawValue | UIUserNotificationType.badge.rawValue)
}
You can also check weather the app is open from notification or not in
AppDelegate's didFinishLaunchingWithOptions
But it is recommended to keep the this didFinishLaunchingWithOptions method light as possible.
I hope this will work for you
I am working Push notification and i have done all steps to setup push notification.
i can able to receive notification when application in background but when application in foreground its landing on didReceiveRemoteNotification but its not firing.
here my code in AppDelegate.swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let notificationSettings = UIUserNotificationSettings(forTypes: [.Badge, .Alert, .Sound], categories: nil)
application.registerUserNotificationSettings(notificationSettings)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
if application.applicationState == UIApplicationState.Active {
let localNotification = UILocalNotification()
let date = NSDate(timeIntervalSinceNow: 10)
localNotification.fireDate = date
let timeZone = NSTimeZone.localTimeZone()
localNotification.timeZone = timeZone
localNotification.alertBody = "Sample Notification Body"
localNotification.userInfo = userInfo
print(localNotification)
localNotification.applicationIconBadgeNumber = UIApplication.sharedApplication().applicationIconBadgeNumber + 1
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
}
}
What mistake i am doing ??
Thanks in advance
What I suspect is, you're trying to show the remote notification when the app is active using local notification.
Well, either its local notification or remote, you can't see any UI alert when the app is active, instead the delegate methods for local or remote notification are called accordingly.
However iOS 10 adds the ability to view it inside the app. Here's the discussion: https://stackoverflow.com/a/37844312/593709
For showing any alert on pre-iOS-10, while your app is active, you need to use UIAlertController or some other implementation like MPNotificationView.
When the application is in Foreground and running, it does not show notification banner. Banner alert is only shown when Application is either in background(inactive) or is not running at all. The delegate method
application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void)
is called for Remote(Push) Notification and
application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification)
is called for local notification.
You can use any 3rd party library bryx-inc/BRYXBanner to show a banner for your notification alert message . The delegate method didReceiveRemoteNotification can be used to update badge icon and show message in banner view.
I am creating local notification when app receiving Push notification. these local notification generating when app in foreground and when i am creating local notification at the same time didReceiveLocalNotification method is calling and getting difficulties to manage local notification and clicking/tap on location same event calling twice.I need to avoids duplicate Local notifications also.
Please help me for solve this issue.
//MARK: - Delegate Method For APNS Notification
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
print("Notification Message \(userInfo)")
let aps = userInfo["aps"] as! [String: AnyObject]
// 1
if userInfo["postData"] != nil {
// Refresh Promotions
print("Got it...")
// Clear Previous Value Data
postData.removeAll()
//Adding New Post Data here
if (userInfo["postData"] != nil){
self.postData = userInfo["postData"]! as! [String : AnyObject]
print(self.postData)
}
//Condition here for Notification
if appInForeground == false {
//Goto Promo List
//Set Boolean for View
notiDetails = true
//Navigation
gotoPromoListView()
}else{
let systemSoundID: SystemSoundID = 1016
// to play sound
AudioServicesPlaySystemSound (systemSoundID)
AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
let notification = UILocalNotification()
notification.alertBody = (aps["alert"] as? String)!
notification.soundName = UILocalNotificationDefaultSoundName
notification.userInfo = userInfo["postData"]! as! [String : AnyObject]
UIApplication.sharedApplication().scheduleLocalNotification(notification)
}
How to manage this method for local notification
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
// Do something serious in a real app.
print("Received Local Notification:")
print(notification.userInfo)
self.postData = notification.userInfo as! [String : AnyObject]
didTapNotification()
}
Could you please show your code, where you register your remote notifications?
If you want to show alert and badge, when receive push notifications, you can make like this:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let notificationTypes: UIUserNotificationType = [.Alert, .Badge, .Sound]
let notificationSettings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(notificationSettings)
return true
}
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
UIApplication.sharedApplication().registerForRemoteNotifications()
}
After that you can add custom actions to method:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject :
}
If you need local notifications, you should set fire property, when you schedule notification:
let localNotification = UILocalNotification()
localNotification.fireDate = NSDate()
localNotification.timeZone = NSTimeZone.defaultTimeZone()
localNotification.alertBody = text
localNotification.soundName = UILocalNotificationDefaultSoundName
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
For some reason my didReceiveRemoteNotification is never called. I have done the following:
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
With Code:
Register app for push notification
Handle didRegisterForRemoteNotificationsWithDeviceToken method
Set targets> Capability> background modes> Remote Notification
Handle didReceiveRemoteNotification
Yet my function does not seem to get called. My code looks like this:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
if (application.respondsToSelector("isRegisteredForRemoteNotifications"))
{
// iOS 8 Notifications
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: (.Badge | .Sound | .Alert), categories: nil));
application.registerForRemoteNotifications()
}
else
{
// iOS < 8 Notifications
application.registerForRemoteNotificationTypes(.Badge | .Sound | .Alert)
}
return true
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
var tokenString = ""
for var i = 0; i < deviceToken.length; i++ {
tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
}
apnsID = tokenString
println("******apnsID is \(apnsID)")
dToken = deviceToken
println("******dToken is \(dToken)")
NSUserDefaults.standardUserDefaults().setObject(deviceToken, forKey: "deviceToken")
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
println("***********didFailToRegisterForRemoteNotificationsWithError")
println(error)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
println("Getting notification")
var message: NSString = ""
var alert: AnyObject? = userInfo["aps"]
println(userInfo["aps"])
if((alert) != nil){
var alert = UIAlertView()
alert.title = "Title"
alert.message = "Message"
alert.addButtonWithTitle("OK")
alert.show()
}
}
add content_available:true in your request . for iOS payload data.You will get notification in didReceiveRemoteNotification. Now handle it.
As I found out having the same problem myself, in order for didReceiveRemoteNotificationto be called, the incoming notification music carry an "available_content" : true parameter with the notification payload. So in case of you sending the notification in a dictionary form , as was my case in device to device pushes, you just have to add it in the dictionary as you would specify other parameters as you would for sound or badge, also needed if you're using some sort of push service as Postman
Three steps:
Add logic here to handle incoming notification:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// Add your logic here
completionHandler(.newData)
}
Add Background mode to capabilities in target, and ensure to check 'Remote notifications'
While sending a push notification, add "content_available" : true
This worked for me in iOS 14/Xcode 12.3.