I was wondering how I could prompt the user with the well known 'app' wants to send you push notifications after the user has registered as a user on my app and not as the user opens my app as default (without even being a user).
How would I do this? I thought you would only configure push notification settings in the appDelegate.swift? Thanks in advance!
You can ask for permission for push notification anywhere you want, where realistically if your app has a login page, then for sure after login you need to do it.
You will need first to place the code which asks for the permission in a function in AppDelegate.swift.
func registerUserNotification() {
if #available(iOS 10.0, *) {
let authOptions : UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions, completionHandler: { (bool, error) in
UNUserNotificationCenter.current().delegate = self
if (error == nil) {
// its required for iOS 11 to avoid getting warning about "UI API called on a background thread"
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
})
} else {
if UIApplication.shared.responds(to: #selector(UIApplication.registerUserNotificationSettings(_:))) {
let types:UIUserNotificationType = ([.alert, .badge, .sound])
let settings:UIUserNotificationSettings = UIUserNotificationSettings(types: types, categories: nil)
UIApplication.shared.registerUserNotificationSettings(settings)
UIApplication.shared.registerForRemoteNotifications()
}
}
}
Note: Also don't forget to import UserNotifications to be able to use the latest SDK for iOS 10.
in any view controller you need to reference the app delegate and call that function:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.registerUserNotification()
Update 1:
You will need to implement the delegate of UNUserNotificationCenter as the following, place the following code at the end of AppDelegate out of class scope (}), this is required for iOS 10 :
#available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {
// Receive displayed notifications for iOS 10 devices.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print("Userinfo \(notification.request.content.userInfo)")
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("Userinfo \(response.notification.request.content.userInfo)")
}
}
You can go through all of the remote notification configuration outlined by Firebase but skip the steps that prompt the user with "app wants to send you push notifications". Then when your user has completed your registration process, request push notification authorization from iOS.
The following code shows the critical pieces that will display the system prompt to the user. They can be called at anytime. These are also the sames lines of code that need to be left out at app startup.
func turnOnNotifications() {
if #available(iOS 10.0, *) {
UNUserNotificationCenter
.currentNotificationCenter()
.requestAuthorizationWithOptions([.Alert, .Badge, .Sound]) { authorized, error in
}
} else {
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: .None)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
}
}
Related
I'm trying to implement push notifications with Firebase Cloud Messaging on an iOS application.
My applications uses the SwiftUI life cycle.
I followed the official documentation from Firebase documentation
But, for the moment, I'm unable to make it works. I'try a lot of things, but none of them make the job. There is somebody who sees what can be the problem?
I tested on a real device, which ask me for the notification's permission. But no one arrives...
My AppDelegate class:
import SwiftUI
import FirebaseCore
import GoogleMobileAds
import FirebaseMessaging
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: { _, _ in }
)
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
Messaging.messaging().delegate = self
GADMobileAds.sharedInstance().start(completionHandler: nil)
return true
}
}
extension AppDelegate: UNUserNotificationCenterDelegate{
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
Messaging.messaging().appDidReceiveMessage(userInfo)
// Change this to your preferred presentation option
completionHandler([[.alert, .sound]])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
Messaging.messaging().appDidReceiveMessage(userInfo)
completionHandler()
}
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
Messaging.messaging().appDidReceiveMessage(userInfo)
completionHandler(.noData)
}
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
}
}
extension AppDelegate: MessagingDelegate{
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
print("Firebase registration token: \(String(describing: fcmToken))")
let dataDict: [String: String] = ["token": fcmToken ?? ""]
NotificationCenter.default.post(
name: Notification.Name("FCMToken"),
object: nil,
userInfo: dataDict
)
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
}
#main
struct BochoGameApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
var body: some Scene {
WindowGroup {
SplashScreen()
}
}
}
I created a key on my Apple account with the Apple Push Notifications service (APNs) service enabled. After I configured the Firebase console with it.
(I erased the empty fields for the image)
I set the next capabilities
On the info.pils I set FirebaseAppDelegateProxyEnabled to false
Also, I have an App ID with the Push Notification checked
In my profile says I enable to use Push notifications.
And I set the provisioning profile on Xcode
Any idea? Any help will be appreciated
Finally, I found a solution. The official documentation suggest changing the methods if you disable swizzling, or you are building a SwiftUI application. I don't know why they suggest that, because if you keep the original methods, works....
I follow this tutorial and now push notifications arrive to my device.Excellent tutorial
Okay, now I realize that with the methods of this post works also. You only have to edit that.
completionHandler([[.banner,.badge ,.sound]]).
I am creating an app in swift which will use UNNotificationAction buttons.
I have userNotificationCenter set up properly and I can call didReceive properly while the app is open... From here I show a modal window.
The issue is that when the app is not running in foreground or background (user hasn't opened app yet) I can't get didFinishLaunchingWithOptions to parse my code when I check on launchOptions?[UIApplication.LaunchOptionsKey.remoteNotification]
Is there a new technique for processing when a user fresh opens the app when tapping on a push notification using a UNNotificationAction?
In didFinishLaunchingWithOptions, when you discover that you are launching because of a notification, set yourself as the UNUserNotificationCenter's delegate and return false. Now your didReceive implementation will be called.
Kindly Check this code below , Hope this helps.
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,CLLocationManagerDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
}
#available(iOS 10, *)
// Receive displayed notifications for iOS 10 devices.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
// With swizzling disabled you must let Messaging know about the message, for Analytics
Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// print(userInfo)
completionHandler([.alert, .badge, .sound])
// Change this to your preferred presentation option
// completionHandler([])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
switch response.actionIdentifier {
case "action1":
print("Action First Tapped")
case "action2":
print("Action Second Tapped")
default:
break
}
// Print full message.
print(userInfo)
Messaging.messaging().appDidReceiveMessage(userInfo)
completionHandler()
}
I'm doing an app that schedules local notifications and saves an userInfo. That's part its ok.
But when the app is closed, if a Notification appears and the user clicks, the method is not called and I can't handle userInfo.
I saw that there's a new way to receive a notification with UNUserNotificationCenter. But is not working too.
I've tried it that way, but I did not succeed:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
if let yourData = userInfo["yourKey"] as? String {
// Handle your data here, pass it to a view controller etc.
}
}
That's my implementation in AppDelegate:
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let lNotification = UILocalNotification()
lNotification.userInfo = response.notification.request.content.userInfo
// Handle your data here, pass it to a view controller etc.
}
Anyone, to help me? I saw all the questions related here and didn't found anything.
Have you registered for notifications?
If not, add this to AppDelegate 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")
}
})
UNUserNotificationCenter.current().delegate = self
if more than a minute pass from the time a user notification arrived to notification center, there is a "clear" option to dismiss one or more notifications at once from notification center.
How the iOS OS notify that the user tapped on "clear" to dismiss several notifications together?
Van's anwser goes straight into the right direction, but we do not need to implement the custom action to get what the question giver wanted.
If you create the category and pass it to the UNUserNotificationCenter you get a callback on the delegates didReceive function even if the user tabbed on the builtin Clear Button or the "X" Button on the content extension. The ResponeIdentifier will then be response.actionIdentifier == UNNotificationDismissActionIdentifier.
The Category must be something like that:
//Create the category...
UNNotificationCategory(identifier: "YourCustomIdentifier",
actions: [], intentIdentifiers: [], options: .customDismissAction)
//... and pass it to the UNUserNotificationCenter
UNUserNotificationCenter.current().setNotificationCategories(notificationCategories)
The category triggers the magic in the iOS framework and suddenly you get callbacks in your delegate.
The delegate function should look like:
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
if response.actionIdentifier == UNNotificationDismissActionIdentifier {
// notification has been dismissed somehow
}
completionHandler()
}
its possible from iOS 10 and above with implementation of custom notification, you will need to work with UNNotificaitons
private func registerForRemoteNotificaiton(_ application: UIApplication) {
// show the dialog at a more appropriate time move this registration accordingly.
// [START register_for_notifications]
if #available(iOS 10.0, *) {
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {(granted, error) in
if granted {
DispatchQueue.main.async(execute: {
UIApplication.shared.registerForRemoteNotifications()
})
}
})
configureUserNotification()
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
// For iOS 10 data message (sent via FCM)
Messaging.messaging().delegate = self as MessagingDelegate
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
// [END register_for_notifications]
}
private func configureUserNotification() {
if #available(iOS 10.0, *) {
let action = UNNotificationAction(identifier: UNNotificationDismissActionIdentifier, title: "Cancel", options: [])
//let action1 = UNNotificationAction(identifier: "dismiss", title: "OK", options: [])
let category = UNNotificationCategory(identifier: "myNotificationCategory", actions: [action], intentIdentifiers: [], options: .customDismissAction)
UNUserNotificationCenter.current().setNotificationCategories([category])
} else {
// Fallback on earlier versions
}
}
call registerForRemoteNotificaiton method from appdelegate's didFinishLaunching method.
Then you will need to implement UNUserNotificationCenterDelegate in appdelegate.
and then you will get the clear (here "Dismiss" as we added in action name)
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
if response.actionIdentifier == UNNotificationDismissActionIdentifier {
//user dismissed the notifcaiton:
}
completionHandler()
}
find more information here
First you should set the UNUserNotificationCenterDelegate:
import UserNotifications
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self
return true
}
then user the delegate functinos
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
switch response.actionIdentifier {
case UNNotificationDismissActionIdentifier:
// Do whatever you want to do on dismiss action, when user clear the notification
break
case UNNotificationDefaultActionIdentifier:
// Do whatever you want to do on tap action, when user tap on notification and your application will open
break
default:
break
}
}
}
I'm working on App that have push notification property. And I should enable/disable the push notification permission within my app without go to iPhone settings.
Is there a way to implement that?
I searched a lot, but I didn't find any proper way to implement it.
Any help?
If a user denied permissions for push notifications you can not let him enable it from within the app.
You could however, set a button in your settings app (ViewController), and let the user switch the notifications off and on there. Then you can set a boolean to check before sending notifications. This way a user might use it instead of disabling the app's notification permission on the device settings.
Enable Push Notification (Setup from app):
if #available(iOS 10.0, *) {
// SETUP FOR NOTIFICATION FOR iOS >= 10.0
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
if error == nil{
DispatchQueue.main.async(execute: {
UIApplication.shared.registerForRemoteNotifications()
})
}
}
}else{
// SETUP FOR NOTIFICATION FOR iOS < 10.0
let settings = UIUserNotificationSettings(types: [.sound, .alert, .badge], categories: nil)
UIApplication.shared.registerUserNotificationSettings(settings)
// This is an asynchronous method to retrieve a Device Token
// Callbacks are in AppDelegate.swift
// Success = didRegisterForRemoteNotificationsWithDeviceToken
// Fail = didFailToRegisterForRemoteNotificationsWithError
UIApplication.shared.registerForRemoteNotifications()
}
Delegate methods to handle push notifications
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// ...register device token with our Time Entry API server via REST
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
//print("DidFaildRegistration : Device token for push notifications: FAIL -- ")
//print(error.localizedDescription)
}
Disable Push Notifiacation:
UIApplication.shared.unregisterForRemoteNotifications()