VOIP push notification - ios

I want to play sound when my app kill in background mode. For this I am using VOIP notification. My method is call and sound play in foreground mode. But in background mode method call sound not fire. Here is my code snippet.
func pushRegistry(registry: PKPushRegistry, didReceiveIncomingPushWithPayload payload: PKPushPayload, forType type: String) {
var a = payload.dictionaryPayload
// NSBundle.mainBundle().pathForResource(<#T##name: String?##String?#>, ofType: <#T##String?#>)
let url = NSBundle.mainBundle().URLForResource("demo", withExtension: "mp3")!
do {
player = try AVAudioPlayer(contentsOfURL: url)
guard let player = player else { return }
player.prepareToPlay()
player.play()
} catch let error as NSError {
print(error.description)
}
}

Once you receive pushkit payload. You have to schedule local notification with sound file. Your sound file plays max for 30 seconds.
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
}
}
Refer

Related

Push notifications in iOS suddenly not delivering via Firebase

Recently I stopped receiving Firebase Cloud Messaging APNs notifications. I decided to update to latest version of Firebase pods and my AppDelegate.swift had a few functions deprecated so it currently looks like this now:
import UIKit
import SwiftyJSON
import IQKeyboardManagerSwift
import Firebase
import FirebaseInstanceID
import FirebaseMessaging
import UserNotifications
import AVFoundation
import Crittercism
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
var isPulltoRefreshInProgress: Bool = Bool(false)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Crittercism.enable(withAppID: Config.sharedInstance.apteligentAppID())
//To find Home Directory
print("Home Directory - \(NSHomeDirectory())")
IQKeyboardManager.shared.enable = true
IQKeyboardManager.shared.enableAutoToolbar = false
IQKeyboardManager.shared.shouldShowToolbarPlaceholder = false
// IQKeyboardManager.shared.shouldResignOnTouchOutside = true
// UIApplication.shared.statusBarStyle = .lightContent
configureForPushNotification()
registrationForNotification(application: application )
self.startOver()
return true
}
func registrationForNotification(application: UIApplication) {
// iOS 10 support
if #available(iOS 10, *) {
DLog("registrationForNotification")
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .alert, .sound]){ (granted, error) in }
application.registerForRemoteNotifications()
}
else {
application.registerForRemoteNotifications(matching: [.badge, .sound, .alert])
}
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
Tokens.sharedInstance.isNotificationCame = true
NotificationCenter.default.post(name: NSNotification.Name(NotificationCenterIDs.kPushNotificationReceivedNotification), object:self)
if application.applicationState == UIApplication.State.active {
DLog("App is in foreground when notification received")
// app was already in the foreground
} else {
DLog("App was just brought from background to foreground via PUSH")
// app was just brought from background to foreground via PUSH
self.startOver()
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
// let application = UIApplication.shared
// if(application.applicationState == .active){
// DLog("user tapped the notification bar when the app is in foreground")
if let window = self.window {
if let viewController = UIStoryboard(name: StoryboardControllerIDs.kStoryboardId, bundle: nil).instantiateViewController(withIdentifier: StoryboardController.kNotificationsViewController) as? NotificationsViewController{
if let rootViewController = window.rootViewController as? UINavigationController{
// DLog("Root: " + String(describing: type(of: rootViewController)))
Tokens.sharedInstance.isNotificationCame = true
rootViewController.pushViewController(viewController, animated: true)
}
}
}
// }
// if(application.applicationState == .inactive)
// {
// DLog("user tapped the notification bar when the app is in background")
// }
/* Change root view controller to a specific viewcontroller */
// let storyboard = UIStoryboard(name: "Main", bundle: nil)
// let vc = storyboard.instantiateViewController(withIdentifier: "ViewControllerStoryboardID") as? ViewController
// self.window?.rootViewController = vc
completionHandler()
}
func configureForPushNotification() {
var fileName : String = "GoogleServiceQA-Info"
let currentConfiguration = Bundle.main.object(forInfoDictionaryKey: "Config")! as! String
if currentConfiguration.lowercased() == "production" {
fileName = "GoogleServiceProd-Info"
}
let filePath = Bundle.main.path(forResource: fileName, ofType: "plist")!
let options = FirebaseOptions(contentsOfFile: filePath)
FirebaseApp.configure(options: options!)
Messaging.messaging().delegate = self
// if let refreshedToken = InstanceID.instanceID().token() {
// print("InstanceID token: \(refreshedToken)")
// DeviceTokenConstants.deviceToken = refreshedToken
// }
InstanceID.instanceID().instanceID { (result, error) in
if let error = error {
DLog("Error fetching remote instange ID: \(error)")
} else if let result = result {
DLog("configureForPushNotification - Remote instance ID token: \(result.token)")
DeviceTokenConstants.deviceToken = result.token
}
}
NotificationCenter.default.addObserver(self, selector:
#selector(tokenRefreshNotification), name:
NSNotification.Name.InstanceIDTokenRefresh, object: nil)
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
//Getting errors in Xcode10 for iOS12
let hexString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
DLog("===DEVICE-TOKEN: \(hexString)")
// In debug mode
Messaging.messaging().apnsToken = deviceToken
Messaging.messaging().setAPNSToken(deviceToken, type: .sandbox)
Messaging.messaging().setAPNSToken(deviceToken, type: .prod)
// In release mode
// InstanceID.instanceID().setAPNSToken(deviceToken, type: InstanceIDAPNSTokenType.prod)
}
// This method will be called when app received push notifications in foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
completionHandler([.alert, .badge, .sound])
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
DeviceTokenConstants.deviceToken = fcmToken
FireBaseToken.didReceived = true
}
#objc func tokenRefreshNotification(_ notification: Notification) {
InstanceID.instanceID().instanceID { (result, error) in
if let error = error {
print("Error fetching remote instange ID: \(error)")
} else if let result = result {
print("tokenRefreshNotification - Remote instance ID token: \(result.token)")
DeviceTokenConstants.deviceToken = result.token
let dataDict:[String: String] = ["token": result.token]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
}
}
// Deprecated code
// if let refreshedToken = InstanceID.instanceID().token() {
// print("InstanceID token: \(refreshedToken)")
// DeviceTokenConstants.deviceToken = refreshedToken
// }
// Connect to FCM since connection may have failed when attempted before having a token.
// connectToFcm()
}
Is there something in this code that may prevent the notification from being delivered or is this an external issue outside of the iOS app? I am able to see tokens being printed in my console for the device token and fcm token, so I feel that the setup in the iOS app is not the issue. I ensured that the app notifications were not disabled in my iPhone.
If you are using keyid instead of certification, you can try to change ur debug mode to release mode then you can try to see if you receive push or u can upload to TestFlight and check if you receive the push.
However it’s better to use certification instead keyid that you can use in debug and in release mode.
I don't understand from your code why it doesn't work, have you tried to follow firebase's guide to the letter? It never gave me problems.

