Friday, February 25, 2011

Push Notification Setup pcntl_signal_dispatch

I really can't follow instructions or maybe the instructions I follow are all unclear.  In any case this is my journey through setting up Push Notification for our server.  If you run into any problems along the way, i have a Troubleshooting section below.

First of all, you need to have a server with port 2159 (outbound) open so that you can send notifications to Apple's servers.  Shared Hosting plans alone usually do not allow this port to be open.  Bluetooth, Host Gator, and others (not GoDaddy) will open port 2159 if you purchase the dedicated IP plan (roughly $2.50/month).  Other options would be to purchase a dedicated server or VPS (about $30/month) or go to urban airship.  We have big dreams, so Urban Airship is not feasible for us.   We have no money, so shared hosting with dedicated IP is the winner.

Once you get a server with port 2159 open, and you want to use the apns-php project, make sure you have PHP 5.3.  Otherwise, you may run into trouble.  It is unknown what issues there are.

To get started, you need to create your Push Certificate.  Follow these instructions from the apns-php project.

Generate a Push Certificate

To generate a certificate on a Mac OS X:
  1. Log-in to the iPhone Developer Program Portal
  2. Choose App IDs from the menu on the right (or click here)
  3. Create an App ID without a wildcard. For example
  4. Click the Configure link next to this App ID and then click on the button to start the wizard to generate a new Development Push SSL Certificate(Apple Documentation: Creating the SSL Certificate and Keys)
  5. Download this certificate and double click on aps_developer_identity.cer to import it into your Keychain
  6. Launch Keychain Assistant (located in Application, Utilities or search for it with Spotlight) and click on My Certificates on the left
  7. Expand Apple Development Push Services and select Apple Development Push Services AND your private key (just under Apple Development Push Services)
  8. Right-click and choose "Export 2 elements..." and save as server_cerificates_bundle_sandbox.p12 (don't type a password).
  9. Open Terminal and change directory to location used to save server_cerificates_bundle_sandbox.p12 and convert the PKCS12 certificate bundle into PEM format using this command (press enter when asked for Import Password):
  10. openssl pkcs12 -in server_cerificates_bundle_sandbox.p12 -out server_cerificates_bundle_sandbox.pem -nodes -clcerts
  11. Now you can use this PEM file as your certificate in ApnsPHP!

You can most likely skip the part about the Entrust Certificate because most Linux servers already had this in place even if you didn't know about it.  There are many articles saying to just try to push a notification to apple's sandbox server and if it fails then you can look into getting one.  In most cases it won't.

Once I got through these steps I looked at the requirements on apns-php and realized my server doesn't have PHP 5.3.  So instead of trying apns-php, I opted for a simpler solution.  On to the next tutorial... 

At this tutorial I wanted the PHP code to test out if the connection could be made.  So I wanted something quick and simple.  This is what I gathered from that tutorial. 
if (isset($_POST['device']) && strlen($_POST['device']) > 0) {
echo "Trying Push";
$apnsHost = '';$apnsPort = 2195;$apnsCert = 'server_certificates_bundle_sandbox.pem';
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
if (strlen($errorString) > 0) {
  echo "errored:  ";  echo $errorString;  exit;}
echo "SSL Cert is Good!";
$payload['aps'] = array('alert' => 'This is the alert text', 'badge' => 1, 'sound' => 'default');$payload = json_encode($payload);
$deviceToken = $_POST['device'];
$apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
fwrite($apns, $apnsMessage);
<form method='POST'><input type='text' name='device' value='' /><input type='Submit'>form>
Next I got the Objective-C code from the apns-php project:

That's it!  If it's not working for you, read on...

So you went through all the steps and it's still not working!?  This happened to me too, fellow idiot.  Below are the error messages and what worked for me.  Hopefully it works for you too.

error no valid 'aps-environment' entitlement string found
No, I didn't need to add the 'aps-environment' attribute.  For some reason, the "Code Signing Entitlements" build setting had gone blank so Xcode didn't know where to find my Entitlements.plist.  Here's how you add it back:
- Go to project -> Edit Active Target -> Build tab.
- Search for "Code Signing Entitlements".
- Enter your "Entitlements.plist" file in the Value column.  If you have it in the project's root directory, that's all you need.  If you have it in a folder you need to specify the folder.

Another solution was to re-create the provisioning file that you are using to build the app and download and drag it into Organizer.  It didn't work for me, but this was the first thing I tried so it might have helped.

The executable was signed with invalid entitlements.
I apparently had to learn all my lessons at once.  I'm not sure why this didn't happen to me sooner, but to resolve this problem, I had to check, not uncheck, my "get-task-allow" property.  It turns out that this property needs to be checked for Developer builds and unchecked for Ad Hoc builds.

I get no errors, but the message still doesn't get to my device
I have to ask:
- Is the device turned on?
- Do you have wifi or cellular internet connection?
- Are you on the right server?
- When opening the app, did you allow Push Notifications?
- Did you put your Device ID into the PHP code?  If so, you need the device TOKEN instead.  The objective-c code from the apns-php project prints the device token in the logs.


  1. Hi, I have a question do I need to have both inbound and outbound ports open in host gator? Can it be just the outbound?

  2. Only outbound is needed. Thanks for the question, updating the post..

  3. This comment has been removed by the author.

  4. DreamHost is ultimately one of the best hosting provider with plans for all of your hosting requirments.