iOS FCM Push notification is not receiving at the first run app - ios

I build and test an app that uses FCM, but when I run the app for the first time, I don't get a push notification. But from the second run, notifications start to come.
The procedure for the application to send the token to the server is as follows.
The application is launched.
Store the token in UserDefault.
Get informed consent.
Proceed to membership registration.
At the end of membership registration, member information and token are sent together.
Membership registration completed
As a result of the test, the situation in which notifications do not come from the app is as follows.
Run the app for the first time and proceed with membership registration. = No notification.
Run the application for the first time to complete membership registration and turn off and on the application. = A notification is coming.
Turn the application off and on several times and proceed with membership registration. = No notification.
Turn the application off and on several times, sign up for a membership, and turn the application off and on. = Notification is coming.
If i enter the home screen without a push notification, I get a notification, but the didReceive function is not executed when I touch it.
Even if the terminal is turned off and on several times, the token is sent once when registering as a member, but I really don't know why these results are coming out.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
// 앱 메세지를 받는 델리게이트
UNUserNotificationCenter.current().delegate = self
Messaging.messaging().delegate = self
application.registerForRemoteNotifications()
return true
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
messaging.token { token, _ in
guard let token = token else {
return
}
let defaults = UserDefaults.standard
defaults.set(token, forKey:"userFCMToken")
print("FIR Token : ", token)
}
}
The part of the AppDelegate that receives the FCM token. The part to receive notification consent from the user is to press a button in another ViewController.
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { success, _ in
guard success else {
print("알림 미동의")
self.registerViewPush()
return
}
print("알림 동의")
self.registerViewPush()
}
This is the part that receives notification consent when the button is pressed.
#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("willPresent App Push")
let userInfo = notification.request.content.userInfo
print("============willPresent================")
print(userInfo)
print("============================")
completionHandler([[.alert, .badge, .sound]])
}
// 사용자가 메세지를 눌렀을 때
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("didReceive ")
let userInfo = response.notification.request.content.userInfo
print("============OriginaldidReceive================")
print(userInfo)
print("============================")
completionHandler()
}
}
The FirebaseMessaging I'm using is 9.0.0 and I installed it using a pod.
[
AnyHashable("google.c.fid"): f9lzDdLFjkQpneQsfb-GxW,
AnyHashable("google.c.sender.id"): 900007830000,
AnyHashable("type"): CRING,
AnyHashable("aps"): {
alert = {
body = "message";
title = "message";
};
sound = default;
},
AnyHashable("title"): message,
AnyHashable("google.c.a.e"): 1,
AnyHashable("push"): N,
AnyHashable("body"): message,
AnyHashable("gcm.message_id"): 1657080600087000
]
If this is successful, this is what I will receive.
It's okay if the answer isn't right. I'd appreciate it if you could let me know what I should check.

If you already have latest Firebase SDK version, then you properly missing registering for remote notifications as following:
UIApplication.shared.registerForRemoteNotifications()
after requesting authorization using
func requestAuthorization(options: UNAuthorizationOptions = []) async throws -> Bool
This was my mistake. I hope other developers find this answer helpful.

Related

Periodic IOS Background execution [duplicate]

