Detect user clicks on push notification - ios

If the user clicks on the icon, then the application starts with the start page. How can I make sure that the user clicked on the push notification to launch the application with another start page?

func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken;
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Registration failed!")
}
// Firebase notification received
// This function will work app is in foreground state
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (_ options: UNNotificationPresentationOptions) -> Void) {
// custom code to handle push while app is in the foreground
if notification.request.content.userInfo["cook"] != nil{
return;
}
print(notification.request.content.userInfo)
UIApplication.shared.applicationIconBadgeNumber = 1;
DispatchQueue.main.async {
// add some code here..
// window?.rootViewController = LoginController()
// If you use the storyboard, then you can get controller by
// storyboard?.instantiateViewController(withIdentifier: "identifier") as! UIViewController
}
}
// This function will work app is in state of background or closed.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
// if you set a member variable in didReceiveRemoteNotification, you can check if this is from closed or background
print("Handle push from background or closed\(response.notification.request.content.userInfo)")
if response.notification.request.content.userInfo["somevariable"] != nil{
return;
}
UIApplication.shared.applicationIconBadgeNumber = 1;
DispatchQueue.main.async {
// add some code here..
}
}
Please use this this code into AppDelegate.swift
Please see the function called userNotificationCenter and comments in
code.

Ok..i will make it simple for you.
First step-
Add this function inside your AppDelegate file.
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("Hi Kirill...")
}
If you add this in your AppDelegate file, after running your app when you tap on the notification you will see this on your debugger, .
Like this -
And finally, to show a specific page in application add this inside the function.
let sb = UIStoryboard(name: "Main", bundle: nil)
let otherVC = sb.instantiateViewController(withIdentifier: " Your view controller identifier name") as! yourViewControllerClassName
window?.rootViewController = otherVC;
It will look like this -
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("Hi Kirill...")
let sb = UIStoryboard(name: "Main", bundle: nil)
let otherVC = sb.instantiateViewController(withIdentifier: " Your view controller identifier name") as! yourViewControllerClassName
window?.rootViewController = otherVC;
}
Make sure you add a another viewController, what you want to redirect/show when you tap on the notification. Thank you.

Related

UNUserNotificationCenterDelegate is not working when app is removed from background

UNUserNotificationCenterDelegate is not working when is remove from background. It is working fine while app stays in foreground and background.
Here is code
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let rootViewController = self.window!.rootViewController as! UINavigationController
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let profileViewController = mainStoryboard.instantiateViewController(withIdentifier: "SampleViewController") as! SampleViewController
rootViewController.pushViewController(profileViewController, animated: true)
completionHandler()
}
}
When app is remove from background delegate method is not called. Please help me out
When adding UserNotifications framework to a project, here are 5 things to check:
1) If you are dealing with remote notifications, be sure you have enabled that in your project's capabilities settings page of Xcode.
See figure 1
If that gives you an error, you probably need to log into your apple developer account and create a key with push notification credentials. The end result gives you a .p8 file to download. The creation of this file will clear up the error. The file itself is needed on the server that sends push notifications to your app/device. If you need help with this, check out this tutorial.
2) Add import line to the top of your AppDelegate file
import UserNotifications
3) Add UNUserNotificationCenterDelegate to your AppDelegate class declaration line.
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {...
4) Set UNUserNotificationCenter delegate to self in the application:didFinishLaunchingWithOptions method.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
//...
UNUserNotificationCenter.current().delegate = self
//...
return true
}
5) Add your delegate functions (if you want to use them)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
NSLog("Application delegate method userNotificationCenter:didReceive:withCompletionHandler: is called with user info: %#", response.notification.request.content.userInfo)
//...
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
NSLog("userNotificationCenter:willPresent")
//...
completionHandler([.alert])
}
Hope that helps.
check didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? method. When user taps a notification banner (and the app is terminated) the app is started, this method is called and launchOptions contains notification info. Therefore you can understand (by checking the launchOptions) that the app is launched by tapping on notification banner and navigate user wherever you want to

Execute function on tap Push Notifications

