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
Related
I register delegate for PKPushRegistry in AppDelegate method func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool by following code:
let voipRegistry: PKPushRegistry = PKPushRegistry(queue: nil)
voipRegistry.delegate = self
voipRegistry.desiredPushTypes = [.voIP]
self.voipRegistry = voipRegistry
When I run app on iOS 12 everything works correctly - method func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) is triggered, but in iOS 13 case this method is not triggered at all.
What I do wrong in iOS 13 case? May be I need add some additional code?
I don't know what changed but after day everything is works - token is received, method func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) is triggered.
My app can receive background notifications through PushKit. These PushKit notifications trigger an action to clean up previously delivered regular notifications.
When I terminate the app and receive a PushKit notification, viewDidAppear is triggered on my initial view controller (as configured in the storyboard). This is causing some problems for me. I understand that PushKit launches your app in the background, but I don't understand why viewDidAppear is triggered; as the app is actually never opened.
pseudo AppDelegate.swift:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
voipRegistration()
Messaging.messaging().delegate = self
// setup Firebase/Bugfender
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) {granted, _ in
// setup regular notifications
}
application.registerForRemoteNotifications()
return true
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: #escaping () -> Void) {
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: identifiers)
}
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
// register token with server
}
fileprivate func voipRegistration() {
let voipRegistry = PKPushRegistry(queue: nil)
voipRegistry.delegate = self
voipRegistry.desiredPushTypes = [.voIP]
}
I wonder if it's normal behaviour that viewDidAppear gets triggered through PushKit? The viewDidAppear in the initial controller starts my authentication process and I don't want that to happen while the app is in the background.
As described in the link #fewlinesofcode posted, viewDidAppear doesn't trigger when it physically appears on the screen, it triggers when it's added to the view controller hierarchy. So it makes sense that this triggers on startup.
I solved this using UIApplication.shared.applicationState, like so:
pseudo AppDelegate.swift:
func applicationWillEnterForeground(_ application: UIApplication) {
center.post(name: .ApplicationWillEnterForeground, object: self, userInfo: nil)
}
pseudo BaseViewController.swift:
class BaseViewController: UIViewController {
var applicationWillEnterForegroundObserver: NSObjectProtocol?
let center = NotificationCenter.default
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if UIApplication.shared.applicationState != .background {
authenticate()
} else {
if applicationWillEnterForegroundObserver == nil {
applicationWillEnterForegroundObserver = center.addObserver(
forName: .ApplicationWillEnterForeground,
object: nil, queue: nil) { (_) in
self.center.removeObserver(self.applicationWillEnterForegroundObserver!)
self.authenticate()
}
}
}
}
fileprivate func authenticate() {
// do authentication logic
}
}
This checks in viewDidAppear if the app is running in the background (like when PushKit launches the app). If it doesn't, simply authenticate and proceed. If it does, schedule a listener for applicationWillEnterForeground that authenticates as soon as the app actually comes to the foreground.
As you can find from Apple official documentation
Upon receiving a PushKit notification, the system automatically launches your app if it isn't running. By contrast, user notifications aren't guaranteed to launch your app.
So yes, it is correct behaviour.
UPD: The key point is, that application is woken up after receiving of the PushKit notification. As soon as app is running it has some execution time and your code is executing.
I have implemented VOIP in swift.
Earlier it was working fine.
But, Now it is not triggering the didReceiveIncomingPushWith function.
Please find my configuration
let config = CXProviderConfiguration.init(localizedName: "AppName")
var provider: CXProvider!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
provider = CXProvider(configuration: config)
provider.setDelegate(self, queue: DispatchQueue.main)
self.registerVOIP()
}
func registerVOIP() {
//register for voip notifications
pushRegistry = PKPushRegistry(queue: DispatchQueue.main)
pushRegistry.delegate = self;
pushRegistry.desiredPushTypes = Set([PKPushType.voIP])
}
extension AppDelegate : PKPushRegistryDelegate{
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {
}
}
In the extension method, didUpdate works fine, since delegate is set in didiFinishLoad
I am using QuickBlox for VOIP
I check the voip certificate everything is fine.
Here the quick box new session delegate
extension AppDelegate : QBRTCClientDelegate{
func didReceiveNewSession(_ session: QBRTCSession, userInfo: [String : String]? = nil) {
print(#function)
}
}
the didReceiveNewSession function is trigger when receives a new call (If the app is in foreground)
Your code is fine, it is Quickblox server-side code needs to be changed.
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?
I am implementing PushKit for my VoIP application for iOS 10.
I have written this code in AppDelegate.swift file:
import PushKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate {
var window: UIWindow?
private let _pushRegistry = PKPushRegistry(queue: DispatchQueue.main)
//MARK: - App Life Cycle -
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
//Register for local notifications
NotificationController.registerNotifcationForApplication()
//PushKit
_pushRegistry.delegate = self
var typeSet = Set<PKPushType>()
typeSet.insert(.voIP)
_pushRegistry.desiredPushTypes = typeSet
window!.makeKeyAndVisible()
return true
}
//MARK: - Delegates -
func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, forType type: PKPushType) {
DDLogVerbose("PushKit Token: \(credentials.token) length: \(credentials.token.count)")
print("pushRegistry didUpdate credentials")
}
func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenForType type: PKPushType) {
DDLogVerbose("")
print("pushRegistry didInvalidatePushTokenForType")
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, forType type: PKPushType) {
DDLogVerbose("Payload: \(payload.dictionaryPayload)")
print("pushRegistry didReceiveIncomingPushWith")
}
}
I have enabled these background modes:
But none of the delegate is getting called when I launch the app.
It also not working on iOS 9.
I solved it just simply by enabling Push Notifications in capabilities as:
Actually I tried this already also but it was not worked previously.
Now I enabled it, closed Xcode 8.2.1, reopen, clean-build and it worked!
Thanks for this SO answer by vin25