I want to make an app that makes HTTP request to a website periodically. The app has to run in the background, but can wake up or show a notification, depending on a response of request. Like a message of WhatsApp, but I don't have a webserver, only the device check values of the http get request.
The only way to do that is using a Silent push notification(see the Docs HERE and HERE), it will wake up your app on background and give you a chance to execute some code for a bit of time. But unfortunately it wont work with local notification, need to be a push notification.
Obs: Note that your time is limited to execute the background task, as the doc says
Your app has 30 seconds to perform any tasks and call the provided completion handler
And if you send too much push, the iOS can punish your application by giving it a small priority to execute your task, or even simply don't executing it
If you use silent push notification, you should know that silent push have some limit for frequency send.
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns
Check to see if silent notifications are being throttled. APNs sends a
limited number of silent notifications—notifications with the
content-available key—per day. In addition, if the device has already
exceeded its power budget for the day, silent notifications are not
sent again until the power budget resets, which happens once a day.
These limits are disabled when testing your app from Xcode.
And don't get to application if application force-quit.
If you need guaranteed delivery, you should use VoIP push notification.
But you need reason for Apple, why you need VoIP push.
But you're way drain battery non stop, and it not friendly for you're users.
It's Possible using Silent Push notifications ,you can this answer.
import Firebase
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var dataManager = DataManager()
var reloadSign = false;
let gcmMessageIDKey = "gcm.message_id"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions:
[UIApplicationLaunchOptionsKey: Any]?) -> Bool {
Fabric.with([Crashlytics.self])
// Override point for customization after application launch.
IQKeyboardManager.shared.enable = true
DropDown.startListeningToKeyboard()
FirebaseApp.configure()
Messaging.messaging().delegate = self
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
// //Solicit permission from user to receive notifications
UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { (_, error) in
guard error == nil else{
print(error!.localizedDescription)
return
}
}
//
// //get application instance ID
InstanceID.instanceID().instanceID { (result, error) in
if let error = error {
print("Error fetching remote instance ID: \(error)")
} else if let result = result {
print("Remote instance ID token: \(result.token)")
}
}
application.registerForRemoteNotifications()
return true
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
let proj = Project()
proj.checkData()
}
// Print full message.
print(userInfo)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Unable to register for remote notifications: \(error.localizedDescription)")
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
let ud = UserDefaults.standard
ud.set( true, forKey: "isTerminated");
ud.synchronize()
}
func crashlyticsDidDetectReport(forLastExecution report: CLSReport, completionHandler: #escaping (Bool) -> Void) {
completionHandler(true)
}
}
extension AppDelegate: UNUserNotificationCenterDelegate{
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 full message.
print(userInfo)
// 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)")
}
// Print full message.
print(userInfo)
completionHandler()
}
}
extension AppDelegate: MessagingDelegate{
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(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.
}
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print("Received data message: \(remoteMessage.appData)")
}
}

Swift iOS app receive push notification when app is inactive and run code

