(1) You need to create an App ID without .* in the Program Portal (that means one cert for one app)
(2) Generate a certificate signing request from your Mac's keychain and save to disk
(3) Upload the CertificateSigningRequest.certSigningRequest to the Program Portal
(4) Wait for the generation of cert (about 1 min). Download the certificate (aps_developer_identity.cer) from the Program Portal (If you need to renew this cert, it is under the App ID that you created in step 1, and choose Action Configure)
(5) Keep (or rename them if you prefer) these 2 files (steps 2 and 4) in a safe place. You might need the CertificateSigningRequest.certSigningRequest file to request a new cert for a new app in the future or renew the old cert when expired.
(6) Suppose you have imported the aps_developer_identity.cer to the keychain. Then you have to export these new cert and the private key of this cert (not the public key) and saved as .p12 files.
(7) Then you use these commands to generate the cert and key in Mac's Terminal for PEM format (Privacy Enhanced Mail Security Certificate)
openssl pkcs12 -clcerts -nokeys -out cert.pem -in cert.p12
openssl pkcs12 -nocerts -out key.pem -in key.p12
(8) The cert.pem and key.pem files will be used by your own php script communicating with APNS.
(9) If you want to remove the passphase of private key in key.pem, do this
openssl rsa -in key.pem -out key.unencrypted.pem
Then combine the certificate and key
cat cert.pem key.unencrypted.pem > ck.pem
But please set the file permission of this unencrypted key by using chmod 400 and is only readable by root in a sever configuration.
(10) The testing APNS is at ssl://gateway.sandbox.push.apple.com:2195
(11) For the source codes to push payload message to the APNS, you can find them in the Developer Forum. This is the one that I used, for php script. Run this (after obtaining the device token from the testing device and with iPhone Client program setup)
php -f apns.php "My Message" 2
or if you put this php script and the ck.pem in a local web server, you can use this to test
http://127.0.0.1/apns/apns.php?message=test%20from%20javacom&badge=2&sound=received5.caf
Please be patient to get message from the sandbox server. Normally, you need 10 minutes+ to get the first message from push notification testing.
- apns.php Select all
#!/usr/bin/env php
<?php
$deviceToken = '02da851dXXXXXXXXb4f2b5bfXXXXXXXXce198270XXXXXXXX0d3dac72bc87cd60'; // masked for security reason
// Passphrase for the private key (ck.pem file)
// $pass = '';
// Get the parameters from http get or from command line
$message = $_GET['message'] or $message = $argv[1] or $message = 'Message received from javacom';
$badge = (int)$_GET['badge'] or $badge = (int)$argv[2];
$sound = $_GET['sound'] or $sound = $argv[3];
// Construct the notification payload
$body = array();
$body['aps'] = array('alert' => $message);
if ($badge)
$body['aps']['badge'] = $badge;
if ($sound)
$body['aps']['sound'] = $sound;
/* End of Configurable Items */
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
// assume the private key passphase was removed.
// stream_context_set_option($ctx, 'ssl', 'passphrase', $pass);
$fp = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
// for production change the server to ssl://gateway.push.apple.com:2195
if (!$fp) {
print "Failed to connect $err $errstr\n";
return;
}
else {
print "Connection OK\n";
}
$payload = json_encode($body);
$msg = chr(0) . pack("n",32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload;
print "sending message :" . $payload . "\n";
fwrite($fp, $msg);
fclose($fp);
?>
(12) For iPhone Client Program, you need to edit the bundle identifier to the App ID that you created and imported the new provisioning profile for that APP ID to the XCode and iPhone. And codesign with that new provisioning profile. Then implement the following methods in AppDelegate to Build & Go
- AppDelegate.m Select all
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSLog(@"Registering Remote Notications");
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
// Override point for customization after app launch
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
// Delegation methods
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
const void *devTokenBytes = [devToken bytes];
// self.registered = YES;
NSLog(@"deviceToken: %@", devToken);
// [self sendProviderDeviceToken:devTokenBytes]; // custom method
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSLog(@"Error in registration. Error: %@", err);
}
(13) Additional tips for sandbox testing
- The feedback service is feedback.sandbox.push.apple.com:2195
- Send your messages to gateway.sandbox.push.apple.com:2195
Here is the feedback server request php code. For the sandbox feedback server, you have to create a second dummy app to make the first one works. May be the sandbox feedback server is buggy as the production push and feedback servers does not have this problem.
php -f feedback.php
- feedback.php Select all
#!/usr/bin/env php
<?php
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
stream_context_set_option($ctx, 'ssl', 'verify_peer', false);
// assume the private key passphase was removed.
// stream_context_set_option($ctx, 'ssl', 'passphrase', $pass);
$fp = stream_socket_client('ssl://feedback.sandbox.push.apple.com:2196', $error, $errorString, 60, STREAM_CLIENT_CONNECT, $ctx);
// production server is ssl://feedback.push.apple.com:2196
if (!$fp) {
print "Failed to connect feedback server: $err $errstr\n";
return;
}
else {
print "Connection to feedback server OK\n";
}
print "APNS feedback results\n";
while ($devcon = fread($fp, 38))
{
$arr = unpack("H*", $devcon);
$rawhex = trim(implode("", $arr));
$feedbackTime = hexdec(substr($rawhex, 0, 8));
$feedbackDate = date('Y-m-d H:i', $feedbackTime);
$feedbackLen = hexdec(substr($rawhex, 8, 4));
$feedbackDeviceToken = substr($rawhex, 12, 64);
print "TIMESTAMP:" . $feedbackDate . "\n";
print "DEVICE ID:" . $feedbackDeviceToken. "\n\n";
}
fclose($fp);
?>
Hints: If you want to test the production push and feedback servers, use the adhoc distribution certificate and adhoc build to your devices. Moreover, the device tokens are different for the same device under sandbox and production servers.
43 comments:
How do I send the payload to the server? I can't find the code anywhere :(
The apns.php is the php code to send the payload to the APNS server
I get repeated errors when using terminal, and when using browser I get through once every 9 or 10 tries.
Here are errors
Warning: stream_socket_client() [function.stream-socket-client]: Unable to set local cert chain file `ck.pem'; Check that your cafile/capath settings include details of your certificate and its issuer in /Library/WebServer/Documents/notifyTest/anps.php on line 33
Warning: stream_socket_client() [function.stream-socket-client]: failed to create an SSL handle in /Library/WebServer/Documents/notifyTest/anps.php on line 33
Warning: stream_socket_client() [function.stream-socket-client]: Failed to enable crypto in /Library/WebServer/Documents/notifyTest/anps.php on line 33
Warning: stream_socket_client() [function.stream-socket-client]: unable to connect to ssl://gateway.sandbox.push.apple.com:2195 (Unknown error) in /Library/WebServer/Documents/notifyTest/anps.php on line 33
I added a few comments so the line # no longer match up. The line referred to is:
$fp = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
any ideas?
Thanks
Greg
You should put the ck.pem file under the same folder of apns.php script
or may be you can put the actual path of the file in the php script
Moreover, please check your generation of ck.pem, may be the file is not generated correctly.
Hello, This worked fine with OS3.0 beta 2, but now I get an error with beta 3:
UIApplication may not respond to -registerForRemoteNotifications
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[UIApplication registerForRemoteNotifications]: unrecognized selector sent to instance 0xd139e0'
Does anyone have an idea how to solve this?
Thank you
The API has changed in beta3, see the documentation
[[UIApplication sharedApplication]
registerForRemoteNotificationsTypes:(UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound)];
yes I noticed but even with the new one I get the same error. I tried copy pasting from apple doc, doesn't work either.
(I have no knowledg of objc I simply use apns to get important messages from my website).
Right now the code I have looks like this:
any idea what I should do to make it work?
#import "apnsAppDelegate.h"
@implementation apnsAppDelegate
@synthesize window;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSLog(@"Registering Remote Notications");
[window makeKeyAndVisible];
[[UIApplication sharedApplication] registerForRemoteNotificationsTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
// other codes here
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSLog(@"deviceToken: %@", deviceToken);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"Error in registration. Error: %@", error);
}
- (void)dealloc {
[window release];
[super dealloc];
}
@end
Thanks for your help!
Finally figured it out...
there is a typing mistake on apple push doc...
registerForRemoteNotificationTypes takes no 'S' after notification....
it used to be registerForRemoteNotifications so I guess that's why.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"%@",[[[launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"] objectForKey:@"aps"] objectForKey:@"alert"]);
}
gives me "warning control reaches end of non-void function"
How to send the payload to the application after submitting to app store. I mean , after testing the application and submitting to app store, how to send the payload from php to all device using the application?
This is the example I wanted :). Thanks a lot for this article and providing the source code for sending payload to server. Just like your last article, this article is also useful :)
Kapil
www.makeurownrules.com
My certificate will not export as a p12. What am I doing wrong?
Worked great, thanks!
You are saying there:
(6) Suppose you have imported the aps_developer_identity.cer to the keychain. Then you have to export these new cert and the private key of this cert (not the public key) and saved as .p12 files.
Okay, I did the first step. But how do I export the file and its private key in the keychain application? I cannot select .p12 as output file format? Only .pem, .cer and .p7b are available. Any ideas?
Thanks a lot.
Best regards,
Sebastian
A very helpful tutorial, appreciate the efforts.
This tutorial is for a distribution profile rt? Cant we test the push notification with the developer profile and test it on the simulator or the testing device?
If so, can some tell me the detailed step in doing so..
I have generated the APNs certificate and provisioning profile and installed them on the mac n the iphone, i have also save the .p12 on my mac. Can someone guide me from here?
Thank u,
NR
Hi all,
Works fine on a non-jailbroken 3GS but fails on a jailbroken 3G.
Has anyone managed to make this work on a jailbroken device ?
Im my case, "didRegisterForRemoteNotificationsWithDeviceToken" is never called so that I can retrieve the device token.
Thanks in advance for any help...
Please,
I'd like to know the steep of push notification deployment.
How I configure and communicate between my iphone application and the provider ?
And if I wish to have a notification at the fixed time (for exemple at 12'o clock)
Hi... Is it possible to have only one button in the alert (say "ok") that will launch the application when pressed...
As per the Apple document, we can get one button as "Ok" but if pressed it just dismisses the alert and will not launch application.
Please help...
you put null string "" in alert, if you want one button only.
Great tutorial, thanks!
How do you send emoji through APNS?
$msg = chr(0) . pack("n",32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload;
I would like to know what does this format specifies.
hi,
nice tutorial
I can not retrieve device token.
The two delegate method for device token found do not invoked.
plz help.
I get these errors
Warning: stream_socket_client() [function.stream-socket-client]: unable to connect to ssl://gateway.sandbox.push.apple.com:2195 (Connection timed out) in /home/content/o/r/a/orangeslide8/html/sendpush.php on line 15
Connection timed out
Warning: fwrite(): supplied argument is not a valid stream resource in /home/content/o/r/a/orangeslide8/html/sendpush.php on line 20
Fatal error: Call to undefined function socket_close() in /home/content/o/r/a/orangeslide8/html/sendpush.php on line 22
I’m getting this error
Warning: stream_socket_client() [function.stream-socket-client]: Unable to set private key file `apns-dev.pem’ in /home/bryan/sendpush.php on line 14
Warning: stream_socket_client() [function.stream-socket-client]: failed to create an SSL handle in /home/bryan/sendpush.php on line 14
Warning: stream_socket_client() [function.stream-socket-client]: Failed to enable crypto in /home/bryan/sendpush.php on line 14
Warning: stream_socket_client() [function.stream-socket-client]: unable to connect to ssl://gateway.sandbox.push.apple.com:2195 (Unknown error) in /home/bryan/sendpush.php on line 14
Warning: fwrite(): supplied argument is not a valid stream resource in /home/bryan/sendpush.php on line 17
Warning: socket_close() expects parameter 1 to be resource, boolean given in /home/bryan/sendpush.php on line 19
Warning: fclose(): supplied argument is not a valid stream resource in /home/bryan/sendpush.php on line 20
What do you mean by "second dummy app"?
About when does the feedback service send anything? I can send messages now but the feedback service is always empty.
There is an open source PHP/MySQL back-end for APNS. So if you want your own integration of push notifications on your own server, here you go :)
Main Link: http://www.easyapns.com
Google Code: http://code.google.com/p/easyapns/
Google Group: http://groups.google.com/group/easyapns
I'm successful in sending notifications in the development environment. Now i need to deploy this in the production environment. What are the necessary changes that needs to be done except that i need to change the gateway url to gateway.push.apple.com .
Do i need to generate a new ck.pem file with aps_production_identity.cer? and place it on the server?
You have to generate and download the production cert from the portal and generate the new ck.pem to the server.
Thanks very much for this post
In step 11, the following code will fail because device tokens can contain NUL bytes (two consecutive zeros), and this will result in your packed string being truncated before the
pack('H*', str_replace(' ', '', $deviceToken))
Instead, you should use something like this:
pack('H'.$device_token_length, str_replace(' ', '', $deviceToken))
where $device_token_length is 64, the length of a device token in nybbles.
For the error "Unable to set local cert chain file", uncomment the line "extension=php_curl.dll" in php.ini. Ensure that php_curl.dll is located in php/ext/ folder.
Restart apache & php, the problem will be gone.
Dear Concerned,
I can send the request for push message successfully from my MAC terminal.
Terminal Output:
$ php -f apns.php "My Apns Test" 2
Connection OK
sending message :{"aps":{"alert":" Apns Test","badge":2}}
//end of output
I have a valid device token id.But I can't receive any notifications on my device.
Please guide me..
Thanks,
I make the apns server in first attempt using the code and description.
I got this error while executing apns.php. But it is working perfectly in the local server and not in the remote server. Please advice me on this.
Warning: stream_socket_client() [function.stream-socket-client]: Unable to set local cert chain file `apns-dev.pem'; Check that your cafile/capath settings include details of your certificate and its issuer in /var/www/pushv2/apns.php on line 26
Warning: stream_socket_client() [function.stream-socket-client]: failed to create an SSL handle in /var/www/pushv2/apns.php on line 26
Warning: stream_socket_client() [function.stream-socket-client]: Failed to enable crypto in /var/www/pushv2/apns.php on line 26
Warning: stream_socket_client() [function.stream-socket-client]: unable to connect to ssl://gateway.sandbox.push.apple.com:2195 (Unknown error) in /var/www/pushv2/apns.php on line 26
Failed to connect 0
Hi,
In apns.php, from where do I get the device token.
Thanks.
I am facing error with PHP server code in index.php file.
Warning: stream_socket_client() [function.stream-socket-client]: Unable to set local cert chain file `ck.pem'; Check that your cafile/capath settings include details of your certificate and its issuer in http://localhost/apns/index.php on line 51
Warning: stream_socket_client() [function.stream-socket-client]: Failed to enable crypto in
http://localhost/apns/index.php on line 51
Please assist me where I am lacking. I have generate ck.pem from 2 different mac and aswell deployed via windows server also but having above errors.
someone know how the change of december 22 will affect this script?
I have successfully implemented code in your tutorial but it doesn't work, So my query is that Will it work for Jailbroken and unlock Iphone also
i received this message when i run your code at localhost:
Connection OK
sending message :{"aps":{"alert":"Nam1","badge":2,"sound":"beep.wav"}}
Is this successful?
My device did not receive any message.
How can i know that my message pushed to the server?
Great article...
I was able to successfully receive push notification.
Simple description, easy to follow.
Paresh Rathod
Thanks for this superb post..It helped me many times.am referring this blog whenever am doing push notification for my apps
Thanks for Gr8 Post !!!!!!
In the step 7 you say cert.p12 and key.p12 where do i get these two different p12's...Where will i get them from...
Post a Comment