Looked at past questions about this but the answers to those have already been applied to my project but the pushRegistry() delegate method isn't getting invoked.
First here's the code:
import UIKit
import PushKit
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate{
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let notificationSettings = UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil)
application.registerUserNotificationSettings(notificationSettings)
UNUserNotificationCenter.current().delegate = self
UIApplication.shared.registerForRemoteNotifications()
let voipRegistry = PKPushRegistry(queue: DispatchQueue.main)
voipRegistry.desiredPushTypes = Set([PKPushType.voIP])
voipRegistry.delegate = self;
return true
}
...
}
extension AppDelegate: PKPushRegistryDelegate {
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
NSLog("voip token: \(pushCredentials.token)")
}
The following app capabilities have been enabled:
- Push Notifications
- Background Modes
- Background Fetch
- Remote Notifications
I'm using Xcode 9.1 Beta which no longer has Voip as an explicit capability, apparently this is no longer needed and importing PushKit should suffice.
On the provisioning portal Push Notifications have been enabled for the app id.
(A Void Push cert has been generated but obviously can't use this to send the pushes yet)
apparently this is no longer needed and importing PushKit should suffice.
I read a couple of posts saying this but its not correct.
In order to get things working I had to manually edit the info.plist to add voip to the list of background modes.
<string>voip</string>
What are Apple playing at? Why have they removed this as a capability from Xcode if its still required?
Related
I have looked at all questions about this but the answers to those have already been applied to my project but the pushRegistry() delegate method isn't getting invoked.
First here's the code:
import UIKit
import PushKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
print("App Launched");
self.registerVoIPPush();
return true
}
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
print("didUpdate");
print(pushCredentials);
print(type);
if type == PKPushType.voIP {
let tokenData = pushCredentials.token
let voipPushToken = String(data: tokenData, encoding: .utf8)
print(voipPushToken);
//send token to server
}
}
func registerVoIPPush() {
print("registerVoIPPush");
let voipPushResgistry = PKPushRegistry(queue: DispatchQueue.main)
voipPushResgistry.delegate = self
voipPushResgistry.desiredPushTypes = [PKPushType.voIP]
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {
print(payload);
ATCallManager.shared.incommingCall(from: "jane#example.com", delay: 0)
}
}
I have also enabled following app capabilities: - Push Notifications -
Background Modes - Background Fetch - Remote Notifications - Voice
Over IP
I'm using Xcode11.3 & building using iOS13.2
On the provisioning portal Push Notifications have been enabled for the app id. (A VoIP Push cert has been generated & imported into keychain access as well but obviously can't use this to send the pushes yet).
Any help at all would be highly appreciated as I am trying to get this done since last 3 days.
Your PKPushRegistry object is deallocated as soon as registerVoIPPush() method is finished
Check if you set up appropriate background mode
I am setting up Firebase Cloud Messaging to send notifications to an iOS app.
And I want to be able to send notifications, to all users who accepted to receive them.
After reading and experimenting quite a bit, my understanding is that (for my use case) I should set up some kind of general topic and then send each notification to this topic.
My question is: how to create a topic first, and then how to register (a client) to a topic in my iOS Swift app?
Though I tried to browse the net for info on that, I did not find much.
For information, I am using Xcode Version 10.1, iOS 12.1 and Swift 4.2.
Step 1: Setting Up Firebase
If you have yet to add Firebase to your project, it's all documented here:
https://firebase.google.com/docs/ios/setup
You will need to start the configuration of Firebase. For my project, I started the configuration in the AppDelegate upon app start.
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
Messaging.messaging().delegate = self
...
}
...
}
Step 2: Requesting Authorization
Assuming you have all the APNs Authentication Key/Certificates configured on your Apple Developer Portal and Firebase Cloud Messaging settings,
https://developer.apple.com/account/ios/certificate/
https://console.firebase.google.com/u/0/project/FIREBASE_PROJECT_NAME/settings/cloudmessaging/ios:APP_BUNDLE_ID
Next, you will need to request authorization for Push Notifications on the device. I've placed this in one of the first few UIViewControllers my project.
class FirstViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound], completionHandler: { (success, error) in
guard success else { return }
UIApplication.shared.registerForRemoteNotifications()
})
}
}
Step 3: Device Token
Upon registering for remote notification in step 2 with:
UIApplication.shared.registerForRemoteNotifications()
You will need to implement this delegate function in your AppDelegate:
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate {
...
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
}
...
}
Do note that the deviceToken received is in NSData, and the apnsToken required by Firebase is in String.
Step 4: Topic Subscription
Remember the delegate reference we set to AppDelegate in step 1?
Messaging.messaging().delegate = self
You will need to implement its delegate function to let the app know that it Firebase did receive the token and it is ready to subscribe to a topic.
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate {
...
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
Messaging.messaging().subscribe(toTopic: "/topics/example")
}
...
}
Step 5: Validation
One simple way to check if your app has successfully subscribed to a topic is to send a push notification via Firebase Console.
https://console.firebase.google.com/u/0/project/FIREBASE_PROJECT_NAME/notification
I use Firebase to send Notification with my iOS app, I have followed all step in documentation :
Apple Developer Account Configuration
Generating a CSR file
Uploading CSF file
Preparing the APNs Certificate
Configuring Firebase for Push Notifications
Building the Firebase Notification in my app
When I try to send a Notification there isn't no problem found in Firebase, for one particular user or for all iOS device. But none of my device (real device obviously) receive notification.
I use the good Bundle, I enable notification in my application and there is the code in my AppDelegate :
import UIKit
import UserNotifications
import Firebase
import FirebaseInstanceID
import FirebaseMessaging
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UINavigationBar.appearance().barTintColor = Design.blue_es
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName:UIColor.white]
UINavigationBar.appearance().tintColor = UIColor.white
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 })
// For iOS 10 data message (sent via FCM
Messaging.messaging().remoteMessageDelegate = self
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
FirebaseApp.configure()
return true
}
func application(received remoteMessage: MessagingRemoteMessage) {
print(remoteMessage.appData)
}
// Called when APNs failed to register the device for push notifications
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
// Print the error to console (you should alert the user that registration failed)
print("APNs registration failed: \(error)")
}
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
}
}
IN Swift 3
Configuring Your Apple Developer Account
Generating a CSR file
Uploading Your CSR File
Preparing the APNs Certificate
Configuring Firebase for Push Notifications
Building the Firebase Notification App
Installing the Firebase SDK Using CocoaPods
Adding GoogleService-Info.plist
Enabling Push Notifications
Initializing Push Notifications
AppDelegate of your Project
import UIKit
import SVProgressHUD
import UserNotifications
import Firebase
import FirebaseInstanceID
import FirebaseMessaging
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,UNUserNotificationCenterDelegate, MessagingDelegate {
var window: UIWindow?
static var appDelegate:AppDelegate!
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 })
// For iOS 10 data message (sent via FCM
Messaging.messaging().remoteMessageDelegate = self
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
FirebaseApp.configure()
return true
}
func application(received remoteMessage: MessagingRemoteMessage) {
print(remoteMessage.appData)
}
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
Messaging.messaging().apnsToken = deviceToken as Data
}
}
I think first configure for firebase
FirebaseApp.configure()
after that you should call registerForRemoteNotifications()
I'm searching informations about push notifications for VoIP push notifications. Some point remains unclear to me :
1) If the user has not the application opened, and then he receives a call. Is there a mean to launch the applications from the notification ?
2) How does the application wait for a specific event ? How does my device would know he receive a call from someone for example ?
3) I use the Appdelegate file from https://github.com/Hitman666/ios-voip-push but in my case it doesn't work (many errors), here is a preview of the error i get.
Thanks
1) If the user has not opened the application, and then he receives a call. Is there a mean to launch the applications from the notification ?
- First time user has to tap on app icon and open it then only device id will get register to receive push kit payload. then no need to open app. It will also work when app is in killed state and you have to schedule local notification as per push kit payload.
2) How does the application wait for a specific event ? How does my device would know he receive a call from someone for example ?
- You have to schedule local notification as per push kit payload.
3) I use the Appdelegate file from https://github.com/Hitman666/ios-voip-push but in my case it doesn't work (many errors), here is a preview of the error i get.
- Refer below code
import UIKit
import PushKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,PKPushRegistryDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let types: UIRemoteNotificationType = [.Alert, .Badge, .Sound]
application.registerForRemoteNotificationTypes(types)
self.PushKitRegistration()
return true
}
//MARK: - PushKitRegistration
func PushKitRegistration()
{
let mainQueue = dispatch_get_main_queue()
// Create a push registry object
if #available(iOS 8.0, *) {
let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue)
// Set the registry's delegate to self
voipRegistry.delegate = self
// Set the push type to VoIP
voipRegistry.desiredPushTypes = [PKPushTypeVoIP]
} else {
// Fallback on earlier versions
}
}
#available(iOS 8.0, *)
func pushRegistry(registry: PKPushRegistry!, didUpdatePushCredentials credentials: PKPushCredentials!, forType type: String!) {
// Register VoIP push token (a property of PKPushCredentials) with server
let hexString : String = UnsafeBufferPointer<UInt8>(start: UnsafePointer(credentials.token.bytes),
count: credentials.token.length).map { String(format: "%02x", $0) }.joinWithSeparator("")
print(hexString)
}
#available(iOS 8.0, *)
func pushRegistry(registry: PKPushRegistry!, didReceiveIncomingPushWithPayload payload: PKPushPayload!, forType type: String!) {
// Process the received push
}
}
Get some more information about how to integrate pushkit for VOIP based app.
Just updated with Swift 4.0 code as well.
https://github.com/hasyapanchasara/PushKit_SilentPushNotification
In Android it is possible to overwrite an existing push notification if you keep using the same notification id.
Is the same possible for iOS in any way?
It seems hard to find any information about replacing an push notification, because a lot of answers are using silent push notifications and remove them manually.
I use Cordova so I have limited options for background processes when receiving push notifications.
On iOS I cannot run code to manually remove any push notifications when the app is in the background.
No, in iOS you can not overwrite already scheduled remote / local notification.
You have to schedule another push notification.
By maintaining some flag or checking on key / value. You have to remove previous notification while reviving new notification.
Hope this helps.
Updated
As an alternate, once you receive push notification, on based of information you received in push notification payload.
You can schedule local notification.
import UIKit
import PushKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,PKPushRegistryDelegate {
var window: UIWindow?
let notificationObject = UILocalNotification()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
return true
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
notificationObject.fireDate = NSDate(timeIntervalSinceNow: 1)
notificationObject.alertBody = "Title"
notificationObject.alertAction = "Open"
notificationObject.soundName = "SoundFile.mp3"
notificationObject.category = ""
notificationObject.userInfo = "As per payload you receive"
UIApplication.sharedApplication().scheduleLocalNotification(notificationObjectCall)
}
Swift 4.2 Code
import UIKit
import PushKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate{
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
<#code#>
}
var window: UIWindow?
let notificationObject = UILocalNotification()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
notificationObject.fireDate = NSDate(timeIntervalSinceNow: 1) as Date
notificationObject.alertBody = "Title"
notificationObject.alertAction = "Open"
notificationObject.soundName = "SoundFile.mp3"
notificationObject.category = ""
notificationObject.userInfo = "As per payload you receive"
UIApplication.shared.scheduleLocalNotification(notificationObject)
}
As you can see in above code, local notification object is declared globally. So that object will get overwrite again and again whenever you receive payload.
For remote notification, you can not make object and overwrite it.
I am not much aware of cordova, but in native iOS, this way, you can do overwrite using local notification.
Hope you understand what technique is been used and help you figure out solution.
In iOS10 (and higher) and also via the new v2 apns protocol (from Apple) you can now use apns-collapse-id which is more or less the same as tag for Android to overwrite older notifs. More info here https://medium.com/the-guardian-mobile-innovation-lab/how-to-replace-the-content-of-an-ios-notification-2d8d93766446