Platform
Swift 5
iOS 13+
xCode 11
Node v14.2.0
Firebase/Firestore latest
Setting
Alice send push notification to Bob, while Bob's phone is .inactive or .background. Bob's phone should get notification and immediately trigger code.
Problem
This question has plenty of answers, but most of what I can find revolves around hacking the PushKit and CallKit native API to send .voIP pushes. Per this question (iOS 13 not getting VoIP Push Notifications in background), Apple no longer allow you to send .voIP pushes w/o triggering CallKit's native phone ring routine.
On iOS side, I have the following bits in AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
registerForPushNotifications()
}
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void)
{
print(">>> I would like this to be triggered even if the app is asleep")
switch application.applicationState {
case .active:
print(">>>>>>> the app is in [FOREGROUND]: \(userInfo)")
break
case .inactive, .background:
print(">>>>>>>> the app is in [BACKGROUND]: \(userInfo)")
break
default:
break
}
}
func registerForPushNotifications() {
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter
.current()
.requestAuthorization(options:[.alert, .sound, .badge]) {[weak self] granted, error in
guard granted else { return }
self?.getNotificationSettings()
}
}
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { settings in
guard settings.authorizationStatus == .authorized else { return }
Messaging.messaging().delegate = self
DispatchQueue.main.async {
// Register with Apple Push Notification service
UIApplication.shared.registerForRemoteNotifications()
/// cache token client side and save in `didRegisterForRemoteNotificationsWithDeviceToken`
if let token = Messaging.messaging().fcmToken {
self.firebaseCloudMessagingToken = token
}
}
}
}
//#Use: listen for device token and save it in DB, so notifications can be sent to this phone
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
if (firebaseCloudMessagingToken != nil){
self.updateMyUserData(
name : nil
, pushNotificationToken: firebaseCloudMessagingToken!
)
}
}
func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
///print(">>> Failed to register: \(error)")
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
// #NOTE: this fires when the app is open. So you can go the call screen right away
let payload = notification.request.content.userInfo as! [String:Any?]
let type = payload["notificationType"]
print(">> this fires if the app is currently open")
}
/// #NOTE: we are using backward compatible API to access user notification when the app is in the background
/// #source: https://firebase.google.com/docs/cloud-messaging/ios/receive#swift:-ios-10
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
print(" this fires when the user taps on the notification message")
}
On the server/Node.js side, I send push notification this way:
// Declare app push notification provider for PushKit
const _ApnConfig_ = {
token: {
key : fileP8
, keyId : "ABCDEFG"
, teamId: "opqrst"
},
production: false
};
var apnProvider = new apn.Provider(_ApnConfig_);
exports.onSendNotification = functions.https.onRequest((request, response) => {
var date = new Date();
var timeStamp = date.getTime();
const deviceTok = "..."
var recepients = [apn.token( deviceTok )]
const notification = new apn.Notification();
notification.topic = "com.thisisnt.working"
notification.body = "Hello, world!";
notification.payload = {
from: "node-apn"
, source: "web"
, aps: {
"content-available": 1
, "data" : { "custom_key":"custom value", "custom_key_2":"custom value 2" }
}
};
notification.body = "Hello, world # " + timeStamp;
return apnProvider.send(notification, recepients).then(function(res) {
console.log("res.sent: ", res.sent)
console.log("res.failed: ", res.failed)
res.failed.forEach( (item) => {
console.log(" \t\t\t failed with error:", item.error)
})
return response.send("finished!");
}).catch( function (error) {
console.log("Faled to send message: ", error)
return response.send("failed!");
})
})
Both are pretty standard. I have set the content-availabe to 1. Right now the messages are coming through and displayed by Apple Push Notification center, they're just not triggering the block with didReceiveRemoteNotification as intended.
You need to enable the background mode - remote notifications capability.
To receive background notifications, you must add the remote notifications background mode to your app. In the Signing & Capability tab, add the Background Modes capability, then select the Remote notification checkbox.
Enabling the remote notifications background mode:
For watchOS, add this capability to your WatchKit Extension.
Source: Pushing Background Updates to Your App | Apple Developer Documentation

Notification from Firebase stopped appearing on iOS

