PushKit not conceiving credentials - ios

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)

Related

VOIP push notification

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

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()
}
}

Unable to receive VoIP notification using PushKit

I am following this article and M Penades' answer building VoIP Notification Demo. I am able to register notification using didRegisterUserNotificationSettings and can get voip token from didUpdatePushCredentials.
But when I am using houston simulates sending notification to my device, I can get 1 push notification sent successfully message from console but no actions or logs on device side. It seems that didReceiveIncomingPushWithPayload never invoked.
P.S. I am using Xcode 7.3, iPhone 6(iOS 9.3) and iPad Mini(iOS 9.3) for development. Distributed Ad Hoc ipa for installation.
The codes posted here.
import UIKit
import PushKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let voipRegistry = PKPushRegistry(queue: dispatch_get_main_queue())
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
//Enable all notification type. VoIP Notifications don't present a UI but we will use this to show local nofications later
let notificationSettings = UIUserNotificationSettings(forTypes: [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound] , categories: nil)
//register the notification settings
application.registerUserNotificationSettings(notificationSettings)
//output what state the app is in. This will be used to see when the app is started in the background
NSLog("app launched with state \(application.applicationState.stringValue)")
return true
}
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")
}
}
extension AppDelegate {
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
//register for voip notifications
NSLog("didRegisterUserNotificationSettings called")
voipRegistry.desiredPushTypes = Set([PKPushTypeVoIP])
voipRegistry.delegate = self;
}
}
extension AppDelegate: PKPushRegistryDelegate {
func pushRegistry(registry: PKPushRegistry!, didUpdatePushCredentials credentials: PKPushCredentials!, forType type: String!) {
NSLog("didUpdatePushCredentials called")
//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!) {
NSLog("didReceiveIncomingPushWithPayload called")
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 {
NSLog("incoming notificaiton from background")
let localNotification = UILocalNotification();
localNotification.alertBody = message
localNotification.applicationIconBadgeNumber = 1;
localNotification.soundName = UILocalNotificationDefaultSoundName;
UIApplication.sharedApplication().presentLocalNotificationNow(localNotification);
}
else {
NSLog("incoming notificaiton from frontend")
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let alertController = UIAlertController(title: "Title", message: "This is UIAlertController default", preferredStyle: UIAlertControllerStyle.Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil)
alertController.addAction(cancelAction)
alertController.addAction(okAction)
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)
})
}
NSLog("incoming voip notfication: \(payload.dictionaryPayload)")
}
func pushRegistry(registry: PKPushRegistry!, didInvalidatePushTokenForType type: String!) {
NSLog("didInvalidatePushTokenForType called")
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"
}
}
}
}
Any idea on how to receive such notification?
Finally I fixed this issue.
There is ok for swift source code, the issue is I mis-send the push request to apple's development server gateway.sandbox.push.apple.com, actually we should send request to apple's production server gateway.push.apple.com.
If you are following M Penades' procedure, please note that you need modify Simplepush script, just replace ssl://gateway.sandbox.push.apple.com:2195 by ssl://gateway.push.apple.com:2195 at line 20 and try again.
Hope it works for you.

GCM group notifications not received on iOS when app is in background

