Posts Tagged ‘APNS’

I recently discovered, that push notifications containing the word “(null)” (without the quotes) do not get pushed. They don’t break your APNS connection, simply never reach the recipient’s device.
Most likely, Apple wants to avoid some injection and I’m pretty sure, there are more words out there, that will not push.

In PHP, you can take simple precautions, to work around this:

$message = "(null) bla bla bla bla bla"; //this is our message
$messageFiltered = str_replace("(null)", "", $message);

I discovered this, when trying to push an iCal calendar event. Sometimes, iCal does not add the sender’s name, but (null) instead.

Hope, this is helpful to someone out there.
In case, you know more “forbidden words”, please leave a comment.

When implementing a push notification feature into your application, you usually create two different types of certificates: One for development (sandbox) and one for your customers/testers (production).

As you might already know, your device will automatically run in sandbox mode when launching the app directly from XCode.

So, the following method inside your app delegate will receive a device token, which is different than the one it receives, when you install it via iTunes:


- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken;

You have to keep in mind, that your push messages will not get delivered on this device, if you’re not running the development (sandbox) certificate on your server. Another important thing is the fact, that in case your server is running the production certificate and you try to send a push message to a device in sandbox mode, it will break connection to APNS. This means, that even push messages using the correct certificate will not get delivered any longer, until you reset connection to APNS.

So, if you sometimes wonder why push notifications fail during development of your app, consider the above.

Implementing Apple push notifications into your iPhone/iPod Touch or iPad app can be quite the challenging task. You really have to pay close attention to the official docs when setting it up and even then it might not work right out of the box.

If you’re new to APNS, you might want to check out the tutorials, I mentioned in one of my previous posts:

http://blog.boxedice.com/2009/07/10/how-to-build-an-apple-push-notification-provider-server-tutorial/
and
http://mobiforge.com/developing/story/programming-apple-push-notification-services

I can only repeat myself by saying, that these tutorials really rock and should definitely get you started.

If you don’t plan on running your own server, check out Urban Airship. They currently offer two different plans, which should perfectly fit your needs.

However, implementing APNS on your own server is most fun, as you’re likely going to face some issues :)

Rule #1, if nothing you tried so far works: Get some open source package and learn from the professionals: EasyAPNS is exactly what you might want to check out in this kinda situation.

Don’t forget to watch the video tutorial, which can be found right on the landing page.

Some additional hints and suggestions:

If your iPhone/iPod Touch/iPad app communicates with your server (maybe via php scripts), check out ASIHTTPRequest. This is some awsome package, that you can easily integrate into your existing XCode project. It’s perfect for contacting your server via POST requests. However, ASIHTTPRequest can do much more – just check out the official docs, which can be found on the developer’s website.

If you’re testing push notifications with your beta testers, make sure that you’re using the correct APNS certificate on your server. By correct I mean: Development certificate or Production certificate. In case you followed the tutorials above, you probably created both. In order to clear things up, check out the steps below:

  • If your iPhone/iPod Touch/iPad app communicates with your server (maybe via php scripts), check out ASIHTTPRequest. This is some awsome package, that you can easily integrate into your existing XCode project. It’s perfect for contacting your server via POST requests. However, ASIHTTPRequest can do much more – just check out the official docs, which can be found on the developer’s website.
  • If you’re testing push notifications with your beta testers, make sure that you’re using the correct APNS certificate on your server. By correct I mean: Development certificate or Production certificate. In case you followed the tutorials above, you probably created both. In order to clear things up, check out the steps below:
  1. Find your Provisioning certificate and the AdHoc one, you are using for your beta testers: Open up XCode and go to “Window”->”Organizer”. Now click on your Provisioning certificate, then right click -> “Reveal in Finder”. Do the same for your AdHoc certificate.
  2. Open up both files with TextEdit (DON’T EVER CHANGE ANYTHING IN THERE!!!) and look for the following string: “Environment”.
  3. Right below you should see either “Development” or “Production”.
  4. If you want your beta testers to receive push notifications and their AdHoc certificate says “Production”, you now know that you will have to use the APNS Production certificate on your server. Otherwise push messages won’t get delivered.

Happy pushing :)

If you’re an iPhone, iPod Touch or iPad developer, you might have heard about Apple’s push notification service. It’s a convenient way to send messages to your users or even allow them to communicate with each other (via your server). You can find great tutorials on the internet, that show you how you can get started. I can especially recommend:

http://blog.boxedice.com/2009/07/10/how-to-build-an-apple-push-notification-provider-server-tutorial/
and
http://mobiforge.com/developing/story/programming-apple-push-notification-services

I admit, it really depends on the scale of your service and the possible message load, but you might wanna pay close attention to the following statement, which can be found in the official Apple docs:

Refrain from opening and closing the connections to the APNs for each push notification that you want to send. Rapid opening and closing of connections to the APNs will be deemed as a Denial-of-Service (DOS) attack and may prevent your provider from sending push notifications to your applications.