Push Kit Not receiving pushCredentials token

I am new in integrating Push Kit so I am not able to receive the pushCredentials token please suggest me solution.
Below is my code :
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// For debugging
//OneSignal.setLogLevel(.LL_VERBOSE, visualLevel: .LL_NONE)
//Enable all notification type.
let notificationSettings = UIUserNotificationSettings(types: [UIUserNotificationType.alert, UIUserNotificationType.badge, UIUserNotificationType.sound] , categories: nil)
//register the notification settings
application.registerUserNotificationSettings(notificationSettings)
return true
}
extension AppDelegate {
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
//register for voip notifications
let voipRegistry = PKPushRegistry(queue: DispatchQueue.main)
voipRegistry.desiredPushTypes = Set([PKPushType.voIP])
voipRegistry.delegate = self;
print("didRegisterUserNotificationSettings")
}
}
extension AppDelegate: PKPushRegistryDelegate {
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, forType type: PKPushType) {
print("voip token: \(pushCredentials.token)")
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, forType type: PKPushType) {
let payloadDict = payload.dictionaryPayload["aps"] as? Dictionary<String, String>
let message = payloadDict?["alert"]
//present a local notifcation to visually see when we are recieving a VoIP Notification
if UIApplication.shared.applicationState == UIApplicationState.background {
let localNotification = UILocalNotification();
localNotification.alertBody = message
localNotification.applicationIconBadgeNumber = 1;
localNotification.soundName = UILocalNotificationDefaultSoundName;
UIApplication.shared.presentLocalNotificationNow(localNotification);
}
else {
print(message)
// dispatch_async(DispatchQueue.main, { () -> Void in
//
// let alert = UIAlertView(title: "VoIP Notification", message: message, delegate: nil, cancelButtonTitle: "Ok");
// alert.show()
// })
}
NSLog("incoming voip notfication: \(payload.dictionaryPayload)")
}
func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenForType type: PKPushType) {
NSLog("token invalidated")
}
}
extension UIApplicationState {
//help to output a string instead of an enum number
var stringValue : String {
get {
switch(self) {
case .active:
return "Active"
case .inactive:
return "Inactive"
case .background:
return "Background"
}
}
}
}
Am I missing something please suggest.
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, forType type: PKPushType) {
let deviceTokenString = pushCredentials.token.map { String(format: "%02.2hhx", $0) }.joined()
print("deviceTokenString \(deviceTokenString)")
}

