b2cloud

26th July 2011

iOS push notifications in PHP

Guides | Tutorial By 5 years ago

Push notification servers are very tedious to begin with. Here is a step by step guide on how to set up one correctly in PHP. Remember that push notifications are only available to actual devices, you will not be able to do this on the simulator.

Some background behind push notifications:
Instead of every push notification app on your phone maintaining a constant internet connection listening for messages, Apple’s server handles sending messages to the phone for you, meaning only one connection from your phone to the APNS (Apple Push Notification Server) is required, meaning your app doesn’t even need to be open for the phone to receive a push notification. Push notifications can contain a message, a badge number, a sound and custom (user) data for the app to use.

 

Find your App ID in the list of your apps and hit the configure link for it. Click the configure buttons for both development and production and upload a certificate generated by Keychain Access. Download both development and production certificates after they have been created. From your downloads folder double click on each of the downloaded certificates to add them into Keychain Access.

In Keychain Access find both of the push certificates under the certificates category on the left. For the development one, expand the certificate so you can see the private key underneath and select both the cert and it’s private key, then right click and choose ‘Export 2 items…’, save it as a .p12 file to the DESKTOP with the name ‘cert-dev.p12’. When prompted for a password, enter none and just click OK, you will be prompted for your user password however. The name doesn’t really matter too much, but the code later on uses this name. Find the production cert and also export it and it’s private key, calling it ‘cert-prod.p12’.

Make sure the files are still on your desktop and open the Terminal (found in the /Application/Utilities/ folder), type the following commands line by line, when asked for the import password just push enter as you never set one.

cd ~/Desktop
openssl pkcs12 -in cert-dev.p12 -out cert-dev.pem -nodes -clcerts
openssl pkcs12 -in cert-prod.p12 -out cert-prod.pem -nodes -clcerts

You can delete the .p12 files now, the .pem ones are the ones needed to actually send push notifications. Make sure nobody gets their hands on these or they will be able to send out bogus messages to your users. Save these .pem files on your web server somewhere, behind the public folder so nobody can access them.

Now we’re ready for some code, we’ll start with the iPhone.

In your application delegate under application:didFinishLaunchingWithOptions:, enter this line of code. This will present the user with the popup dialog asking if they wish to receive notifications.

[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];

Add the following method to your app delegate, under application:didFinishLaunchingWithOptions:

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
	const unsigned* tokenBytes = [deviceToken bytes];
	NSString* deviceTokenString = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
						  ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
						  ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
						  ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];

	NSLog(@"%@", deviceTokenString);
}

The deviceTokenString variable contains the device token in hex. Make sure you read this next part, it is very important and caused me lots of grief when starting out with push notifications. The device token is not the device id, it is not unique for the phone, and not unique per application, and will change from development to production. Whatever device tokens you collect during development, you must separate them from the ones you collect during production or the phone will not receive them.

So with that out of the way, you need to somehow get your device tokens to your server, and have a way to distinguish development tokens from production tokens. I wont walk you through this part.

And finally, the code that sends the message from your server. You will need to make sure port 2195 is open for both outgoing and incoming connections.

Customise the message, badge and sound at the start of the code. For custom sounds, the sound is the filename of the sound included in your apps bundle, otherwise just use ‘default’. Change the $development boolean to switch between development and production pushes.

$message = 'Hello';
$badge = 3;
$sound = 'default';
$development = true;

$payload = array();
$payload['aps'] = array('alert' => $message, 'badge' => intval($badge), 'sound' => $sound);
$payload = json_encode($payload);

$apns_url = NULL;
$apns_cert = NULL;
$apns_port = 2195;

if($development)
{
	$apns_url = 'gateway.sandbox.push.apple.com';
	$apns_cert = '/path/to/cert/cert-dev.pem';
}
else
{
	$apns_url = 'gateway.push.apple.com';
	$apns_cert = '/path/to/cert/cert-prod.pem';
}

$stream_context = stream_context_create();
stream_context_set_option($stream_context, 'ssl', 'local_cert', $apns_cert);

$apns = stream_socket_client('ssl://' . $apns_url . ':' . $apns_port, $error, $error_string, 2, STREAM_CLIENT_CONNECT, $stream_context);

//	You will need to put your device tokens into the $device_tokens array yourself
$device_tokens = array();

foreach($device_tokens as $device_token)
{
	$apns_message = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $device_token)) . chr(0) . chr(strlen($payload)) . $payload;
	fwrite($apns, $apns_message);
}

@socket_close($apns);
@fclose($apns);

