51

Is there a sample project showing how to use APNS on the IPhone and how to set up things? I'm currently looking at the documentation but it would be nice to have some working code to pick apart and see how it all works together?

I can't seem to find anything using google or in the iphone dev center.

Janak Nirmal
  • 22,706
  • 18
  • 63
  • 99
froh42
  • 5,190
  • 6
  • 30
  • 42
  • 2
    Check here http://arashnorouzi.wordpress.com/2011/03/31/sending-apple-push-notifications-in-asp-net-part-1/ its exactly what you are looking for. – Moon Jul 25 '11 at 11:02
  • @ froh42 Have you got any satisfactory code? I also want sample code for step by step implementation.If you have then please provide it to me. Thank you in advance. – Zalak Patel Oct 14 '14 at 11:21

10 Answers10

59

The worst part about setting up the push notification service is the provisioning. The major stumbling block that I came across was that there is a certificate and a key in the .cer file you download from Apple's site, I wrote a system service in C# that sent out notifications and the connections kept failing because I had exported the certificate and not the key.

I don't recall who originally wrote this, here is a little bit of code in python that helped me out when I was first testing the notification service. I like it because it is very simple and works well during testing.

import socket, ssl, json, struct

# device token returned when the iPhone application
# registers to receive alerts

deviceToken = 'XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX' 

thePayLoad = {
     'aps': {
          'alert':'Oh no! Server\'s Down!',
          'sound':'k1DiveAlarm.caf',
          'badge':42,
          },
     'test_data': { 'foo': 'bar' },
     }

# Certificate issued by apple and converted to .pem format with openSSL
# Per Apple's Push Notification Guide (end of chapter 3), first export the cert in p12 format
# openssl pkcs12 -in cert.p12 -out cert.pem -nodes 
#   when prompted "Enter Import Password:" hit return
#
theCertfile = 'cert.pem'
# 
theHost = ( 'gateway.sandbox.push.apple.com', 2195 )

# 
data = json.dumps( thePayLoad )

# Clear out spaces in the device token and convert to hex
deviceToken = deviceToken.replace(' ','')
byteToken = bytes.fromhex( deviceToken ) # Python 3
# byteToken = deviceToken.decode('hex') # Python 2

theFormat = '!BH32sH%ds' % len(data)
theNotification = struct.pack( theFormat, 0, 32, byteToken, len(data), data )

# Create our connection using the certfile saved locally
ssl_sock = ssl.wrap_socket( socket.socket( socket.AF_INET, socket.SOCK_STREAM ), certfile = theCertfile )
ssl_sock.connect( theHost )

# Write out our data
ssl_sock.write( theNotification )

# Close the connection -- apple would prefer that we keep
# a connection open and push data as needed.
ssl_sock.close()

There's also a rails gem called apn_on_rails that seems to work pretty well if you're developing a rails application, I just saw it today and was able to send out notifications from the console.

On the iPhone side you'll just need to call the following to register for all types of notifications:

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

To receive the device token you'll need to implement the following delegate methods:

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error

During testing you can just kick the deviceToken to the console with NSLog, then paste it into the python script above, in production you'll obviously need to set up some method to get the token to your servers.

Also, in production you'll need to query Apple's feedback service and remove device tokens from users who removed your app.

David H
  • 40,852
  • 12
  • 92
  • 138
jessecurry
  • 22,068
  • 8
  • 52
  • 44
  • 1
    Check out Simon's answer below - he's wrapped up the Python code in a nice library which you can get here: http://github.com/simonwhitaker/PyAPNs – David Underhill Jan 21 '11 at 10:01
  • 1
    WARNING - this code is for version 0 of the protocol. Apple is now up to version 2. – David K. Hess Nov 16 '13 at 14:27
  • Since writing this answer I've moved almost entirely to Urban Airship to provide push notification services. I've heard some good reviews for http://helios.io but have never used it myself. – jessecurry Nov 20 '13 at 15:12
  • @jessecurry Thank you so much for this, two additional questions, using above code is there a way to send a notification to all my users without going in a loop? is there a step by step tutorial for implementing airship on the python server side, can you share your code? – liv a Jan 20 '14 at 19:44
  • line: `theNotification = struct.pack(theFormat, 0, 32, byteToken, len(data), data)` got error: `struct.error: argument for 's' must be a bytes object` – TomSawyer Apr 24 '21 at 19:20
15

A good place to start is Urban Airship. You can set up a free basic account that will do all of the server-side work of sending push notifications to Apple's servers. They also do a great job of walking you through all of the steps needed to get your application working with their service, and have excellent sample code that shows how to register your application for notifications.

I have no other affiliation with them other than being a happy user of their service.