IOS Swift Pushkit: didUpdatePushCredentials not called

I am trying to develop a VoIP app using Twilio Client iOS SDK. My app receives incoming calls when its not in background. For background mode I am trying to use PushKit Framework as Apple suggests. But my app is not getting registered for PushKit. The method didUpdatePushCredentials is not getting called.
This is my app delegate and settings:
import UIKit
import PushKit;
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var voipRegistry: PKPushRegistry!;
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
if UIApplication.instancesRespondToSelector(#selector(UIApplication.registerUserNotificationSettings(_:))) {
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound], categories: nil))
}
let preferences = NSUserDefaults.standardUserDefaults()
let usrIdKey = "usrId"
let tokenKey = "token"
if preferences.objectForKey(usrIdKey) == nil || preferences.objectForKey(tokenKey) == nil{
// Doesn't exist
} else {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
var nav1 = UINavigationController()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewControllerObj = storyboard.instantiateViewControllerWithIdentifier("NumberScreenViewController") as? NumberScreenViewController
nav1.viewControllers = [viewControllerObj!]
self.window!.rootViewController = nav1
self.window?.makeKeyAndVisible()
}
phone.login{
device in
}
var state:String
switch application.applicationState {
case .Active:
state = "Active"
case .Background:
state = "Background"
case .Inactive:
state = "Active"
}
NSLog("App launched with state \(state)")
return true
}
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 throttle down OpenGL ES frame rates. 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 informationO 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:.
//output to see when we terminate the app
NSLog("app terminated")
}
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
NSLog("Registering for VOIP notifications.")
//register for voip notifications
voipRegistry = PKPushRegistry(queue: dispatch_get_main_queue())
voipRegistry.desiredPushTypes = Set([PKPushTypeVoIP])
voipRegistry.delegate = self;
}
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification)
{
if ( application.applicationState == UIApplicationState.Active)
{
print("Active")
// App is foreground and notification is recieved,
// Show a alert.
}
else if( application.applicationState == UIApplicationState.Background)
{
print("Background")
// App is in background and notification is received,
// You can fetch required data here don't do anything with UI.
self.redirectToPage(notification.userInfo)
}
else if( application.applicationState == UIApplicationState.Inactive)
{
print("Inactive")
// App came in foreground by used clicking on notification,
// Use userinfo for redirecting to specific view controller.
self.redirectToPage(notification.userInfo)
}
}
func redirectToPage(userInfo:[NSObject : AnyObject]!)
{
var viewControllerToBrRedirectedTo:DialScreenViewController = DialScreenViewController(nibName: "DialScreenViewController", bundle: nil)
if userInfo != nil
{
if let pageType = userInfo["TYPE"]
{
if pageType as! String == "Page1"
{
// viewControllerToBrRedirectedTo = UIViewController() // creater specific view controller
}
}
}
if self.window != nil && self.window?.rootViewController != nil
{
let rootVC = self.window?.rootViewController!
if rootVC is UINavigationController
{
(rootVC as! UINavigationController).pushViewController(viewControllerToBrRedirectedTo, animated: true)
}
else
{
rootVC?.presentViewController(viewControllerToBrRedirectedTo, animated: true, completion: { () -> Void in
})
}
}
}
}
extension AppDelegate: PKPushRegistryDelegate {
func pushRegistry(registry: PKPushRegistry!, didUpdatePushCredentials credentials: PKPushCredentials!, forType type: String!) {
//print out the VoIP token. We will use this to test the nofications.
NSLog("voip token: \(credentials.token)")
}
func pushRegistry(registry: PKPushRegistry!, didReceiveIncomingPushWithPayload payload: PKPushPayload!, forType type: String!) {
let payloadDict = payload.dictionaryPayload["aps"] as? Dictionary<String, String>
let message = payloadDict?["alert"]
//present a local notifcation to visually see when we are recieving a VoIP Notification
if UIApplication.sharedApplication().applicationState == UIApplicationState.Background {
let localNotification = UILocalNotification();
localNotification.alertBody = message
localNotification.applicationIconBadgeNumber = 1;
localNotification.soundName = UILocalNotificationDefaultSoundName;
UIApplication.sharedApplication().presentLocalNotificationNow(localNotification);
}
else {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let alert = UIAlertView(title: "VoIP Notification", message: message, delegate: nil, cancelButtonTitle: "Ok");
alert.show()
})
}
NSLog("incoming voip notfication: \(payload.dictionaryPayload)")
}
func pushRegistry(registry: PKPushRegistry!, didInvalidatePushTokenForType type: String!) {
NSLog("token invalidated")
}
}
I have same problem. However it was recovered after rebooting the phone.
Go through https://www.raywenderlich.com/123862/push-notifications-tutorial
Download
import UIKit
import PushKit
class AppDelegate: UIResponder, UIApplicationDelegate,PKPushRegistryDelegate{
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
}
}
Life cycle of app - when app is in terminated and push kit payload comes

