Apple Push Notification mit PHP (APNS)

Heute möchte ich eine Anleitung veröffentlichen, mit der auf einfachste Art und Weise Nachrichten an alle i-Devices (iPhone, iPad, …) gesendet werden können. Zunächst müssen wir jedoch ein paar Vorbereitungen treffen:

  • Erstellung der Zertifikate:
    1. Sie müssen im Program Portal eine App ID ohne .* erstellen.
    2. Erstellen Sie eine Anfrage zur Zertifikat signierung mit der Schlüsselbundverwaltung und speichern Sie dieses auf die Festplatte unter CertificateSigningRequest.cert.
    3. Nun laden sie die Datei im Program Portal hoch und warten bis das neue Zertifikat erzeugt wurde. Dieses speichern Sie unter aps_developer_identity.cer. Die beiden Dateien sollen Sie an einem sicheren Ort speichern. Sie werden für eine Erneuerung des Zertifikats benötigt !
    4. Importieren Sie das heruntergeladene Zertifikat in die Schlüsselbundverwaltung. Beim Import “Anmeldung” als Ziel angeben.
    5. Suchen Sie das importierte Zertifikat im Bereich Meine Zertifikate und exportieren sie zunächst das Zertifikat und anschließend den Schlüssel als cert.p12 bzw. key.p12
    6. Anschließend gehen Sie mit dem Terminal in das Verzeichnis der exportierten Dateien und setzen folgende Befehle ab:
      
      openssl pkcs12 -clcerts -nokeys -out cert.pem -in cert.p12
      openssl pkcs12 -nocerts -out key.pem -in key.p12
      
    7. Nun können Sie noch das Passwort bei Bedarf entfernen.
      
      openssl rsa -in key.pem -out key.unencrypted.pem
      
    8. Als letzten vereinen Sie die jeweiligen Dateien:
      cat cert.pem key.unencrypted.pem > ck.pem
      
    9. Beachten Sie, dass die Datei unbedingt mittels chmod 400 ck.pem gesichert werden muss !
  • Zum Senden einer neuen Push-Notification wird nun noch das folgende Script benötigt:
    
    <?php 
    
    $deviceToken = 'd919eba8711a4a398aadb80c25bb5e5dc66257200a3ee4591aa170895404fa3a';
    // 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:219
    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);
    ?>
    
  • Ihr iPhone App benötigt die folgenden Methoden:
    
    - (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);
    }
    
    
  • Schließlich noch das Feedback Script:
    <?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);
    ?>

7 thoughts on “Apple Push Notification mit PHP (APNS)”

  1. Schönes Tutorial,

    der Produktion Pfad ist jedoch
    ssl://gateway.push.apple.com:2195 hattest die 5 vom Port vergessen.

    gruß
    Marcel

  2. Nettes Tutorial! Ich hab bei meinem letzten Script aber doch lieber auf WAP PAP für die Kommunikation zurück gegriffen: Push Notification – Schade, dass das immer noch so verdammt teuer ist.

    Viele Grüße,

    Jan

  3. Hallo an die APNS -Nutzer,

    wir haben den PUSH fast identisch umgesetzt. Den Zertifikat haben wir nur komplett exportiert und entsprechend umgewandelt. Problem: stream_socket_client ist da und Schreiben funktioniert auch, aber es kommt nichts an! Und keine Hinweise auf Fehler.
    Woran kann es liegen was meint Ihr?

  4. I’m amazed, I must say. Seldom do I encounter a blog that’s both equally educative and interesting,
    and without a doubt, you’ve hit the nail on the head. The issue is something which too few folks are speaking intelligently about. Now i’m very happy that I found this during my hunt for something
    relating to this.

Leave a Reply

Your email address will not be published. Required fields are marked *