What does this mean?


It means, that you should retain an open connection to APNS and not open/close it every time you send a message. Most php scripts out there dealing with APNS exactly do that! They open a connection, send a single message or a couple of messages from your database and then close the connection. As I already mentioned, it depends on how you are using APNS. If you send messages every hour or every couple of hours, you should be fine and there is probably nothing to worry about.

However, if you are rather looking for a dynamic way of pushing (user to user via your server), you of course wanna avoid putting all messages in a queue and sending them out every hour.

What you need in this case, is something a bit more advanced.

[I don't claim for this solution to be the best one - it certainly is not - but it GET'S THE JOB DONE]

So, let’s take a look at it, shall we?

1) We need to create an empty php script. You can do this in a text editor or whatever php editor you prefer. Name it PushScript.php or give it some other meaningful name.


<?

set_time_limit(0); //Keep process running forever...

$timeNow = strtotime("now"); //get current time and time + 2 hours. I read, that an idle connection might time out after 2 hours, so we will later use this information to re-connect

$inTwoHours = strtotime("+ 2 hours"); 

First, we set time limit to 0. This makes sure, that the php script does not accidentally time out.
Next, we get the current time and another time stamp (+2 hours). We will later use this to close connection to APNS and re-open it.

Why are we doing that?

Well, I read on several blogs, that Apple might close an idle connection after some time. Some people report, that it can actually stay open for several days, but keeping it down to 2 hours, will most likely give us the least trouble.


//connect to APNS - ONLY 1 time after script is started
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'nameOfDevCertificateInSameFolder.pem');
$apnsConnection = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
error_log(date('Y-m-d H:i')." - Successfully connected to APNS", 3, 'PushLog.log'); //log, that we are successfully connected - used for debugging

The script runs from top to bottom and when we call it we wanna make sure, that our server makes a connection to APNS.


//let's start our "deamon"
while (true) {

 //here we are sending a single message to a single device every 60 seconds. In theory you could run some mySQL query to empty a queue.

 $deviceToken = '************************************************'; // your device token here

 $message = 'Hi, I'm a push message!';
 $badge = (int)$argv[2];
 $sound = 'soundFile.caf'; //name of the sound file inside the XCode project.
 // Construct the notification payload
 $body = array();
 $body['aps'] = array('alert' => $message);
 if ($badge)
 $body['aps']['badge'] = $badge;
 if ($sound)
 $body['aps']['sound'] = $sound;

 $payload = json_encode($body);
 $msg = chr(0) . pack("n",32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload;
 error_log(date('Y-m-d H:i')." - Pushing message to APNS", 3, 'PushLog.log'); //another log entry
 fwrite($apnsConnection, $msg); //this pushes the message to APNS

This is actually our “deamon”. It will loop and loop and because we set the time limit to 0, this process won’t get killed. Look at the code comments, it’s pretty much self explanatory.


//now let's close and re-open connection every 2 hours
 if (strtotime("now") >= $inTwoHours) {
 $timeNow = strtotime("now");
 $inTwoHours = strtotime("+ 2 hours");

 //close APNS connection
 fclose($apnsConnection);
 error_log(date('Y-m-d H:i')." - Closing connection to APNS", 3, 'PushLog.log');

 //re-open APNS connection
 //connect to APNS - ONLY 1 time after script is started
 $ctx = stream_context_create();
 stream_context_set_option($ctx, 'ssl', 'local_cert', 'apns-dev.pem');
 // assume the private key passphase was removed.
 // stream_context_set_option($ctx, 'ssl', 'passphrase', $pass);
 $apnsConnection = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);

 error_log(date('Y-m-d H:i')." - Reconnecting to APNS", 3, 'PushLog.log');
 }

Now, we’re using the time stamps, we created earlier. In case our old time stamp has expired (script ran longer than 2 hours), we renew it.

Finally:


sleep(60); // loop every X seconds
?>

Pause the loop for X seconds, until we start it again.

That’s pretty much it :)

When reading the code, you might have noticed, that we’re sometimes writing information to PushLog.log. I can highly recommend this. It will show you how many times you actually connect/disconnect and send a message. This way, you can see what your script is doing and that it does, what we want it to do.

In order to get this up and running, create the php file and the PushLog.log file (simple text file – just make sure, it has a .log suffix, instead of .txt).

Put both files, plus your push certificate into the same folder on your webserver and you’re good to go. Now, you only need to call the php script from your browser or terminal and you got your very own php deamon.

Hope, this is helpful. In case, you can’t get it to work, make sure the solution from the tutorials above works. Then use my script.

Happy pushing :)

[Code posted without any warranty whatsoever];

An App, you might like:
We recommend…
You might also like…
Get Adobe Flash playerPlugin by wpburn.com wordpress themes