Register for voip notifications outside of app delegate

My app requires onboarding and I want to wait until the user reach the AskForVOIPNotificationsViewController before I ask for permission to present push/voip notifications. The code below kind of works, the problem is that pushRegistry in AppDelegate does not realise it has permission and didUpdatePushCredentials in AppDelegate does not get called. The code is never run and the server never gets the device token. However if I close the app and relaunch, didUpdatePushCredentials is called, the server gets the token and the user is able to receive notifications.
How can I make sure didUpdatePushCredentials/PKPushRegistry is called from AskForVOIPNotificationsViewController so that the user is able to receive voip notifications immediately without relaunching the app?
I implemented my code according to a similar question, but I am unable to get it to work with PushKit.
Any help is VERY much appreciated - thank you !
In AskForVOIPNotificationsViewController
func registerForNotifications() {
let notificationSettings: UIUserNotificationSettings! = UIApplication.sharedApplication().currentUserNotificationSettings()
if !notificationSettings.types.contains([.Badge, .Sound, .Alert]) {
let notificationTypes: UIUserNotificationType = [.Badge, .Sound, .Alert]
let notificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(notificationSettings)
}
}
In App delegate
import UIKit
import PushKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate {
var voipRegistry:PKPushRegistry!
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
registerForVoIPPushes()
return true
}
func registerForVoIPPushes() {
voipRegistry = PKPushRegistry(queue: dispatch_get_main_queue())
voipRegistry.delegate = self
voipRegistry.desiredPushTypes = Set([PKPushTypeVoIP])
print("VOIP Push registered")
}
func pushRegistry(registry: PKPushRegistry!, didUpdatePushCredentials credentials: PKPushCredentials!, forType type: String!) {
let voipToken: String! = credentials.token.description
print("\n\n##### didUpdatePushCredentials: \n\n", voipToken)
**// update server with device token HERE**
}
func pushRegistry(registry: PKPushRegistry!, didReceiveIncomingPushWithPayload payload: PKPushPayload!, forType type: String!) {
print("\n\n## DID RECEIVE NOTIFICATION ## \n\n")
let data = payload.dictionaryPayload
let aps = data["aps"] as! [String: AnyObject]
let alert = aps["alert"] as! [String: AnyObject]
let localNotification = UILocalNotification()
//setup the notification
localNotification.alertBody = alert["body"] as? String
localNotification.alertTitle = alert["title"] as? String
localNotification.soundName = "Simple_ring_tone_29s.aiff"
localNotification.alertAction = alert["action-loc-key"] as? String
UIApplication.sharedApplication().applicationIconBadgeNumber = 1
//show the notification
UIApplication.sharedApplication().presentLocalNotificationNow(localNotification)
}
This worked for me, I hope that also work for you.
Still it is not good idea to do, this stuff has to be in appdelegate.
Please download code.
//
// ViewController.swift
// PushDemo
//
// Created by Hasya.Panchasra on 01/07/16.
// Copyright © 2016 bv. All rights reserved.
//
import UIKit
import PushKit
class ViewController: UIViewController,PKPushRegistryDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.PushKitRegistration()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//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
}
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let types: UIRemoteNotificationType = [.Alert, .Badge, .Sound]
application.registerForRemoteNotificationTypes(types)
return true
}
From the code you've posted, it seems the only place you call registerForVoIPPushes(), is in application(_:didFinishLaunchingWithOptions:)
Since registerForVoIPPushes() sets the voip registry delegate, you should probably also call it when the user gives permission for notifications.
According to this tutorial, registerUserNotificationSettings(userNotificationSettings) has a delegate callback application(_:didRegisterWithNotificationSettings:) you can use for this purpose:
func application(application: UIApplication, didRegisterUserNotifications notificationSettings: UIUserNotificationSettings)
{
// Check whether notifications are permitted
if notificationSettings != .None
{
print("Permission for notifications granted.")
registerForVoIPPushes()
}
}

