Notification iOs Push delivered? - ios

I recently set up notifications on my application, I can send via php and no worries, everything works fine.
Since last week, I am trying to find out if a push notification is received by the phone or not..
I can know when someone clicks on it but if the person does not click on it and prefer to open the application, it does not work..
Is there not a simple function that can tell me if a notification has just been received by the application ?
In my AppDelegate.swift :
import UIKit
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
...
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Check if launched from notification
if let notification = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? [String: AnyObject] {
//print(notification)
window?.rootViewController?.present(ViewController(), animated: true, completion: nil)
}
else{
//print("ici ?")
registerForRemoteNotification()
}
return true
}
...
//Called when a notification is delivered to a foreground app.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
}
//Called to let your app know which action was selected by the user for a given notification.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
completionHandler()
}
...
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
**print("here ?")**
switch((application.applicationState)){
case UIApplicationState.inactive:
print("Inactive")
//Show the view with the content of the push
completionHandler(.newData)
case UIApplicationState.background:
print("Background")
//Refresh the local model
completionHandler(.newData)
default:
print("Active")
//Show an in-app banner
completionHandler(.newData)
break
}
}
}
Problem : I never pass in didReceiveRemoteNotification :/
The "print here" is never displayed.
I have a mistake on this line :
Instance method
'application(application:didReceiveRemoteNotification:fetchCompletionHandler:)'
nearly matches optional requirement
'application(_:didReceiveRemoteNotification:fetchCompletionHandler:)'
of protocol 'UIApplicationDelegate'
But I do not understand :/
Do you have an idea ?
Thx for your help ^^

It's rather common mistake since the conversion to Swift 3 - you're using Swift 2 method.
The right signature of this method in Swift 3 is:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
print("here?")
}

Related

Deep Link in Push Notification is always redirecting to App Store

I seem to have no control over how the Deep Link in Push Notifications is always sending me to the App Store, even after the App is opened when I tap on the Push Notification. I already have a handler for my Push Notification and it catches the url:
#available(iOS 10.0, *)
extension Coordinating: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
if let apsDict = response.notification.request.content.userInfo["rpr_url"] as? String {
if apsDict.fullURLPathString().contains(string: "myurlPath") {
Coordinating.sharedInstance.customFunction()
}
}
completionHandler()
}
}
The delegate for this is set as well, I also have the didReceiveRemoteNotification handled:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
customHandler.handle(application, userInfo: userInfo, fetchCompletionHandler: completionHandler)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
customHandler.handle(application, userInfo: userInfo, fetchCompletionHandler: nil)
}
I am currently using Repro's Push Notification Service. I have also tried disabling/enabling and adding breakpoints to all URL handlers. Where does this redirect bit of code come from?
Edit: the app-site-association file is also handling Deep Links, so no problems when clicking on the url from E-mails and Browsers. This seems to only be happening for Push Notifications.

Why userNotificationCenter didReceive is not fired?

This is a part of my code. I want to use UNUserNotificationCenter and UNUserNotificationCenterDelegate to handle notification events.
This code catches the notification event when the app is in a foreground state. But "didReceive" is not fired for a background state.
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
UNUserNotificationCenter.current().delegate = self
application.registerForRemoteNotifications()
return true
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
print("willPresent") /// This works
completionHandler([.alert, .badge, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
print("didReceive") /// This doesn't work
completionHandler()
}
But if I don't use UNUserNotificationCenter.current().delegate = self the delegate method is correctly fired in the background.
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping FetchCompletionHandler) {
print("didReceiveRemoteNotification... \(userInfo)")
}
How can I use "didReceive"? I want to handle the notification in the background.
application(_:didReceiveRemoteNotification:fetchCompletionHandler:) is called when the application receives a silent push notification. Silent push notifications can be delivered in when the application is in the background state, iOS wakes the application to perform background processing invisible to the user.
A silent push notification has the content-available flag set to 1.
Silent push notifications should not include an alert, badge, or sound. Silent push is not meant to be visible to the user, it is only a hint to the application that new remote content is available.
Removing the content-available flag from your push notification payload will cause iOS to handle it as a regular notification. The user notification center delegate methods will be called instead of application(_:didReceiveRemoteNotification:fetchCompletionHandler:) but your application will be unable to do background processing triggered by the notification.
You can validate the content of your push notification payload for problems like this using this tool
This is how I handle push notification in my app. I think you need to implement all of these methods to handle all iOS versions in the foreground and background mode.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.sound,.alert,.badge], completionHandler: { (granted, error) in
if error == nil {
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
})
}
else {
let notificationTypes: UIUserNotificationType = [UIUserNotificationType.alert, UIUserNotificationType.badge, UIUserNotificationType.sound]
let pushNotificationSettings = UIUserNotificationSettings(types: notificationTypes, categories: nil)
application.registerUserNotificationSettings(pushNotificationSettings)
application.registerForRemoteNotifications()
}
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print(deviceTokenString)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to get token; error: \(error)")
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert,.sound])
//do sth
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
//do sth
}
// for iOS < 10
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
}
There are methods of UNUserNotificationCenterDelegate:
willPresent: This method gets called when you receive a notification when your app is in the foreground. If the app is in the background then this method will not calls.
didRecieve: This method gets called when a user clicked on the notification.
In case of background state, only 'didRecieve' will be called when user will click on a notification.

