The request for notification permission pop up will appear and then I'll press allow and all that, but none of the delegate functions (didFailToRegisterForRemoteNotificationsWithError or didRegisterForRemoteNotificationsWithDeviceToken work, and I'm testing on a real device...). I've enabled push notifications in Signing & Capabilities and have registered through Apple Developer for the cert and saved it to my keychain. Any help would be appreciated!
#main
struct Sparrow_NavigationApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
RootView {
ContentView()
}
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
UNUserNotificationCenter.current()
.requestAuthorization(
options: [.alert, .sound, .badge]) { granted, _ in
print("Permission granted: \(granted)")
guard granted else { return }
UNUserNotificationCenter.current().getNotificationSettings { settings in
print("Notification settings: \(settings)")
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
}
return true
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
guard let aps = userInfo["aps"] as? [String: AnyObject] else {
completionHandler(.failed)
return
}
print("got something, aka the \(aps)")
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("device token")
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Device Token not found.")
}
}
https://i.stack.imgur.com/MkfDh.png
https://i.stack.imgur.com/dABWZ.png
Related
I have this code that asks the user to allow my app to receive push notes.
The permission part of it works fine but I never get a device token or any error after I allow the app to receive push notifications.
This is my AppDelegate file:
class AppDelegate: UIResponder, UIApplicationDelegate{
var window: UIWindow?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions
launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
registerForPushNotifications()
let notificationOption = launchOptions?[.remoteNotification]
if
let notification = notificationOption as? [String: AnyObject],
let aps = notification["aps"] as? [String: AnyObject] {
(window?.rootViewController as? UITabBarController)?.selectedIndex = 1
}
return true
}
func registerForPushNotifications() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
print("Permission granted: \(granted)")
guard granted else { return }
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
print("Notification settings: \(settings)")
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
}
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
print("Notification settings: \(settings)")
}
}
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { data -> String in
return String(format: "%02.2hhx", data)
}
let token = tokenParts.joined()
print("Device Token: \(token)")
}
func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register: \(error)")
}
}
I've tried different variations of the same code and still getting no device token. Ive enabled the Push notifications in my project in Xcode and I restarted the my device a few times too.
EDIT:
The didRegisterForRemoteNotificationsWithDeviceToken and didFailToRegisterForRemoteNotificationsWithError are never called for some reason!
Because I am not getting any error or device token at all!
I am following the push notification tutorial here:
https://www.raywenderlich.com/11395893-push-notifications-tutorial-getting-started
I've gotten everything working on a test device, and after allowing notifications, I can get the device token when didRegisterForRemoteNotificationsWithDeviceToken runs.
Now I want to change when I ask for notification permissions. I don't want to ask the user permission for notifications on app launch, as in the tutorial. I only want to ask later on, once the user has logged in. However, when I call the AppDelegate to register for notifications, it prompts the user, but when they accept, it doesn't run the didRegisterForRemoteNotificationsWithDeviceToken function, which has the device token I need to send to my back end. What gives?
AppDelegate.swift
import SwiftUI
import UserNotifications
class AppDelegate: NSObject, UIApplicationDelegate {
#EnvironmentObject var authenticatedUser: AuthenticatedUser
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
return true
}
func registerForPushNotifications() {
UNUserNotificationCenter.current()
.requestAuthorization(
options: [.alert, .sound, .badge]) { [weak self] granted, _ in
print("Permission granted: \(granted)")
guard granted else { return }
self?.getNotificationSettings()
}
}
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { settings in
print("Notification settings: \(settings)")
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
// this function never gets called!
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")
// send token to backend here
}
func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error
) {
print("Failed to register: \(error)")
}
}
MyGroupView.swift where I want to prompt for notification permission
import SwiftUI
struct MyGroupView: View {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
#EnvironmentObject var authenticatedUser: AuthenticatedUser
// other variables and state here...
var body: some View {
GeometryReader { proxy in
VStack {
// content here...
}
.onAppear() {
appDelegate.registerForPushNotifications()
}
.edgesIgnoringSafeArea(.bottom)
}
}
// other functions...
}
In your AppDelegates didFinishLaunchingWithOptions you need to set the delegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
UNUserNotificationCenter.current().delegate = self
return true
}
My app has push notifications enabled, and up until today they were working properly. From setting breakpoints I've realized that the issue is that didRegisterForRemoteNotificationsWithDeviceToken is no longer being called. This is confusing to me as my notifications code hasn't change since when it was working (yesterday). Here is what my AppDelegate looks like:
import UserNotifications
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
registerForPushNotifications()
return true
}
func registerForPushNotifications() {
UNUserNotificationCenter.current()
.requestAuthorization(options: [.alert, .sound, .badge]) {
[weak self] granted, error in
print("Permission granted: \(granted)")
guard granted else { return }
self?.getNotificationSettings()
}
}
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { settings in
print("Notification settings: \(settings)")
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")
global_device_token = token
}
The call to UIApplication.shared.registerForRemoteNotifications() in getNotificationSettings does get run however.
I created a simple empty iOS application with XCode 11.5.
With my device iOS 13.5.1, I am tying to implement push notifications but I dont receive the device push token or any error.
What am I doing wrong?
The method didRegisterForRemoteNotificationsWithDeviceToken is never called.
With following code:
import UIKit
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
registerForRemoteNotification()
return true
}
func registerForRemoteNotification() {
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
print("Authorization executed")
}
UIApplication.shared.registerForRemoteNotifications()
}
else {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.sound, .alert, .badge], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")
}
func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register: \(error)")
}
}
I have following output in the console:
Requesting permission
2020-06-06 12:13:23 +0000
Authorization executed
Requesting permission
2020-06-06 12:13:24 +0000
...
...
...
Screenshot:
Before trying this, make sure you have added this Capabilities...
under 'Capabilities', (next to General),
- Push Notifications option is turned ON`
- and under Background Modes, Remote Notifications is turned ON
For me it took like 6 hours after I recived all tokens that I requested. It really can take a long time sometimes
Import the UserNotifications framework and add the UNUserNotificationCenterDelegate in AppDelegate.swift
Request user permission
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization.
}
notificationCenter.delegate = self
application.registerForRemoteNotifications()
return true
}
Getting device token
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
{
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print(deviceTokenString)
}
In case of error
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("i am not available in simulator \(error)")
}
In case if you need to know the permissions granted
UNUserNotificationCenter.current().getNotificationSettings(){ (settings) in
switch settings.soundSetting{
case .enabled:
print("enabled sound setting")
case .disabled:
print("setting has been disabled")
case .notSupported:
print("something vital went wrong here")
}
}
On Receiving notification following delegate will call:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
println("Recived: \(userInfo)")
//Parsing userinfo:
var temp : NSDictionary = userInfo
if let info = userInfo["aps"] as? Dictionary<String, AnyObject>
{
var alertMsg = info["alert"] as! String
var alert: UIAlertView!
alert = UIAlertView(title: "", message: alertMsg, delegate: nil, cancelButtonTitle: "OK")
alert.show()
}
}
In your case, I think you need to replace:-
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
with,
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
I am downloading my events in background mode, for that I will receive a push and a silent Notification. As I have to download data when my app is in background mode, so I am using silent notification for downloading data through a web service and before that I am updating applicationIconBadgeNumber based on an increment value. When I am updating applicationIconBadgeNumber with my auto increased value all my push notifications are getting cleared in notification center. If I am not setting any applicationIconBadgeNumber they are remaining same. As I have posted my code below, please do let me know if I am missing out something.
var autoIncrementForNotification:Int = 0
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UIApplication.shared.setMinimumBackgroundFetchInterval(60)
if #available(iOS 10, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {(accepted, error) in
if !accepted {
print("Notification access denied.")
} else {
application.registerForRemoteNotifications()
}
}
} else {
application.registerForRemoteNotifications(matching: [.badge, .sound, .alert])
}
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
UserDefaults.standard.removeObject(forKey: "Device_Token")
UserDefaults.standard.setValue(deviceTokenString, forKey: "Device_Token")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Swift.Void){
let aps = userInfo["aps"] as! [String: AnyObject]
if ((aps["content-available"] as? NSString)?.integerValue == 1)
{
let type = (aps["type"] as? NSString)
if(type == Constants.action_type_Events)
{
if (application.applicationState == .inactive || application.applicationState == .background)
{
autoIncrementForNotification += 1
application.applicationIconBadgeNumber = autoIncrementForNotification
// Firing my Web service
completionHandler(UIBackgroundFetchResult.newData)
}
}
}
}
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void){
completionHandler(UIBackgroundFetchResult.newData)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("i am not available in simulator \(error)")
}
func applicationDidBecomeActive(_ application: UIApplication) {
application.applicationIconBadgeNumber = 0
autoIncrementForNotification = 0
}
Please try the following :
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void){
var contentAvailable: Int
let aps = userInfo["aps"] as! [String: AnyObject]
if let content = aps["content-available"] as? String {
contentAvailable = Int(content)!
} else {
contentAvailable = aps["content-available"] as! Int
}
if (contentAvailable == 1)
{
let type = (aps["type"] as? NSString)
if(type == Constants.action_type_Events)
{
if (application.applicationState == .inactive || application.applicationState == .background)
{
autoIncrementForNotification += 1
application.applicationIconBadgeNumber = autoIncrementForNotification
// Firing my Web service
completionHandler(UIBackgroundFetchResult.newData)
}
}
}
}
Reason :
If your Payload file is like this {"aps":{"content-available":1}} below condition is not satisfying, so everytime applicationIconBadgeNumber is becoming 0
if ((aps["content-available"] as? NSString)?.integerValue == 1)
If your Payload file is like this {"aps":{"content-available":"1"}} then your code will work fine.