Implement PushKit and test in development behavior
Asked Answered
C

3

23

i'd like to implement PushKit service within my app ( Voip app ), but i have following doubt: I see that i can generate only production voip certificate , it works if i try to test voip push notification service on develop device ?

This is my implementation test:

With this 3 line of code i can get push token on didUpdatePushCredentials callback that i use to save into my server.

PKPushRegistry *pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
pushRegistry.delegate = self;
pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];

Server side i generate a "normal" payload push notification with only alert text, and i sent to voip token stored into my server.

I use the callback with debug log, but they never getting called!

- (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(NSString *)type {

          NSLog(@"didInvalidatePushTokenForType");

}

-(void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type {

          NSLog(@"didReceiveIncomingPushWithPayload: %@", payload.description);

}

-(void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type {
     if([credentials.token length] == 0) {
           NSLog(@"voip token NULL");

          return;
     }

      NSLog(@"didUpdatePushCredentials: %@ - Type: %@", credentials.token, type);

}

If i try to generate a push notification message from my server to voip device token previously uploaded, i'm never notified on didReceiveIncomingPushWithPayload callback, but from server i get 200 ok message( message was successfully sent )

Campos answered 2/12, 2014 at 9:22 Comment(6)
I did not get callbacks being called neither...and not being them called I m not sure how to get token in order to test it. Any progress on that?Clareclarence
nope.. i can't use this service.Campos
I got callbacks called! I missed to check on voip background capabilities of the app.Clareclarence
Did you make any update on the code that i have posted ? did you have any example to share ?Campos
I copy&pasted your code line per line. DId you try to add Background Modes capability? I ve got "Voice over IP" and "Remote notifications" activated.Clareclarence
Yes, my app do this.. thanks so much...Campos
C
71

Just in case someone is interested on testing voip push notifications with Pushkit here I left a small procedure I followed successfully:

1 - Create, if you do not have it already, a CSR with Keychain Access and save your CSR locally.

2 - Go to Apple Developer and get access Certificates, Identifiers & Profiles. On the member center.

  • Inside Identifiers-> App IDs Create one new app id
  • Inside Devices-> All Add devices UDID you want to use for testing voip pushes
  • Inside Certificates-> All Create a new Production certificate: VoIP Services Certificate. Select previously created app Id for your voip Service Certificate. Select previously created CSR (Certificate Signing Request) and once created download your new voip_services.cer

Once downloaded double click on voip_services.cer in order to open Keychain Access application and export private key for generated certificate: right button Export certificate.p12 file.

Save voip_services.cer and certificate.p12 file in a folder in order to create your server push notification generator

Finally go to Apple Developer website again and inside Provisioning Profiles->Distribution create a new Ad-Hoc distribution profile including on it all devices UDID you want to use for testing voip pushes. Download this profile and drag and drop to your xcode in order to use it on your application.

Now lets create the iOS app that will receive voip push notifications:

  • Create a new Single View Application from Xcode new project menu.
  • Fill its bundle Identifier according to created app id in previous section.
  • Add PushKit.framework in General-> Linked Frameworks and Libraries.
  • In Capabilities enable Background Mode and select Voice over IP option.
  • In Build Settings -> Code Signing select provisioning profile you downloaded previously and select Distribution as Code Signing Identity.

Lets add in the app the code Pasquale added in his question:

In your root view controller header (ViewController.h ) an import for PushKit.framework:

#import <PushKit/PushKit.h>

Add delegate in order to implement its functions:

@interface ViewController : UIViewController <PKPushRegistryDelegate>

Add in viewDidLoad function of your root view controller (ViewController.m) push registration:

- (void)viewDidLoad {
    [super viewDidLoad];

    PKPushRegistry *pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
    pushRegistry.delegate = self;
    pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
}

Implement required delegate functions:

- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type{
    if([credentials.token length] == 0) {
        NSLog(@"voip token NULL");
        return;
    }

    NSLog(@"PushCredentials: %@", credentials.token);
}

- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type
{
    NSLog(@"didReceiveIncomingPushWithPayload");
}

Once everything is compiling and ok, archive your project and export your ipa file in order to install it on testing devices (you can use for example Testflight to do the job).

Execute it and get from logs the PushCredentials we will use to send pushes.

Now lets go to server side (I followed this great guide of raywenderlich tutorials):

Get back to folder were you placed the three files:

  • voip_services.cer
  • certificate.p12

1 - Open a terminal and create pem file from certificate file:

#openssl x509 -in voip_services.cer -inform der -out PushVoipCert.pem

2 - Create pem file from exported private key file:

#openssl pkcs12 -nocerts -out PushVoipKey.pem -in certificate.p12

3 - Join both pem files in one:

#cat PushVoipCert.pem PushVoipKey.pem > ck.pem

In order to send pushes you can use Pusher from raywenderlich tutorials tutorial or using a simple php script:

<?php

// Put your device token here (without spaces):
$deviceToken = '0f744707bebcf74f9b7c25d48e3358945f6aa01da5ddb387462c7eaf61bbad78';

// Put your private key's passphrase here:
$passphrase = 'pushchat';

// Put your alert message here:
$message = 'My first push notification!';

////////////////////////////////////////////////////////////////////////////////

$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);

// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);

if (!$fp)
    exit("Failed to connect: $err $errstr" . PHP_EOL);

echo 'Connected to APNS' . PHP_EOL;

// Create the payload body
$body['aps'] = array(
    'alert' => $message,
    'sound' => 'default'
    );

// Encode the payload as JSON
$payload = json_encode($body);

// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;

// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));

if (!$result)
    echo 'Message not delivered' . PHP_EOL;
else
    echo 'Message successfully delivered' . PHP_EOL;

// Close the connection to the server
fclose($fp);

you should modify in script:

  • $deviceToken by adding your PushCredentials (from app logs)
  • $passphrase by the passphrase you added on step 2 when creating PushVoipKey.pem

That's it. Execute php script:

#php simplePushScript.php

and you should receive your voip push notification (you should see app log: "didReceiveIncomingPushWithPayload")

After that test I wondered how I could receive standard push notifications through pushkit framework, but unfortunately I have no answer as when registering the push type I could not find any other PKPushType but the PKPushTypeVoIP...

pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];

That's all! Thanks for reading!

Clareclarence answered 17/2, 2015 at 13:0 Comment(11)
I followed this and the didUpdatePushCredentials method was never called. Do I need register for remote notifications as well using [UIApplication registerForRemoteNotificationTypes:]?Pennywise
I can't edit that comment anymore, but I tried registering for push notifications by calling registerUserNotificationSettings and registerForRemoteNotifications but I still am not getting calls to didUpdatePushCredentials or didReceiveIncomingPushWithPayload.Pennywise
And I resolved my issue. My PKPushRegistry object was getting deallocated because it was a local variable. Once I made it an instance variable of my AppDelegate it fixed the issue.Pennywise
This is a great answer though there is a small change need to be made (mistake/Apple changes): The flags for pkcs12 should be -nodes -clcerts and it works with development version as well.Ectomorph
I have followed the steps. But I am getting error in terminal "Warning: stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in /Users/..../simplepush.php on line 21". I am using macOS Sierra.Diminish
You can try #32020123Clareclarence
Mac OS v10.12 & above Download cacert.pem from curl.haxx.se/ca/cacert.pem and keep it in the same folder. Include the following line under $ctx = stream_context_create(); stream_context_set_option($ctx, 'ssl', 'cafile', 'cacert.pem'); fyi: Syntax: bool stream_context_set_option ( resource $stream_or_context , string $wrapper , string $option , mixed $value ) For additional options check php.net/manual/en/context.ssl.phpDiminish
Great answer EXCEPT it links to a script which is no longer available.Guilbert
Thansk @AndyDent, I edited response including script, but I see in raywenderlich tutorials that they updated how to send pushes with an application named Pusher (I did not try although)Clareclarence
As of Xcode 9, you have to add voip to Info.plist manually; it's not visible under Capabilities anymore: #45026231Shinbone
"Add PushKit.framework in General-> Linked Frameworks and Libraries." is this step necessary?Ofeliaofella
C
7

Today I explored this in great detail. I, too, was wondering how to use the generated push token on a development build when Apple only allows us to generate a production VoIP push certificate.

On the server, you have to send a production push to gateway.push.apple.com and a development/sandbox push to gateway.sandbox.push.apple.com. I was able to generate and receive VoIP pushes on a development build of my app using the production VoIP certificate on gateway.sandbox.push.apple.com. I have not yet tried, but assume it will also work on an ad hoc or production build and using gateway.push.apple.com.

Also, note that push notifications do not work in the simulator at all.

Cavanagh answered 14/1, 2015 at 3:51 Comment(0)
T
1

You need to enable also Remote Notifications, even if you don't use them:

  • inside your App ID identifier on Developer portal
  • recreate the Development Provisioning profiles
  • hit Download All in XCode -> Preferences... -> Accounts -> your account
  • enable Remote Notifications in Capabilities -> Background Modes

Done this you will receive the delegate callback both in Debug and in Release.

Testicle answered 14/7, 2016 at 16:41 Comment(3)
"enable Remote Notifications in Capabilities -> Background Modes" is not strictly necessary. That is for requesting background time to download content. Our PushKit notification work perfectly fine without that being set.Monosymmetric
That's not correct, you need to "enable Remote Notifications in Capabilities -> Background Modes" if you want to do some processing of the push notification while your app is in background. The behavior you are talking about is "Background fetch in Capabilities -> Background Modes".Testicle
No, I am talking about "Remote Notifications in Capabilities -> Background Modes" and I am directly paraphrasing the Apple docs here: developer.apple.com/library/content/documentation/iPhone/… . Now I could have been a bit more explicit in saying it was for getting time to download content when a push notification comes in. I was not clear. Don''t need "Remote Notifications in Capabilities -> Background Modes" for push notifications to work. May need it if you want PN to wake you for bkgrnd processingMonosymmetric

© 2022 - 2024 — McMap. All rights reserved.