How to handle localNotifications when app is closed

I've searched in all questions here but no solution worked.
I scheduled localNotifications with a userInfo option.
When app is in foreground, the notification arrived and a can handle perfectly with this function that system calls by itself.
For local notifications
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
if application.applicationState == .active {
return
}
//My implementation
}
For remote notifications
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
if application.applicationState == .active {
return
}
//My implementation
}
But the problem is, when app is closed, this functions are not called and I can't handle the data that I need.
I've tried get userInfo in that function in appDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if let localUserInfo = launchOptions?[UIApplicationLaunchOptionsKey.localNotification] as? [AnyHashable: Any] {
// My implementation
} else if let remoteUserInfo = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? [AnyHashable: Any] {
// My implementation
}
return true
}
But.. Didn't work...
Someone could help me please?
Thanks in advance.
Have you registered for notifications?
In didFinishLaunchingWithOptions():
// Register Notifications
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: { granted, error in
if granted {
print("User notifications are allowed")
} else {
print("User notifications are NOT allowed")
}
})
application.registerForRemoteNotification()
UNUserNotificationCenter.current().delegate = self
Then you should catch local notifications in UNUserNotificationCenterDelegate method:
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
completionHandler()
}
}
You will get the notification in didFinishLaunchingWithOptions if the user clicks it whether it's local or remote , otherwise you won't know except if store them in server and pull them every time you open the app

Why I did not receive any notification on my iPhone?

Running this on Xcode8.3 with swift 3.1
Below is my code in AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge], completionHandler: { granted, error in
if granted {
print("OK!")
}
else {
print("No!")
}
})
application.registerForRemoteNotifications()
return true
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("==== didReceiveRemoteNotification ====")
print(userInfo)
}
I use node-apns to push notification to my app and I can have message from my Debug area in Xcode.
==== didReceiveRemoteNotification ====
[AnyHashable("id"): 123, AnyHashable("aps"): {
alert = "Hello World \U270c";
badge = 3;
}]
But, I did not receive any notification on my iPhone.
Did I missing something?
With iOS 10, you can do the following to see push notifications when the App is in Foreground. You have to implement the below function in AppDelegate. It's a delegate method of UNUserNotificationCenterDelegate.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
Follow the below steps:
Import UserNotifications and extend UNUserNotificationCenterDelegate in AppDelegate.
Set up the UNUserNotificationCenter delegate in didFinishLaunchingWithOptions.
let center = UNUserNotificationCenter.current()center.delegate = self
Implement the will present method in AppDelegate and call the completion handler with the options.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert,.badge,.sound])
}
Now if you get a push, you can see the notification alert even if your app is in foreground. More Info in Apple Doc.
if you want to handle notifications, when your app is active, you should do something like this, because the push view won't appear
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
if application.applicationState == .active {
//create custom view or something
} else {
//it was background/off
}
}
you might be also interested in creating new build schema, so your app will wait until it would be launched, so you can debug your app behaviour when receiving push.

Get data from payload when remote push notification arrive while my app is in background or closed

I need to capture data from payload when recive a remote push notification, on IOS 9 i did this using the func:
didReceiveRemoteNotification
On IOS 10 using swift 3.0 i've implemented this 2 functions.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
print("\(notification.request.content.userInfo)")
completionHandler([.alert, .badge, .sound])
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void)
{
print("User Info = ",response.notification.request.content.userInfo)
completionHandler()
}
the second fuction only executes when the user touch the push
i need capture data when a push notification arrives while my app is in background or even closed.
Regards.
greetings
When a push notification is received and your app isn't running, you need to implement your notification logic in didFinishLaunchingWithOptions:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Called when a notification is tapped and the app wasn't running, not in foreground neither in background.
if let userInfo = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? [String: AnyObject]{
// your logic here!
}
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// Capture payload here something like:
let appState = userInfo["appState"] as? String
print(appState!)
// Do something for every state
if (application.applicationState == UIApplicationState.active){
print("Active")
}else if (application.applicationState == UIApplicationState.background){
print("Background")
}else if (application.applicationState == UIApplicationState.inactive){
print("Inactive")
}
completionHandler(.noData)
}
try with the didReceiveRemoteNotification function in iOS10:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
print(userInfo)
}

Resources