Scott K.
  • 1,761
  • 15
  • 26
  • I'm also currently going this route as most shared hosting do not allow connection to Apple's custom ports for push notifications. I remember seeing a Python program for Google App Engine before which sends out REST requests to Urban Airship (useful for cron based notifications) but I can't seem to find it at the moment. Please let me know if you guys stumble upon it. Thanks! – pm_labs Apr 06 '10 at 13:11
  • Yes, their service works well. They've expanded to a true store-and-forward service called AirMail which takes most of the work off the backend - all it needs to do now is send JSON with embedded HTML to the Urban Airship servers; they take care of sending the notifications and serving up the HTML when requested. – Joe McMahon Apr 15 '10 at 21:27
  • Hey can you please help me for implementing Urban Airship API in my iPhone app ? see what problem i'm getting is : http://stackoverflow.com/questions/5634125/having-problem-with-urbanairship-notification-iphone i hope that you must be having some solution. thanks – Devang Apr 12 '11 at 11:20
14

In case it helps, I've written a Python library, PyAPNs, for interacting with the Push Notification Service on the server side:

http://github.com/simonwhitaker/PyAPNs

Simon Whitaker
  • 20,506
  • 4
  • 62
  • 79
12

http://blog.boxedice.com/2009/07/10/how-to-build-an-apple-push-notification-provider-server-tutorial/

This one helped me a lot with making provider side code on linux server with PHP.

Mladen
  • 25,578
  • 11
  • 39
  • 48
  • Word of caution: most shared hosting do not have the ports open specific for APNS. So if you want to go this route, you might need to have it hosted in a VPS at least. – pm_labs Apr 06 '10 at 13:18
5

There really isn't much code to write on the iPhone side. You need to get the unique token of the iPhone or iPod Touch and then relay that token to your server. Getting the token requires a call to UIApplication but there's no predefined way of getting that to your server. One of my apps performs an HTTP POST to a PHP script that puts the token into a database.

If you're curious about provisioning and the setup of the certificates, etc..., you might check out the Apple Push Notification Service Programming Guide.

Ben Gotow
  • 14,805
  • 3
  • 42
  • 47
  • Ben, yes it does not look to complicated from the documentation and I'm also positive I'll work out the provisioning (haven't looked at that, yet ...) It would have been just nice to have a step-by-step example of how to set up things. – froh42 Jun 30 '09 at 09:35
4

I know this is a very old question and has received many answers but I found the tutorial of Rey Wenderlich very useful and wanted to share it for APNS beginners. It is very useful and very easy to understand.

halfer
  • 19,824
  • 17
  • 99
  • 186
Aditya
  • 4,414
  • 5
  • 29
  • 40
3

I know that was late, but you should see MonoPush project. It seems they will be provide a new way push integration as well as detailed statistics, including statistics over the map.

fyasar
  • 3,996
  • 2
  • 42
  • 55
2

Look in the forums in the iPhone dev center, supposedly there are a lot of examples of server side code to talk to Apple's push server.

Kendall Helmstetter Gelner
  • 74,769
  • 26
  • 128
  • 150
1

Here's a tested php5 version of jessecurry's test-script. It uses the 'enhanced message format', and tries to catch and display errors from apple. This might give an indication as to what's wrong with your messages.

// Settings
$deviceToken = 'xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx';
$apnsCert = 'apns-dev.pem';
$apnsHost = 'gateway.sandbox.push.apple.com';
$apnsPort = 2195;

// Prepare payload
$payload = 
array(
    'aps' => array(
        'alert' => 'Hi, this is an alert!',
        'badge' => 8
    )
);
$payload = json_encode($payload);
print($payload . "\n");

// Connect to Apple Push Notification server
$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 (!$apns) {
    die('Error creating ssl socket');
}
// Don't block on reading from the socket
stream_set_blocking ($apns, 0);

// Send payload in enhanced message format ( http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingWIthAPS/CommunicatingWIthAPS.html#//apple_ref/doc/uid/TP40008194-CH101-SW1 )
$apnsMessage = 
    // Command "1"
    chr(1)
    // Identifier "88"
    . pack('N', 88)
    // Expiry "tomorrow"
    . pack('N', time() + 86400)
    // Token length
    . chr(0) . chr(32) 
    // Device token
    . pack('H*', str_replace(' ', '', $deviceToken)) 
    // Payload length
    . chr(0) . chr(strlen($payload)) 
    // Actual payload
    . $payload . $payload;
fwrite($apns, $apnsMessage);

// Pause for half a second to check if there were any errors during the last seconds of sending.
usleep(500000); 

checkAppleErrorResponse($apns);

// Close connection -- apple would prefer that we keep
// a connection open and push data as needed.
fclose($apns);

function checkAppleErrorResponse($apns)
{
    $responseBinary = fread($apns, 6);
    if ($responseBinary !== false && strlen($responseBinary) == 6)
    {
        print(
            "\n"
            .'Error message recieved from Apple.'."\n"
            .'For the meaning, refer to: "Provider Communication with Apple Push Notification Service"'."\n"
        );
        $response = unpack('Ccommand/Cstatus_code/Nidentifier', $responseBinary);
        var_dump($response);
    }
}
Simon Epskamp
  • 8,813
  • 3
  • 53
  • 58
1

Try the NWPusher project on GitHub. It provides OS X and iOS apps to send push notifications manually, or you can use the included Objective-C library directly.

leo
  • 7,518
  • 1
  • 24
  • 25