That should be it, you now have a working push notification server. Note that if for whatever reason you send a bad device token or a development token during production (or vice versa) to the APNS within the foreach loop, Apple will drop your connection, so if not all or none of your messages are getting through, check this.

  • Pingback: Push Notification doesn’t work()

  • Komlos Khmer

    Hi thank you for php code for push notification for iPhone. How do I use your php script to push notification to live production because a live production has no device token. In my app, I have 1000s people download my app. I don’t know their device token ID. In $device_tokens = array(); what is going to be for live production env.

    • Tom

      You need to build a way to get “deviceTokenString” from my code snippet above to your server and stored in a database. Then that goes into the $device_tokens array

  • Komlos Khmer

    Hi thank you for php code for push notification for iPhone. How do I use your php script to push notification to live production because a live production has no device token. In my app, I have 1000s people download my app. I don’t know their device token ID. In $device_tokens = array(); what is going to be for live production env.

    • Tom

      You need to build a way to get “deviceTokenString” from my code snippet above to your server and stored in a database. Then that goes into the $device_tokens array

  • Demo Narola

    Hi,I need to know, how can i send Notification in iphone device when iphone notification option is disable.

    • Tom

      That’s impossible, however you can still present a local UILocalNotification

      • Demo Narola

        Sorry, i forgot to mention that i am creating one php script which will send message from server to iphone device. now, according to our requirement we have to send push notification to iphone from php script and also need to receive notification in iphone when setting of push notification setting is disabled. is it possible using php?

        • Tom

          If it’s disabled then like I said, it’s not possible. But you can download them in advance from the server and schedule them later as UILocalNotifications

          • Demo Narola

            Hi,Thanks for your reply. actually i want to implement socket programming code in php when the push notification setting is disabled.so, i don’t need to code UILocalNotifications and not make load on application. is it any way to do with socket programming in php ?

          • Tom

            Your socket code will close when you close the app, not to mention Apple will reject you if they find you trying to circumvent their push notification system.

          • tejas g

            Yes You are right. But we will implement socket programming when user will be on conversation window . So At that time app will be in active stage.

  • Brian

    We are using the same code. Pem files are generated as mentioned above. Server is not showing any error. But app is not receiving any notifications. I have given both delegate methods..

    – (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;

    – (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler;

    Both are not being called. kindly help

    • Tom

      Are you sure your script is being called?

      Also, make sure your server has ports 2195 and 2196 open for incoming and outgoing traffic. These ports are used to communicate with Apple

      • Brian

        Script is being called. Now the response message shows error 110 , Connection timed out.

        • Brian

          I tried another server and solved 110 error, now error status is 0, so I guess no erro. But no response in App end

          • Tom

            You need to make sure that you have those ports open (2195 for production, 2196 for development)

            Ask your shared server host to open them for you, however sometimes they wont do this on shared hosting

          • Brian

            Thanks a lot. That helped me

  • Jim Copley

    I have followed all the steps as like mentioned above. While running the server side no error showing. Yet not received any notification form apns server.

    When the msg will receive to the corresponding iPhone.

    And didReceiveRemoteNotification function is not triggered while running app front or background.

    When it will trigger and when i get the msg? Kindly provide solution for this issue.

    • Tom

      Please check you have ports 2195 and 2196 open for incoming and outgoing traffic. Check my messages below with Brian, I think he had the same issue.

      • Jim Copley

        Thanks Tom… Here i have checked the port (2195 and 2196).

        Checked via terminal in mac : telnet gateway.sandbox.push.apple.com 2195 / telnet gateway.sandbox.push.apple.com 2196

        it says Connected to gateway.sandbox.push.apple.com

        So if i use this line openssl s_client -connect gateway.sandbox.push.apple.com:2195

        It says like

        verify error:num=20:unable to get local issuer certificate

        What is the issue. How to rectify this?

        Anything i have to do?

        • Tom

          The certificate error is because the connection requires your certificate.pem
          As for the php not working for you, I’m not sure. We use the same code and the only times I have ever had problems is with those ports, all other times it works fine providing I’ve got the right certificate, and have setup push notifications correctly in the app.

          • Jim Copley

            Thanks tom. I have created from the scratch. Now its working.

  • bindu

    Warning: stream_socket_client(): unable to connect to ssl://gateway.sandbox.push.apple.com:2196 (Permission denied) in /var/www/html/Pocket_Sale/administrator/WebServices/push_notifications.php on line 36

    • Tom

      Please read the other comments about port 2195

  • Jude Michael Murphy

    It is to my understanding that Apple is rejecting apps that are storing and using UDIDs. Does this code still work, and if it does, what other identifier can I use to send a push to a device?

    • Tom

      The push identifier is different to the one Apple has been rejecting apps for.

      Apple has been rejecting those that use the device’s unique identifier ([UIDevice currentDevice].uniqueIdentifier), the push identifier is different and is unique per app per device, and changes when you reinstall the app, so it cant be used for tracking across apps.

Recommended Posts

7 Tips From Apple's iOS Human Interface Guidelines

Post by 5 years ago

With Apple’s iOS Human Interface Guidelines now available on the iBook Store, here some important tips to keep in mind when designing an app.

Got an idea?

We help entrepreneurs, organizations and established brands from around
the country bring ideas to life. We would love to hear from you!