ios swift creating local notification after silent notification - ios

I am sending a silent push notification to my app, then processing the content of the push notification, before deciding whether to send a local notification to the user. However I cant fire a local notification from the app after receiving a silent notification.
Here is my code in appdelegate after triggering a silent notificaiton:
func application(application: UIApplication,
didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void) {
println("Did receive remote with completion handler")
var localNotification:UILocalNotification = UILocalNotification()
localNotification.alertAction = "view broadcast messages"
localNotification.alertBody = "Hello"
localNotification.fireDate = NSDate(timeIntervalSinceNow: 0)
localNotification.soundName = UILocalNotificationDefaultSoundName;
application.scheduleLocalNotification(localNotification)
handler(UIBackgroundFetchResult.NewData)
}
However the local notification never fires.
I have enabled Location updates, background fetch and remote notifications capabilities.
Also, when my app is in it's background state it listens for location updates then alerts the user with a local notification in specific situations- which works from similar code.
So why do local notifications not fire from didReceiveRemoteNotification?
Thanks

Ok I figured it out,
application.scheduleLocalNotification(localNotification)
should have been
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
Hope this helps someone!

Related

How to delete specific remote notification if app is closed or in background

My app has a chat service, when new notification is received, I want to clear the notifications between user1 and user2 except the new one.
I can do it when app is in foreground by calling:
UNUserNotificationCenter.current().getDeliveredNotifications { notifications in
print("count: \(notifications.count)")
for notif in notifications {
let nUserInfo = notif.request.content.userInfo
let nType = Int(nUserInfo[AnyHashable("type")] as! String)
if nType == type {
let notifId = notif.request.identifier
if notifId != notification.request.identifier {
center.removeDeliveredNotifications(withIdentifiers: [notif.request.identifier])
}
}
}
where type is a customValue.
How to do this when app is in background or closed by a user.
You need to turn on Background Modes capability and check Remote notifications mode. In order to delete the notification in background, you need to send a new notification with no alert, like {"aps": {"content-available": 1}, "del-id": "1234"}, where content-available means (you can check more about here Apple push service)
Include this key with a value of 1 to configure a background update notification. When this key is present, the system wakes up your app in the background and delivers the notification to its app delegate. For information about configuring and handling background update notifications, see Configuring a Background Update Notification.
and del-id will be the id of the notification you want to delete, you can use an array as well. You can put these information with together with your message notification as well.
In your AppDelegate.swift you will need to add this method to delete the notification in background. In your case, you can send the id of the notification you does not want to delete and use your method to delete all delivered notification except the one with the id you send in your last notification.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
guard let idToDelete = userInfo["del-id"] as? String else {
completionHandler(.noData)
return
}
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [idToDelete])
completionHandler(.noData)
}

Local Notification on offline (Swift)

I want to receive a local notification in my app (swift) when I'm not connected to Internet and I have some information registered in my Local Data base.
Is it possible to do that please?
Local Notification doesnot requires internet.
About Local Notification from apple developer site
Local notifications give you a way to alert the user at times when your app might not be running. You schedule local notifications at a time when your app is running either in the foreground or background. After scheduling a notification, the system takes on the responsibility of delivering the notification to the user at the appropriate time. Your app does not need to be running for the system to deliver the notification.
For more info check this link. You can also check this link for tutorial.
do like this :
public func presentNotification(_ notifAction: String, notifBody: String) {
let application = UIApplication.shared
let applicationState = application.applicationState
if applicationState == UIApplicationState.background {
let localNotification = UILocalNotification()
localNotification.alertBody = notifBody
localNotification.alertAction = notifAction
localNotification.soundName = UILocalNotificationDefaultSoundName
localNotification.applicationIconBadgeNumber += 1
application.presentLocalNotificationNow(localNotification)
}
}
UIApplicationState has these states :
case active
case inactive
case background

detect specific localNotification opened

I am scheduling timer and sending some local notification for user about some data, example is - if there is some store near.
func configureNotification(shop: Shop) {
let notification = UILocalNotification()
notification.fireDate = NSDate(timeIntervalSinceNow: 0)
notification.alertBody = "There is a store \(shop.name) near!"//Localized().near_shop_string + shopName
notification.alertAction = "Swipe to see offer!"//Localized().swipe_to_see_string
notification.soundName = UILocalNotificationDefaultSoundName
UIApplication.sharedApplication().scheduleLocalNotification(notification)
}
When app running in background if there is some store near users coordinates, there is a local notification.
For example, there is three local notification received about different stores and user swipes the second one and make app active from it.
The question is, to recognize from what specific notification applicationDidBecomeActive was launched, some launcOptions, as for push notifications from server? Any solutions?
You need handle it in didReceiveLocalNotification delegate method
func application(application: UIApplication!, didReceiveLocalNotification notification: UILocalNotification!) {
// do your jobs here
}
notification param will contain info for every notification.
Also launchOptions has a key UIApplicationLaunchOptionsLocalNotificationKey that contains notification.
You can get it like
let localNotification:UILocalNotification = launchOptions.objectForKey(UIApplicationLaunchOptionsLocalNotificationKey)