I have an iOS APP and a push notifications system which sends programatically notifications to the storing their token in a database.
I have some views which I show or hide in the default View Controller. I would like to make the APP show a specific view when the user taps the notification. I have created a function, but I dont know how to make it work.
You can catch a push notifications inside AppDelegate and add Observer inside your controller file where you want to show a specific view on tap.
Send push notification payload data in userInfo or object in NotificationCenter.default.post.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
UIApplication.shared.applicationIconBadgeNumber = 0
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "NewNotification") , object: nil, userInfo: response.notification.request.content.userInfo)
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(.alert)
}
Add Notification Observer in your controller file :
NotificationCenter.default.addObserver(self, selector: #selector(pushNotificationHandler(_:)) , name: NSNotification.Name(rawValue: "NewNotification"), object: nil)
then call UI update method :
func pushNotificationHandler(_ notification : NSNotification) {
// self.udateUI() // Add code to show a specific view on tap.
}
In AppDelegate APNS delegate method make a check according to the userInfo you get with your notification/payload and then call that function either
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
if response.notification.request.content.userInfo["ViewType"] as! String == "ShowNotificationView" {
// Then you can implement your functionaliton here according to the need.
}
if you need any other help please let me know by posting the actuall code & requirement over
First of all, it is required to add one more key to the push notification payload as screen_type based on the content to which screen you need to navigate or show the particular view controller(screen).
After that, add the following method to your AppDelegate class which implements the notifications handler
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
let payload = userInfo
let type = payload["type"]
if type == "all-posts" || type == "default"{
/*
* I'm assuming you have your own HomeViewController object
*/
let homeVC = HomeViewController()
// present or push
UIApplication.topViewController()?.present(homeVC, animated: true, completion: nil)
}else if type = "post-details"{
/*
* I'm assuming you have your own PostDetailViewController object
*/
let postDetailVC = PostDetailViewController()
// present or push
UIApplication.topViewController()?.present(postDetailVC, animated: true, completion: nil)
}else if type == "friend-request"{
/*
* I'm assuming you have your own UserViewController object
*/
let userVC = UserViewController()
// present or push
UIApplication.topViewController()?.present(userVC, animated: true, completion: nil)
}
}
Helper method
extension UIApplication {
class func topViewController(base: UIViewController? = (UIApplication.sharedApplication().delegate as! AppDelegate).window?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}
Note: If you are using latest version of swift, you are required to implement the UNUserNotificationCenterDelegate methods

How do I get the notification to take me to the desired viewController?

I'm working on a project but struggling to get the notification to take me to my "NotiViewController". Sometimes it works as desired but other times it just opens my app to whatever viewController I was last on.
I hacked this code together a few online sources:
extension QuestionViewController: UNUserNotificationCenterDelegate{
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response:
UNNotificationResponse, withCompletionHandler completionHandler: #escaping () ->
Void) {
let vc = storyboard?.instantiateViewController(withIdentifier: "NotiViewControllerID")
as! NotiViewController
show(vc, sender: Any?.self)
completionHandler()
}
I want to be able to send a notification that asks the user a question, then once it is clicked have the user taken to a answer...
eg notificationQuestion: "How many states are in the contiguous United States?" =>tap notification => loads the appropriate NotiViewController: "48"
Try this code:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
//when application is close
if let userInfo = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? [AnyHashable : Any] {
print(userInfo)
self.getBGUserInfo(userInfo: userInfo)
// if notification call to redirect perticular page
}
}
func getBGUserInfo(userInfo : [AnyHashable : Any] ) {
//get userInfo details here
NotificationCenter.default.post(name: Notification.Name(rawValue: "NotificationRedirect"), object: nil)
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
NotificationCenter.default.post(name: Notification.Name(rawValue: "NotificationRedirect"), object: nil)
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
NotificationCenter.default.post(name: Notification.Name(rawValue: "NotificationRedirect"), object: nil)
}
//In ViewController which open first while open app
//In ViewDidLoad
NotificationCenter.default.addObserver(self, selector: #selector(self.receiveTestNotification(_:)), name: NSNotification.Name(rawValue: "NotificationRedirect"), object: nil)
//Over
func receiveTestNotification(_ notification: Notification) {
let notName : String = String(describing: notification.name.rawValue)
if (notName == "NotificationRedirect"){
//Redirect your NotiViewController
}
}

IOS 10 how to handle user clicking on push notification

I have managed to get push notifications working correctly and going to the right device using FireBase. However if a user clicks on the push notification I would like all of them to go to a specific Controller Called "NotificationC" right now if a user clicks on a push notification it goes to a controller called HomeC which I don't want . I have read Firebase push notification action but still can't get it to go to that controller here is my code.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .sound, .alert], completionHandler: {(granted, error) in
if (granted)
{
UIApplication.shared.registerForRemoteNotifications()
Messaging.messaging().delegate = self as? MessagingDelegate
}
else{
//Do stuff if unsuccessful...
}
})
application.registerForRemoteNotifications()
NotificationCenter.default.addObserver(self, selector:
#selector(tokenRefreshNotification), name: NSNotification.Name.InstanceIDTokenRefresh, object: nil)
FirebaseApp.configure()
return true
}
func tokenRefreshNotification(notification: NSNotification) {
// NOTE: It can be nil here
let login = LoginC()
login.getDeviceToken(id: MYID)
newDeviceToken = true
}
// The callback to handle data message received via FCM for devices running iOS 10 or above.
func applicationReceivedRemoteMessage(_ remoteMessage: MessagingRemoteMessage) {
let homeC = HomeC()
homeC.getMyNotifcations()
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print("User Info = ",notification.request.content.userInfo)
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) {
let homeC = HomeC()
homeC.getMyNotifcations()
completionHandler()
}
The code above
let homeC = HomeC()
homeC.getMyNotifcations()
is essentially a segue which should get users to my Notification Controller and this is how I have it done
func getMyNotifcations() {
let Popup = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NotificationC") as! NotificationC
Popup.notificationCount = Int(notificationCount!)
self.addChildViewController(Popup)
Popup.view.frame = self.view.frame
self.view.addSubview(Popup.view)
Popup.didMove(toParentViewController: self)
}
When I put the getMyNotifcations in a IBAction it works . Again I simply want the user to go to the NotificationC Controller when they tap on the Notification any suggestions would be great . I also put a breakpoint on all those functions in the AppDelegate and none of them fire off on tap .
It seems like your view controller is not instantiated properly, you are just making the object of the class.
Try this and maybe add delay too.
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let homeC = storyboard.instantiateViewController(withIdentifier: "YOUR_VIEWCONTROLLER_IDENTIFIER_IN_STORYBOARD") as? HomeC
if homeC != nil {
homeC!.view.frame = (self.window!.frame)
self.window!.addSubview(homeC!.view)
self.window!.bringSubview(toFront: homeC!.view)
homeC.getMyNotifcations()
}