I'm using google cloud messaging to send notifications to my iOS application.
I've configured the GCM services in my App and the notifications are working correctly. I mean that my device can request a gcmRegistrationToken and I can send notification using postman to my app. These notifications are working both when app is active and inactive.
Now I want to use the Device Groups Notifications feature. So I created a group for all my user's device:
https://android.googleapis.com/gcm/notification
Content-Type:application/json
Authorization:key=API_KEY
project_id:SENDER_ID
{
"operation": "create",
"notification_key_name": "appUser-userA",
"registration_ids": ["regToken1", "regToken2"]
}
I receive my device group key:
{
"notification_key": "deviceGroupKey"
}
But no when I want to send notification to the device group using postman, I only receive the notification when the app is ACTIVE.
Here is my POST request:
https://android.googleapis.com/gcm/send
Content-Type:application/json
Authorization:key=API_KEY
{
"to" : "deviceGroupToken",
"content_available" : true,
"priority": "high",
"sound": "default",
"notification" : {
"body_loc_key" : "NOTIF_FRIEND_REQUEST",
"body_loc_args" : ["UserB"],
"click_action": "NEW_FRIEND_REQUEST"
},
"data" : {
"friendRequestId": "12345678901234567890"
}
}
Here is my AppDelegate.swift:
//
// AppDelegate.swift
//
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GGLInstanceIDDelegate, GCMReceiverDelegate {
var window: UIWindow?
var connectedToGCM = false
var gcmSenderID: String?
var gcmRegistrationToken: String?
var gcmRegistrationOptions = [String: AnyObject]()
let gcmRegistrationKey = "onRegistrationCompleted"
var subscribedToTopic = false
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
print("bundleId=\(NSBundle.mainBundle().bundleIdentifier)")
// Configure Google Analytics
// Configure tracker from GoogleService-Info.plist.
var configureError:NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError)")
// Optional: configure GAI options.
let gai = GAI.sharedInstance()
gai.trackUncaughtExceptions = true // report uncaught exceptions
gai.logger.logLevel = GAILogLevel.Verbose // remove before app release
// Override point for customization after application launch.
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)) // types are UIUserNotificationType members
// Register for remotes notifications
UIApplication.sharedApplication().registerForRemoteNotifications()
// Get the gcm sender id
gcmSenderID = GGLContext.sharedInstance().configuration.gcmSenderID
var gcmConfig = GCMConfig.defaultConfig()
gcmConfig.receiverDelegate = self
GCMService.sharedInstance().startWithConfig(gcmConfig)
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 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.
GCMService.sharedInstance().disconnect()
connectedToGCM = false
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive 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.
// -->The app go through this point
// Connect to the GCM server to receive non-APNS notifications
GCMService.sharedInstance().connectWithHandler(gcmConnectionHandler)
// -->The app go through this point
}
func gcmConnectionHandler(error: NSError?) {
// -->The app never enter in this function
if let error = error {
print("Could not connect to GCM: \(error.localizedDescription)")
} else {
self.connectedToGCM = true
print("Connected to GCM")
// ...
}
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
self.saveContext()
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
// Create a config and set a delegate that implements the GGLInstaceIDDelegate protocol.
let instanceIDConfig = GGLInstanceIDConfig.defaultConfig()
instanceIDConfig.delegate = self
// Start the GGLInstanceID shared instance with that config and request a registration
// token to enable reception of notifications
GGLInstanceID.sharedInstance().startWithConfig(instanceIDConfig)
gcmRegistrationOptions = [kGGLInstanceIDRegisterAPNSOption:deviceToken,
kGGLInstanceIDAPNSServerTypeSandboxOption:true]
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: gcmRegistrationOptions, handler: gcmRegistrationHandler)
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
print("-- Failed to get deviceToken: \(error.localizedDescription)")
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
application.applicationIconBadgeNumber += 1
print(userInfo)
let apsInfo = userInfo["aps"] as! NSDictionary
var alertMessage = ""
print("********************** Received Notif")
if let alert = apsInfo["alert"] as? String{
alertMessage = alert
print(alertMessage)
}
else if let alert = apsInfo["alert"] as? NSDictionary {
if let body = alert["body"] as? String {
alertMessage = body
print(alertMessage)
}
else if let locKey = alert["loc-key"] as? String {
var alertBody = ""
if let locArgs = alert["loc-args"] as? [String] {
var safeArgs = ["", "", "", "", "", "", "", "", "", ""]
for var i = 0; i < locArgs.count && i < safeArgs.count; i++ {
safeArgs[i] = locArgs[i]
}
alertBody = String(format: NSLocalizedString(locKey, comment: ""),
safeArgs[0], safeArgs[1],
safeArgs[2], safeArgs[3],
safeArgs[4], safeArgs[5],
safeArgs[6], safeArgs[7],
safeArgs[8], safeArgs[9])
}
else {
alertBody = NSLocalizedString(locKey, comment: "")
}
alertMessage = alertBody
}
}
// If the application is currently on screen "Active" then we trigger a custom banner View for that notification to be shown
// Else the system will handle that and put it in the notification center
if application.applicationState == UIApplicationState.Active {
AGPushNoteView.showWithNotificationMessage(alertMessage, autoClose: true, completion: { () -> Void in
// Do nothing
})
}
else {
// if the app is inactive I try to trigger a local notification to check if the notification is received but not displayed
// or just not received because consol print doesn't work when app is inactive
var localNotification: UILocalNotification = UILocalNotification()
localNotification.alertBody = alertMessage
localNotification.fireDate = NSDate(timeIntervalSinceNow: 1)
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
}
}
func gcmRegistrationHandler(registrationToken: String!, error: NSError!) {
if (registrationToken != nil) {
self.gcmRegistrationToken = registrationToken
print("GCM Registration Token: \(registrationToken)")
let userInfo = ["registrationToken": registrationToken]
NSNotificationCenter.defaultCenter().postNotificationName(
self.gcmRegistrationKey, object: nil, userInfo: userInfo)
} else {
print("Registration to GCM failed with error: \(error.localizedDescription)")
let userInfo = ["error": error.localizedDescription]
NSNotificationCenter.defaultCenter().postNotificationName(self.gcmRegistrationKey, object: nil, userInfo: userInfo)
}
}
// MARK: - GGLInstanceIDDelegate
func onTokenRefresh() {
// A rotation of the registration tokens is happening, so the app needs to request a new token.
print("The GCM registration token needs to be changed.")
GGLInstanceID.sharedInstance().tokenWithAuthorizedEntity(gcmSenderID,
scope: kGGLInstanceIDScopeGCM, options: gcmRegistrationOptions, handler: gcmRegistrationHandler)
}
// MARK: - GCMReceiverDelegate
func willSendDataMessageWithID(messageID: String!, error: NSError!) {
if (error != nil) {
// Failed to send the message.
} else {
// Will send message, you can save the messageID to track the message
}
}
func didSendDataMessageWithID(messageID: String!) {
// Did successfully send message identified by messageID
}
// [END upstream_callbacks]
func didDeleteMessagesOnServer() {
// Some messages sent to this device were deleted on the GCM server before reception, likely
// because the TTL expired. The client should notify the app server of this, so that the app
// server can resend those messages.
}
func subscribeToTopic() {
// If the app has a registration token and is connected to GCM, proceed to subscribe to the
// topic
let subscriptionTopic = "/topics/test-global"
if(gcmRegistrationToken != nil && connectedToGCM) {
GCMPubSub.sharedInstance().subscribeWithToken(gcmRegistrationToken, topic: subscriptionTopic,
options: nil, handler: {(NSError error) -> Void in
if (error != nil) {
// Treat the "already subscribed" error more gently
if error.code == 3001 {
print("Already subscribed to \(subscriptionTopic)")
} else {
print("Subscription failed: \(error.localizedDescription)");
}
} else {
subscribedToTopic = true;
NSLog("Subscribed to \(subscriptionTopic)");
}
})
}
}
}
Do I have forgotten something in my code? or maybe it is not possible?
Any help would be appreciated.
PS: I tryed to send notification to topics "/topics/general" and it workss fine.

Resources