Handling push notifications payload data

I am searching the way about how to handle push notification payload data as soon as the notification reaches to the client app without opening or tapping it.And I am still not getting the data unless the user tap or open it from notification center or banner or alert.The function didReceiveRemoteNotification only triggered when the user click the notification on the screen.So,how to get the notification payload data when the notification arrive to client app even the user ignore(without open or tap) it.
INFO : I heard that GCM(Google Cloud Messaging) can make notification handler if the client app user tapped the notification or not.It can catch the notification payload json data as soon as it reach the client app without even need user to tap or open it.Is that right?
I really need a hand to pick me up with getting notification payload data on ios without even need a user to open or tap it.
Update : The app is still running on device which mean it was active.I can get the payload data when i click my notification which was "{aps:} json i get it.But,I still cant get the data when i don't open the notification"
Here is my state
When the app was at foreground,I get the data.
1.I run the App,
2.Send Notification,
3.Get the notification with an alert,
4.I get the data(payload).
Work fine when app is active.
But,when the app reach to background
1.Run The app,
2.Close The App by pressing home button,
3.Send Notification,
4.Get the notification.
5.But,cant get the data until i click notification that I was receive at banner
or notification center.
But,when i click the notification at banner or notification it went to app and then i get the data.
Is there anyway that i can get the data if the app in background when the notification received.
Here is the code :
import UIKit
import RealmSwift
let realm = try! Realm()
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var data : [NSObject : AnyObject]!
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
//one singnal is the push notification service that i use for push notification.
let oneSignal = OneSignal(launchOptions: launchOptions, appId: "__app_id__") { (message, additionalData, isActive) in
NSLog("OneSignal Notification opened:\nMessage: %#", message)
if additionalData != nil {
NSLog("additionalData: %#", additionalData)
}
}
oneSignal.enableInAppAlertNotification(true)
return true
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
print("User Info : \(userInfo)")
if let custom = userInfo["custom"] as? NSDictionary{
if let a = custom["a"] as? NSDictionary{
print("A : \(a)")
}
}
}
I came across the same problem. As mentioned in the previous comments, this post is quite helpful.
According to Apple,
When a remote notification arrives, the system displays the
notification to the user and launches the app in the background (if
needed) so that it can call this method. Launching your app in the
background gives you time to process the notification and download any
data associated with it, minimizing the amount of time that elapses
between the arrival of the notification and displaying that data to
the user.
The first thing you have to do is to allow your app to do something when in background. You do this by adding Required background mode in your info.plist, then add it App downloads content in response to push notifications. Your info.plist should look something like this:
Now this is done, your app should awake when it receive a notification. You can execute a small code inside didReceiveRemoteNotification. Such as this.
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
//do some code here
UIBackgroundFetchResult.NewData
}
Note that you have to pay attention to the completionHandler:
As soon as you finish processing the notification, you must call the
block in the handler parameter or your app will be terminated. Your
app has up to 30 seconds of wall-clock time to process the
notification and call the specified completion handler block.
Let me know if everything is clear :)

Swift: didReceiveRemoteNotification to be called with no user activity involved (Using Houston ruby gem)

I have a small swift app written. I have successfully configured the remote notification services. Here is the code
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
println("received notification")
var remoteServer = RemoteServer()
remoteServer.sendDataToServer { (success) -> () in
completionHandler(UIBackgroundFetchResult.NewData)
}
}
Now, I am using Houston ruby gem to send the notifications. which looks something like this
require 'houston'
APN = Houston::Client.production
APN.certificate = File.read("production_certificate.pem")
token = "token here"
notification = Houston::Notification.new(device: token)
notification.content_available = true
notification.alert = "test"
notification.badge = 0
APN.push(notification)
I can successfully see the message on the lock screen. But its when I swipe the notification , which opens the app, thats when the didReceiveRemoteNotification method gets called.
I am wondering if there is a way to fire off didReceiveRemoteNotification without the user having to swipe the notification ? (Pretty much no user activity required) ?
I tried setting the alert to nil. But then since no user activity can be detected didReceiveRemoteNotification never gets fired off.
How should I handle this scenario? Should I be using performFetchWithCompletionHandler , but then how to fire it from the remote server?
UPDATE: the didReceiveRemoteNotification does get sent out when the app is currently opened, but as soon as the device is locked. The same isn't getting called.
Thanks

Resources