Two functions to request APNs device token - ios

There are now two functions to request push token, the new one for location pushes (https://developer.apple.com/documentation/corelocation/cllocationmanager/3746837-startmonitoringlocationpushes):
func startMonitoringLocationPushes(completion: ((Data?, Error?) -> Void)? = nil)
and the old one for alerts, backround notifications etc. (https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622958-application):
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
Will both of them return the same device token?

Related

How can I update users FCM token if their current one no longer works?

I discovered an issue with my application, certain users stopped receiving push notifications for awhile. Their FCM token that is associated with their account seems to either have expired or they need a new one. I tested by deleting the app on my device and I was issued a new fcm token in Xcode.
I copied that FCM token from the Xcode console and manually replaced it with the one I had in Firebase database, I then was able to successfully receive push notifications.
My question, is it possible to renew current users FCM token when they sign back into/ or open the app again so they can receive push notifications successfully?
Here is my app delegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
attemptRegisterForNotifications(application: application)
Messaging.messaging().delegate = self
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("Registered for notifications", deviceToken)
Messaging.messaging().apnsToken = deviceToken
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Registered with FCM with token:", fcmToken)
}
// Listen for user notifcations
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(.alert)
}
private func attemptRegisterForNotifications(application: UIApplication) {
print("Attempting to register APNS...")
UNUserNotificationCenter.current().delegate = self
let options: UNAuthorizationOptions = [.alert, . badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: options) { (granted, error) in
if let error = error {
print("Failed to request auth:", error)
return
}
if granted {
print("Auth granted.")
} else {
print("Auth denied")
}
}
application.registerForRemoteNotifications()
}
You don't need to manually "renew" a device token (in fact, there's no way to force that). Instead, you should expect that the device token can change at any time. Because your app might unexpectedly get a new token, you should record that token for the user every time your app launches. The old token will no longer work, and your server code should check for failure in order to know when it's time to remove it.
You want to use the Firebase Messaging delegate FIRMessagingDelegate to handle updates to the FCM token. Ideally, you want to handle this on app launch, so consider doing this in the App Delegate:
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Messaging.messaging().delegate = self
return true
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
if let userId = Auth.auth().currentUser?.uid { // user is signed in
Firestore.firestore().collection("userProfiles").document(userId).updateData(["fcmToken": fcmToken]) { (error) in
if let error = error {
print(error)
}
}
}
}
}
You need to update your users token in your servers database in every app launch, so you always have the latest token.
You would have to manage what user is associated to the token yourself. When the user signs in you should associate the token with the user's ID and when the user signs out you should remove that association.

Ios Push notifications Solution

New to swift coding!
Need some help with Push Notification.
I just implemented the push notification in my app.
I have a Device token id, key id and the software which I am using is Push notification Tester.
My question is once I upload my app on the store will I able to trigger the notification to all the users through the tester app or do I need to write a script for that??
Any help is appreciated!!
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)")
}

didRegisterForRemoteNotificationsWithDeviceToken only called if user allows push notifications

Currently the callback didRegisterForRemoteNotificationsWithDeviceToken is only being called when the users clicks 'allow' after UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .alert, .sound]){ (granted, error) in } is called.
I believe there should be a way to always get the users APN token, but currently I am only getting it if the user allows push notifications. Is there a way to always get the APN token even if the user does not allow?
The intention is to user the token for silent notifications even if they did not allow notifications to be displayed
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
firstLaunchCheck()
UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .alert, .sound]){ (granted, error) in }
application.registerForRemoteNotifications()
return true
}
// Called when APNs has assigned the device a unique token
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Convert token to string
let passedTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
//store token in db
print("APNs device token: \(passedTokenString)")
}
Managed to figure this out after hours of frustration. I simply had to enable "Remote notifications" under Background Modes in the capabilities sections of Xcode
Now I get the APN token regardless if user allows push notifications or not

Push notification cheat inside app

I want to create cheat for the tester to check the push notification. I have a working example from a web link and it's working. I hit the same web-link inside the app and received the success response but no notification. The Same thing is working from a web browser.
eg. I have API suppose www.example.com/send/notif/44 to send the notification to my iPhone 6 and I am calling it from my app dashboard screen notify button.
Please help.
You have to initialize 3 methods to receive remote notifications.
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
<#code#>
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
<#code#>
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
<#code#>
}
If app is in foreground, it still receives push notification but not any banner is displayed by the OS. So, a tester should go to background immediately when they push that test button.

Receiving Push Notifications on Swift with AWS Mobile Hub

I am currently developing and iOS app using Swift, which I am new to, and the code generated from AWS Mobile Hub, with AWS SNS to register devices and send notifications.
On my class AWSMobileClient I have the following code:
func didFinishLaunching(_ application: UIApplication, withOptions launchOptions: [AnyHashable: Any]?) -> Bool {
print("didFinishLaunching:")
// Register the sign in provider instances with their unique identifier
AWSSignInProviderFactory.sharedInstance().register(signInProvider: AWSFacebookSignInProvider.sharedInstance(), forKey: AWSFacebookSignInProviderKey)
var didFinishLaunching: Bool = AWSIdentityManager.default().interceptApplication(application, didFinishLaunchingWithOptions: launchOptions)
didFinishLaunching = didFinishLaunching && AWSPushManager(forKey: ServiceKey).interceptApplication(application, didFinishLaunchingWithOptions: launchOptions)
if (!isInitialized) {
AWSIdentityManager.default().resumeSession(completionHandler: { (result: Any?, error: Error?) in
print("Result: \(result) \n Error:\(error)")
}) // If you get an EXC_BAD_ACCESS here in iOS Simulator, then do Simulator -> "Reset Content and Settings..."
// This will clear bad auth tokens stored by other apps with the same bundle ID.
isInitialized = true
}
return didFinishLaunching
}
Which is called normally.
On my AppDelegate, I have the following:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
AWSMobileClient.sharedInstance.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
NotificationCenter.default.post(name: Notification.Name(rawValue: AWSMobileClient.remoteNotificationKey), object: deviceToken)
print("###--- DID REGISTER FOR REMOTE NOTIFICATION ---###")
}
Which is also called.
However, when I try sending a notification using AWS SNS, my function:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("###--- DID RECEIVE REMOTE NOTIFICATION ---###")
AWSMobileClient.sharedInstance.application(application, didReceiveRemoteNotification: userInfo , fetchCompletionHandler: completionHandler)
// This is where you intercept push notifications.
if (application.applicationState == .active) {
UIAlertView.init(title: "Notification Received", message: userInfo.description, delegate: nil, cancelButtonTitle: "OK").show()
}
}
Is never called.
Looking for a solution I read that since iOS 10 there are some chances that need to be made to deal with push notification, but I'm not sure about the correct ways.
How should I implement the code to receive the notifications?

Resources