I have so many screens in my application. So when the user taps on the local notification , I'd like to deep-link one of the screens.
The could be not running or active on one of those screens or inactive or suspended state.
I couldn't see how to do that
If anyone could explain it'd be great
You can use DeepLinkKit for navigation to different screens. I'm using this library in my app, I have about 30-37 deeplinks for every screen in the app. I'm using this with Cordinators pattern for navigation. Let me know if you need any help with implementing.
Send Notification from anywhere.
func sendNotification(){
let info: [String: String] = ["vc_name": "CartViewController"]
NotificationCenter.default.post(name: Notification.Name("YourLocalNotification"), object: nil, userInfo: info)
}
Add Notification handler on Receive Notification in your root controller.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.youNotificationAction(notification:)), name: Notification.Name("YourLocalNotification"), object: nil)
}
Receive notification, Check your notified information and navigate to your respective controller.
#objc func youNotificationAction(notification: Notification) {
if let vcName = notification.userInfo?["vc_name"] as? String {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let toVC = storyBoard.instantiateViewController(withIdentifier: vcName)
navigationController?.pushViewController(toVC, animated: true);
}
}
Inherit UNUserNotificationCenterDelegate in appdelegate or viewcontroller
Implement below methods
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(UNNotificationPresentationOptions.alert)
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
completionHandler()
}
This is where you intercept the notification tap and call the appropriate modules either using OpenURL or doing a direct push or present or switch the tab of viewcontroller.
Related
I have researched and came across a few articles about opening local notifications to a specific view and showing the information within the view controller. Unfortunately, I'm still unable to make the function work in my app.
I have a quote app and I send local and push notifications. When I have a scheduled notification, the user should be able to click the notfication and be directed to the "TopViewController" and the controller should display the notification information. Instead the app opens up to the last view controller the user was on.
Could someone tell me what I am doing wrong?
Here is the code the I have in the "TopViewController" ViewDidLoad
NotificationCenter.default.addObserver(self, selector: ("Scheduled:"), name:NSNotification.Name(rawValue: "Scheduled"), object: nil)
Here is the code I have in the AppDelegate:
#Published var quote = Quote(id: "", text: "", author: "")
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let application = UIApplication.shared
if(application.applicationState == .active){
print("user tapped the notification bar when the app is in foreground")
}
if(application.applicationState == .inactive)
{
print("user tapped the notification bar when the app is in background")
}
guard let rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController else {
return
}
print("got active scene")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let conversationVC = storyboard.instantiateViewController(withIdentifier: "TopViewController") as? TopViewController,
let tabBarController = self.window?.rootViewController as? UITabBarController
{
conversationVC.shareQuote?.text = response.notification.request.content.body
conversationVC.shareQuote?.author = response.notification.request.content.subtitle
}
completionHandler()
}
The notification doesn't open up to the right view controller nor does it show the notification information.
Here are a few ideas I have, however, I cannot be certain if this is your fix but it was too much to put into the comments.
Are you setting the app delegate as the UNNotificationCenter's delegate ?
UNUserNotificationCenter.current().delegate = self
Does anything print to your console like print("got active scene") or print("user tapped the notification bar when the app is in foreground") ?
If you have done both of the above, can you add breakpoints inside this block of code
{
conversationVC.shareQuote?.text = response.notification.request.content.body
conversationVC.shareQuote?.author = response.notification.request.content.subtitle
}
This will tell you if there is some issue in your logic if it does not enter this block of code
Update
To manage notifications in the foreground, you need to also implement this UNUserNotificationCenterDelegate method:
// This will show the notification when the app is in
// the foreground. This is optional
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.list, .banner, .badge, .sound])
}
I want to show custom UI for notification when App is running but.(Like in whats app). How can i do this custom view. I tried do this in userNotificationCenter but its only showing default notification.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler:
I want to show notification like whats app when app is runing. Do you have any idea how to do this?
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
showUIViewController()
}
func showUIViewController() {
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "MyPage", bundle: nil)
let initialViewControlleripad : UIViewController = mainStoryboardIpad.instantiateViewController(withIdentifier: "ContactUsDetailViewController") as! ContactUsDetailViewController
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialViewControlleripad
self.window?.makeKeyAndVisible()
}
First of all, after calling showUIViewController() call the completionHandler with an empty array:
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
showUIViewController()
//1
completionHandler([])
}
1- This code will prevent the system to show the default iOS notification.
Then, Your piece of code to show custom UI for notifications like whatsapp does not make sense.
You should create a custom view and add/remove it as a subview of UIWindow instead of changing its rootViewController.
I think if you want to customize the notification when app is in foreground , I have used the third party and it's really cool and easy to implement, Check this out
https://github.com/souzainf3/RNNotificationView
I have two type of push notifications in my app Type A and Type B and according to each type I want to navigate the user to different view controls. right now the app show only the homeVC if user clicked on the
notification and can I pass value from the notifications object to the
view controls.?
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
userInfo["Type"] as? String == "TypeA" {
showNotificationA()
} else {
showNotificationB()
}
completionHandler(UIBackgroundFetchResult.newData)
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
// How to identify which notification the user clicked to navigate to the right view?
if UIApplication.shared.applicationState == .inactive {
}
completionHandler()
}
Basically, the handling of push notifications consists more or less of the following steps:
Enabling Push notifications in the capabilities section of project settings
Requesting the access to use remote and local notifications, and delegating incoming notifications to your notification observer entity (class, struct)
This is done in the AppDelegate class, in a similar manner to:
UNUserNotificationCenter
.current()
.requestAuthorization(options: [.alert, .badge]) { (granted, error) in
UNUserNotificationCenter.current().delegate = MyCustomDelegateEntity
}
Implementing the func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) in your delegate, which receives incoming notifications
Notifications can be distinguished by an identifier, which is located in the UNNotificationResponse entity. Based on the id, you can decide how to react accordingly.
In your particular case, you should instantiate a desired view controller from the NotificationDelegate in a similar manner to
let rootVC = MyViewController.instantiateFrom(storyboard: "StoryboardName")
let navigationController = UINavigationController(rootViewController: rootVC)
(UIApplication.shared.delegate as? AppDelegate)?.window?.rootViewController = navigationController
The ViewController.instantiateFrom(storyboard:) content looks something like:
return UIStoryboard(name: storyboard, bundle: nil).instantiateViewController(withIdentifier: String(describing: self)) as! MyViewController
You can redirect all your notification to one controller and in this basview controller check which notification type its came from and navigate accordingly.
You can pass data from notification payload and handle accordingly
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.
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