Getting local notifications to show while app is in foreground Swift 3

Apparently this is now possible with ios10 :
optional func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void)
This answer basically says the tools needed to do it:
Displaying a stock iOS notification banner when your app is open and in the foreground?
I'm just not really understanding how to put it all together.
I dont know how important this is, but I'm not able to keep the optional func and xcode wants me to switch it to private.
I'm trying to show the badge, and the docs provide
static var badge: UNNotificationPresentationOptions { get }
Little lost here.
And then I'm assuming if I want to exclude a certain view controller from getting these badges and I'm not using a navigation controller this code I found would work? :
var window:UIWindow?
if let viewControllers = window?.rootViewController?.childViewControllers {
for viewController in viewControllers {
if viewController.isKindOfClass(MyViewControllerClass) {
print("Found it!!!")
}
}
}
There is a delegate method to display the notification when the app is open in iOS 10. You have to implement this in order to get the rich notifications working when the app is open.
extension ViewController: UNUserNotificationCenterDelegate {
//for displaying notification when app is in foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
//If you don't want to show notification when app is open, do something here else and make a return here.
//Even you you don't implement this delegate method, you will not see the notification on the specified controller. So, you have to implement this delegate and make sure the below line execute. i.e. completionHandler.
completionHandler([.alert, .badge, .sound])
}
// For handling tap and user actions
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
switch response.actionIdentifier {
case "action1":
print("Action First Tapped")
case "action2":
print("Action Second Tapped")
default:
break
}
completionHandler()
}
}
In order to schedule a notification in iOS 10 and providing a badge
override func viewDidLoad() {
super.viewDidLoad()
// set UNUserNotificationCenter delegate to self
UNUserNotificationCenter.current().delegate = self
scheduleNotifications()
}
func scheduleNotifications() {
let content = UNMutableNotificationContent()
let requestIdentifier = "rajanNotification"
content.badge = 1
content.title = "This is a rich notification"
content.subtitle = "Hello there, I am Rajan Maheshwari"
content.body = "Hello body"
content.categoryIdentifier = "actionCategory"
content.sound = UNNotificationSound.default
// If you want to attach any image to show in local notification
let url = Bundle.main.url(forResource: "notificationImage", withExtension: ".jpg")
do {
let attachment = try? UNNotificationAttachment(identifier: requestIdentifier, url: url!, options: nil)
content.attachments = [attachment!]
}
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 3.0, repeats: false)
let request = UNNotificationRequest(identifier: requestIdentifier, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error:Error?) in
if error != nil {
print(error?.localizedDescription ?? "some unknown error")
}
print("Notification Register Success")
}
}
In order to register in AppDelegate we have to write this piece of code in didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
registerForRichNotifications()
return true
}
I have defined actions also here. You may skip them
func registerForRichNotifications() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert,.badge,.sound]) { (granted:Bool, error:Error?) in
if error != nil {
print(error?.localizedDescription)
}
if granted {
print("Permission granted")
} else {
print("Permission not granted")
}
}
//actions defination
let action1 = UNNotificationAction(identifier: "action1", title: "Action First", options: [.foreground])
let action2 = UNNotificationAction(identifier: "action2", title: "Action Second", options: [.foreground])
let category = UNNotificationCategory(identifier: "actionCategory", actions: [action1,action2], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
}
If you want that your notification banner should be shown everywhere in the entire application, then you can write the delegate of UNUserNotificationDelegate in AppDelegate and make the UNUserNotificationCenter current delegate to AppDelegate
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print(response.notification.request.content.userInfo)
completionHandler()
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
}
}
Check this link for more details
https://www.youtube.com/watch?v=Svul_gCtzck
Github Sample
https://github.com/kenechilearnscode/UserNotificationsTutorial
Here is the output
Swift 3 | iOS 10+
Assuming you know how to schedule a local notification:
func scheduleLocalNotification(forDate notificationDate: Date) {
let calendar = Calendar.init(identifier: .gregorian)
let requestId: String = "123"
let title: String = "Notification Title"
let body: String = "Notification Body"
// construct notification content
let content = UNMutableNotificationContent()
content.title = NSString.localizedUserNotificationString(forKey: title, arguments: nil)
content.body = NSString.localizedUserNotificationString(forKey: body, arguments: nil)
content.sound = UNNotificationSound.default()
content.badge = 1
content.userInfo = [
"key1": "value1"
]
// configure trigger
let calendarComponents: [Calendar.Component] = [.year, .month, .day, .hour, .minute]
let dateComponents = calendar.dateComponents(calendarComponents, from: notificationDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
// create the request
let request = UNNotificationRequest.init(identifier: requestId, content: content, trigger: trigger)
// schedule notification
UNUserNotificationCenter.current().add(request) { (error: Error?) in
if let error = error {
// handle error
}
}
}
You need to make your AppDelegate implement the UNUserNotificationCenterDelegate protocol, and set it as the notification center's delegate with UNUserNotificationCenter.current().delegate = self.
// AppDelegate.swift
import UIKit
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// set app delegate as notification center delegate
UNUserNotificationCenter.current().delegate = self
}
}
extension AppDelegate: UNUserNotificationCenterDelegate {
// called when user interacts with notification (app not running in foreground)
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse, withCompletionHandler
completionHandler: #escaping () -> Void) {
// do something with the notification
print(response.notification.request.content.userInfo)
// the docs say you should execute this asap
return completionHandler()
}
// called if app is running in foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent
notification: UNNotification, withCompletionHandler completionHandler:
#escaping (UNNotificationPresentationOptions) -> Void) {
// show alert while app is running in foreground
return completionHandler(UNNotificationPresentationOptions.alert)
}
}
Now your local notifications will appear when your app is in the foreground.
See the UNUserNotificationCenterDelegate docs for reference.
Key to getting your notifications to show up while your app is in the foreground is also setting:
content.setValue(true, forKey: "shouldAlwaysAlertWhileAppIsForeground")
in your UNNotificationRequest. As for the rest, see the excellent answer by Rajan Maheshwari.
When your app is open in the foreground userNotificationCenter method call
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
completionHandler(.alert)
}
None of these answers are good with recent IOS versions
shouldAlwaysAlertWhileAppIsForeground will crash on >= IOS 12
assigning UNUserNotificationCenter.current().delegate changes the behavior of background push notifications. UIApplicationDelegate.didReceiveRemoteNotification() is no longer called, when push notification is received and app is on background (until user clicks the notification).

Resources