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)")
}
Related
I am trying to make an app the launches the app or the incoming call UI when a silent notification is received.
Currently I have the notifications working and I am able to send a notification and print out a log when I receive the notification
This function handels the receiving of notifications:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void){
print("Enitre message \(userInfo)")
let state: UIApplication.State = application.applicationState
switch state {
case UIApplication.State.active:
print("State: App is active")
case UIApplication.State.inactive:
print("State: App is inactive")
case UIApplication.State.background:
print("State: App is running in the background")
default:
print("State: Unknown")
}
completionHandler(UIBackgroundFetchResult.newData)
}
Is it possible to open the app or incoming call UI in this function?
First register for VOIP Notification in
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
requestPushKit()
return true
}
Import the call kit
import CallKit
Register Push kit
fileprivate func requestPushKit() {
let voipRegistry = PKPushRegistry(queue: DispatchQueue.main)
voipRegistry.delegate = self
voipRegistry.desiredPushTypes = [.voIP]
}
Delegates of VOIP(Push Kit)
extension AppDelegate: PKPushRegistryDelegate {
func pushRegistry( registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
if type == PKPushType.voIP {
let tokenParts = pushCredentials.token.map { data -> String in
return String(format: "%02.2hhx", data)
}
let tokenString = tokenParts.joined()
print(tokenString)
}
}
func pushRegistry( registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
}
func pushRegistry( registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type:PKPushType, completion: #escaping () -> Void) {
if type == PKPushType.voIP {
self.incomingCall()
}
}
func pushRegistry( registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {
if type == PKPushType.voIP {
self.incomingCall()
}
}
}
Call incomingcall Method
fileprivate func defaultConfig() -> CXProviderConfiguration{
let config = CXProviderConfiguration(localizedName: "My App")
config.includesCallsInRecents = true
config.supportsVideo = true
config.maximumCallGroups = 5
config.maximumCallsPerCallGroup = 10
// config.iconTemplateImageData = UIImagePNGRepresentation(UIImage(named: "pizza")!)
// config.ringtoneSound = "ringtone.caf"
return config
}
func incomingCall(){
let provider = CXProvider(configuration: defaultConfig())
provider.setDelegate(self, queue: nil)
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .generic, value: "Pete Za")
update.hasVideo = true
provider.reportNewIncomingCall(with: UUID(), update: update, completion: { error in })
}
And Call Kit Delegates Methods
extension AppDelegate : CXProviderDelegate {
func providerDidReset( provider: CXProvider) {
}
func providerDidBegin( provider: CXProvider) {
}
func provider( provider: CXProvider, perform action: CXAnswerCallAction) {
action.fulfill()
}
func provider( provider: CXProvider, perform action: CXEndCallAction) {
action.fulfill()
}
func provider( provider: CXProvider, perform action: CXStartCallAction) {
}
func provider( provider: CXProvider, perform action: CXSetHeldCallAction) {
}
func provider( provider: CXProvider, timedOutPerforming action: CXAction) {
}
func provider( provider: CXProvider, perform action: CXPlayDTMFCallAction) {
}
func provider( provider: CXProvider, perform action: CXSetGroupCallAction) {
}
func provider( provider: CXProvider, perform action: CXSetMutedCallAction) {
}
// func provider(_ provider: CXProvider, execute transaction: CXTransaction) -> Bool {
//
// }
}
Still if you require anything so please let us know. :)
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
After upgrading my app to Xcode8/Swift 3, I no longer receive callbacks from the PKPushRegistryDelegate.
I have verified all steps in Apple´s Voice Over IP (VoIP) Best Practices.
My device logs the following that might be related:
callservicesd[92] : [WARN] Ignoring voipRegister request because either no bundleIdentifier could be determined (0) or no environment could be determined (1)
My AppDelegate:
var voipRegistry: PKPushRegistry!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
voipRegistry = PKPushRegistry(queue: DispatchQueue.main)
voipRegistry.delegate = self
voipRegistry.desiredPushTypes = Set([.voIP])
}
extension AppDelegate: PKPushRegistryDelegate {
func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenForType type: PKPushType) {
print("didInvalidatePushTokenForType")
}
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, forType type: PKPushType) {
print("Incoming voip notfication: \(payload.dictionaryPayload)")
}
func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, forType type: PKPushType) {
print("voip token: \(credentials.token)")
}
}
I figured I had to enable "Push Notifications" under my target´s Capabilities:
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()
}
}
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)