PushKit not conceiving credentials

I'm struggling for some time here and probably this is my mistake but I can't find it anywhere, an answer for this.
I have implemented PushKit in some ways, but none of them were effective.
I have added the correct background modes, implemented the callbacks in the correct way, didUpdatePushCredentials is getting called normally...
However, the credentials: PKPushCredentials! variable, is giving me an error pointer... It´s not null... not nil... not anything... It simply does not have a value... it´s allocated garbage... and for that reason.. I´m receiving EXC_BREAKPOINT..
I have tried in 3 different devices... Same behavior...
I have already created the Certificates for VoIP Push...
I have done it in different ways:
By creating the void Push Registry object after didRegisterForRemotePushNotification
By creating the push registry without registering for remote push notification...
By creating the registry with main, global and custom queues..
Allways the same...
Here´s the code:
extension AppDelegate : PKPushRegistryDelegate {
func registerForVoipPush() {
self.registry = PKPushRegistry(queue:nil)
if self.registry != nil {
self.registry!.delegate = self
self.registry!.desiredPushTypes = Set<String>(arrayLiteral: PKPushTypeVoIP)
}
//let notificationSettings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories:nil)
//UIApplication.sharedApplication().registerUserNotificationSettings(notificationSettings)
}
func pushRegistry(registry: PKPushRegistry!, didUpdatePushCredentials credentials: PKPushCredentials!, forType type: String!) {
//print out the VoIP token. We will use this to test the nofications.
NSLog("voip token: \(credentials.token)")
if credentials != nil {
let username = NSUserDefaults.standardUserDefaults().objectForKey("username") as? String
if username != nil {
ServerDefinitions.subscribeForPush(username!, token: NSString(data: credentials.token, encoding: NSUTF8StringEncoding) as! String, callback: { (retMsg) -> Void in
print(retMsg)
})
}
}
}
func pushRegistry(registry: PKPushRegistry!, didReceiveIncomingPushWithPayload payload: PKPushPayload!, forType type: String!) {
let payloadDict = payload.dictionaryPayload["aps"] as? Dictionary<String, String>
let message = payloadDict?["alert"]
//present a local notifcation to visually see when we are recieving a VoIP Notification
if UIApplication.sharedApplication().applicationState == UIApplicationState.Background {
let localNotification = UILocalNotification();
localNotification.alertBody = message
localNotification.applicationIconBadgeNumber = 1;
localNotification.soundName = UILocalNotificationDefaultSoundName;
UIApplication.sharedApplication().presentLocalNotificationNow(localNotification);
}
else {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
print("Incoming Call")
})
}
NSLog("incoming voip notfication: \(payload.dictionaryPayload)")
}
func pushRegistry(registry: PKPushRegistry!, didInvalidatePushTokenForType type: String!) {
NSLog("token invalidated")
}
}
EDIT:
Please note, that the above code is an extension of AppDelegate, made only to separate the code, so it gets more readable.
I also added var registry : PKPushRegistry? on the AppDelegate's. In order for this to work, you have to call registerForVoipPush() somewhere in code. In my case, I did it from a button.
PLEASE HELP ME!
I ran into the same issue and I solved this by adding a classic Push implementation before initiating the VoIP registration...
I guess that somehow Apple wants to ensure you firstly ask the user for basic push and get the user's aknowledgment before authorizing you to process further silent voip stuff...
Enable the Push Notifications for your app...
Then, this is the whole resulting AppDelegate file, that is quite similar to yours:
import UIKit
import PushKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
//Enable all notification type.
let notificationSettings = UIUserNotificationSettings(forTypes: [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound] , categories: nil)
//register the notification settings
application.registerUserNotificationSettings(notificationSettings)
NSLog("app launched with state \(application.applicationState.stringValue)")
return true
}
func applicationWillResignActive(application: UIApplication) {
}
func applicationDidEnterBackground(application: UIApplication) {
}
func applicationWillEnterForeground(application: UIApplication) {
}
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:.
NSLog("app terminated")
}
}
extension AppDelegate {
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
//register for voip notifications
let voipRegistry = PKPushRegistry(queue: dispatch_get_main_queue())
voipRegistry.desiredPushTypes = Set([PKPushTypeVoIP])
voipRegistry.delegate = self;
NSLog("didRegisterUserNotificationSettings")
}
}
extension AppDelegate: PKPushRegistryDelegate {
func pushRegistry(registry: PKPushRegistry!, didUpdatePushCredentials credentials: PKPushCredentials!, forType type: String!) {
//print out the VoIP token. We will use this to test the nofications.
NSLog("voip token: \(credentials.token)")
}
func pushRegistry(registry: PKPushRegistry!, didReceiveIncomingPushWithPayload payload: PKPushPayload!, forType type: String!) {
let payloadDict = payload.dictionaryPayload["aps"] as? Dictionary<String, String>
let message = payloadDict?["alert"]
//present a local notifcation to visually see when we are recieving a VoIP Notification
if UIApplication.sharedApplication().applicationState == UIApplicationState.Background {
let localNotification = UILocalNotification();
localNotification.alertBody = message
localNotification.applicationIconBadgeNumber = 1;
localNotification.soundName = UILocalNotificationDefaultSoundName;
UIApplication.sharedApplication().presentLocalNotificationNow(localNotification);
}
else {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let alert = UIAlertView(title: "VoIP Notification", message: message, delegate: nil, cancelButtonTitle: "Ok");
alert.show()
})
}
NSLog("incoming voip notfication: \(payload.dictionaryPayload)")
}
func pushRegistry(registry: PKPushRegistry!, didInvalidatePushTokenForType type: String!) {
NSLog("token invalidated")
}
}
extension UIApplicationState {
//help to output a string instead of an enum number
var stringValue : String {
get {
switch(self) {
case .Active:
return "Active"
case .Inactive:
return "Inactive"
case .Background:
return "Background"
}
}
}
}
For a bit more information, this is inspired by this post
As #JBA I forgot to active the push notification. It's look like even you need just the push VOIP you have to active the push (traditional)

Resources