Last night I was testing Push Notifications from Firebase in my iOS app, and it was working as expected
I was able to send a notification from at Cloud Function to a specific FCM token.
This morning notification doesn't arrive when using the same method.
Cloud Function
Here's the function that I use to send the notification:
function sendNotification(title: string, body: string, token: string): Promise<void> {
const message: admin.messaging.Message = {
apns: {
headers: {
'apns-priority': '10'
},
payload: {
aps: {
alert: {
title: title,
body: body,
},
sound: "default"
}
}
},
token: token
}
return admin.messaging().send(message).then(response => { console.log(`Notification response ${response}`) }).then(justVoid)
}
Here token is the token I received from the InstanceId in the iOS app.
When this function is triggered, I see the following in Firebase web console's Cloud Function log:
Notification response projects/project-name/messages/0:1571998931167276%0f7d46fcf9fd7ecd
Which, as far as I understand, is a success message. So I'm expecting the notification to show up on the device at this point, but nothing.
iOS App
I've followed this guide to troubleshoot, and am sure that the setup is right: https://firebase.google.com/docs/cloud-messaging/ios/first-message?authuser=0
I did try to re-install the app on the device on which Im testing: I've verified that the app does through these step after re-install:
call: UNUserNotificationCenter.current().requestAuthorization(options:, completionHandler:)
call: UIApplication.shared.registerForRemoteNotifications()
listen to updated FCM token by implementing: func messaging(_ messaging:, didReceiveRegistrationToken fcmToken:)
call: InstanceID.instanceID().instanceID(handler:)
double check that notifications is allowed for my application in the iOS settings app.
Test Notification from console
I've tried sending a Test Notification in from Notification Composer, using a the recent FCM token for the test device, but this notification doesn't show up either, and it doesn't give me any feedback on screen whether the notification is successfully sendt or not.
What am I doing wrong here?
Any Suggestions to how I can debug this issue?
When we are working with Push Notification then it is very harder to debug issue.
As per my experience, there is nothing wrong with your typescript or iOS code because earlier it was worked perfectly. Below is the possible reason if the push notification is not working.
Generally, the APNS related issue occurs due to the certificate.
Make sure you are uploading the correct APNS profile to the firebase
console for both development and release mode.
Make sure you have enabled the notification in capabilities.
Your Project -> capabilities -> turn on Push Notifications
Make sure you're added correct GoogleService-Info.plist to the
project.
APNS Certificate is not expired.
Make sure you're using the latest version of the firebase.
Your device time should be automatic, not feature time.
If you still think it is code related issue and the above solution is not working then you can go with the below wrapper class of HSAPNSHelper class which is created by me and it is working for iOS 10 and later .
import Foundation
import UserNotifications
import Firebase
class HSAPNSHelper: NSObject {
static let shared = HSAPNSHelper()
let local_fcm_token = "local_fcm_token"
var notificationID = ""
func registerForPushNotification(application:UIApplication){
FirebaseApp.configure()
self.getFCMToken()
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound]) { (granted, error) in
DispatchQueue.main.async {
self.getFCMToken()
}
}
application.registerForRemoteNotifications()
}
}
extension HSAPNSHelper:UNUserNotificationCenterDelegate {
fileprivate func getFCMToken() {
InstanceID.instanceID().instanceID(handler: { (result, error) in
if error == nil, let fcmToken = result?.token{
print("FCM Token HS: \(fcmToken)")
UserDefaults.standard.set(fcmToken, forKey: self.local_fcm_token)
}
})
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("didFailToRegisterForRemoteNotificationsWithError : \(error)")
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
var token = ""
for i in 0..<deviceToken.count {
token = token + String(format: "%02.2hhx", arguments: [deviceToken[i]])
}
Messaging.messaging().apnsToken = deviceToken
getFCMToken()
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo as! [String: Any]
print(userInfo)
completionHandler([.alert, .badge, .sound])
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
print(userInfo)
self.notificationRedirection()
}
private func notificationRedirection(){
}
func fcmToken() -> String{
return UserDefaults.standard.string(forKey:local_fcm_token) ?? ""
}
}
How to use?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//For Push notification implementation
HSAPNSHelper.shared.registerForPushNotification(application: application)
return true
}
Use fcmToken() to get current FCM token.

Show fcm notification if meet a condition with swift

I am using firebase push notification, where my app is subscribed to a topic, all is good. But I want to know if it is possible to show the notification if pass a notification. this is my scene:
local_user_id = 10
var payload = {
notification: {
title: "hi",
body: "this is a notification",
sound: "default"
},
data: {
user_id: "1",
message: "you should pay $3020.25"
}
};
1) control if user is_login (true/false)
2)get the message data of notification and check:
if (payload.data.user_id = local_user_id && is_login){
show_notification()
}
3) show notification
Actually I only have the notification and no more, I am new with firebase, this is my code:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
(granted, error) in
}
application.registerForRemoteNotifications()
FirebaseApp.configure()
return true
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
let dict = userInfo["aps"] as! NSDictionary
let message = dict["alert"]
print("response")
print(message)
}
I don't know how to do that what I want, is it posible?
thanks in advance
You can not control show hide notification in your application. You can put some logic on the backend side, whether this notification should be displayed or not. Nevertheless, I have workaround below possible way.
Use a silent push. Then trigger local notifications. Note: Silent
push isn't always reliable.
So just include content-available: 1 in your payload as shown
below to get a silent notification.it will act as silent notification.
Also in Info.plist should have UIBackgroundModes set to
remote-notification
but it'll be limited to Running and background mode only. you won't be able to receive or handle it if content-available is set to 0 while your app is offline
If you are trying to just present the notification to the user while the app is running in the foreground, you would need to have your AppDelegate conform to the UNUserNotificationCenterDelegate. This is because when the application is running, the notifications will be presented to the UNUserNotificationCenter shared object.
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void {
let content = notification.request.content
if content.data["user_id"] == local_user_id && is_login {
completionHandler(.alert)
} else {
completionHandler([])
}
}
}
You would want to make sure that the completionHandler is executed at some point in this block, because this is the handler that does the presentation of the notification. If you want a silent notification, you can use completionHandler([]) to silence the alert. Other possible options for the completionHandler are available here.

Apple Push Notifications (APN) Inconsistency?

We are running into a confusing issue when using Apple's Push Notifications via APN. We have the following scenario (quite standard i guess):
When our App, let's call it "MyApp" here, is installed and started for the first time we are asking the user for permissions to send him Push Notifications through "MyApp".
In this example the AppDelegate looks like this:
import UIKit
import UserNotifications
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Register Remote Notifications
UNUserNotificationCenter.current().delegate = self
self.registerForPushNotifications()
return true
}
// MARK: - Remote Notifications
func registerForPushNotifications() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
guard granted else {
return
}
self.getNotificationSettings()
}
}
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
guard settings.authorizationStatus == .authorized else {
return
}
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
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("ApnToken: \(token)")
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("did Fail to Register for RemoteNotifications")
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print("willPresentNotification!")
completionHandler([.badge, .sound, .alert])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("UserDidResponseToNotification!")
completionHandler()
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("DidReceiveRemoteNotification!")
completionHandler(.newData)
}
}
So the user installs and the starts the app and is asked if "MyApp" is allowed to send the user Push Notifications. If the user accepts the Push Notifications application(_:didRegisterForRemoteNotificationsWithDeviceToken:) is called and we give the received deviceToken to our API.
Now the part that confuses me:
The user also has the option to turn Push Notifications off later via the iPhone-Settings like this: Settings > "MyApp" > Notifications > Allow Notifications > Turns the Switch off
Our API has now the deviceToken for APN but the user turned Push Notifications off via iPhone-Settings.
The "problem":
After the user turned off Push Notifications we are still able to send silent Push Notifications to the device and "MyApp" gets the data correct without any problems.
But in the other scenario: The User installs and starts "MyApp" and declines at the first start Push Notifications it is not possible to get a deviceToken from Apple. I tried to get a deviceToken from Apple even if the user declined the Push Notification Alert like this: (But this doesn't work - I guess Apple doesn't provide my any if the user declines)
func registerForPushNotifications() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
self.getNotificationSettings()
}
}
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
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("ApnToken: \(token)")
}
It seems like it doesn't matter what the user does if he accepts Push Notifications at the first start. I mean ok, we cannot show the Information via Banner or anything to the user but we can transfer data to the device using APN's even if the user did turn off this setting at a later time. (But we cannot send anything if he declines at start of the app - we need a deviceToken once)
Am i misunderstanding a thing here? This seems inconsistent to me.
I tried to clarify my question so everyone can understand what i am asking for. Excuse my "bad" english it is not easy as a non-native-speaker to ask specific questions with a lot of context here. Anyway, if you need further informations or you didn't understand one or more points from what i am asking let me know i will provide detailed informations and will clarify my question.
I don't know if this matters but at the moment we are using an APN-Development-Certificate (not a distribution certificate yet)
Good question,
The thing is that if user allows you to send push notification (gives you his/her device token) you would be able to send pushes. The push data via notification could be send without notification for a user (silence notification) you could read more about it here: https://medium.com/#m.imadali10/ios-silent-push-notifications-84009d57794c
That's why you are able to send push even if user prevents notification from displaying. That settings controls only displaying appearance, but since he/she gives you the token you still could send data to them. There actually no way for a user to disable that token after it was granted.

Resources