Categories
Ontwikkelaars Software Ontwikkeling Tools (NL) Web (NL)

APNS: Apple Push Notificatie Service voor iPhone / IOS

Push notificaties, misschien ken je ze wel van de NOS als er groot nieuws in Nederland is. Deze kun je versturen naar mobiele telefoons (Android / IOS ) als je een app ontwikkeld. In dit artikel leg ik uit hoe je dat doet voor IOS op iPhone via Apple Push Notificatie Service door gebruik te maken van PHP.

I18N: This article is also available in English (click to switch)

HTTP/2 is een nieuwe standaard op het web, daarover later meer. Bij Apple gaan ze vanaf November 2020 helemaal over naar HTTP/2. Je kan dan niet meer verbinden via de HTTP/1 “legacy” API. In dit artikel vertel ik je hoe je verbinding kunt maken met APNS op de nieuwe manier.

Apple’s service om push notificaties te versturen (APNS: Apple Push Notification Service) gebruikt JSON web tokens voor authenticatie methode waar voorheen certificates werden gebruikt.

Hiervoor gebruiken we bij SaMauto een JWT package / library van Luís Cobucci om dit te kunnen realiseren (Bekijk lcobucci/jwt op GitHub of op packagist.org.

Om dit package via composer toe te voegen aan je project gebruik je het volgende commando:

composer require lcobucci/jwt

De verbinding wordt gemaakt door gebruik te maken van JWT (JSON Web Tokens – RFC 7519) dit heet in technisch jargon Token Based Authentication.

Om een sleutel te krijgen met je naar developer.apple.com surfen, inloggen, naar “Certificates, Identifiers & Profiles -> Keys“ gaan en een sleutel (private_key.p8) downloaden.

Let op!
De sleutel kan je maar één keer downloaden. Bewaar deze goed!

Hieronder een voorbeeldscript:

<?php
require __DIR__ . '/vendor/autoload.php'; // Stap 0: PSR-0 Autoloader

// Stap 1: Importeer de Lcobucci\JWT library
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Ecdsa\Sha256;
use Lcobucci\JWT\Configuration;

// Stap 2: specificeer de configuratie

$device_token = "uniek_token_van_het_apparaat";
$apns_topic = 'nl.samauto.ios-applicatie';
$p8file = "/home/dave/samauto/sleutel_van_apple.p8";
$url = "https://api.sandbox.push.apple.com/3/device/$device_token"; // hier gebruik ik de sandbox API


$config = $container->get(Configuration::class);
assert($config instanceof Configuration);

// Stap 3: Genereer een JWT Token.
$token = (string) $config->createBuilder()
->issuedBy("DEF123GHIJ") // het TeamId
->issuedAt(time()) // de tijd dat het token is uitgegeven
->withHeader('kid', "ABC123DEFG") // Encryptie sleutel van Apple
->setKey('file://' . $p8file) // het .p8 bestand (via apple download)
->setSigner(new Sha256()) // APNs ondersteund alleen het ES256 Algorithme (Elliptic Curve Digital Signature Algorithm using P-256 and SHA-256)
->getToken();

// Stap 4: Maak een bericht om te versturen
$payloadArray['aps'] = [
  'alert' => [
    'title' => "SaMauto.nl Push Notificatie", // titel van de notificatie
    'body' => "Kijk op SamAuto.nl voor meer tips", // bericht inhoud
  ],
  'sound' => 'default',
  'badge' => 1
];

// Stap 4.1: vorm het om naar JSON
$payloadJSON = json_encode($payloadArray);


// Stap 5: Maak en verzend het bericht via cURL (HTTP/2) naar APNs.
$ch = curl_init($url);

curl_setopt($ch, CURLOPT_POSTFIELDS, $payloadJSON);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer $token","apns-topic: $apns_topic"]);
$response = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Als alles gelukt is verwacht je een "200 OK!" terug te krijgen van Apple.
// Voor alle mogelijke antwoorden zie https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH107-SW1

var_dump($response);
var_dump($httpcode); // 200... als alles goed ging.
?>

Dit is eigenlijk alles wat je nodig hebt om de notificaties van een server naar een IOS apparaat te sturen. Heb je nou geen zin om alles zelf te bouwen, dan kan je een kant en klare software gebruiken om je bericht te versturen.

Op internet staat een package genaamd github.com/edamov/pushok of via packagist.org/edamov/pushok. Deze kan je direct gebruiken in je eigen PHP project door het volgende te doen:

composer require edamov/pushok

Hetzelfde bericht als hierboven ziet er dan als volgt uit:

<?php
// Stap 0: PSR-0 Autoloader
require __DIR__ . '/vendor/autoload.php';

// Stap 1: Importeer de edamov/pushok library
use Pushok\AuthProvider;
use Pushok\Client;
use Pushok\Notification;
use Pushok\Payload;
use Pushok\Payload\Alert;

// Stap 2: Opties / Configuratie
$options = [
    'key_id' => 'ABC123DEFG', // Het Key ID van je Apple developer account
    'team_id' => 'DEF123GHIJ', // Het TeamId van je Apple developer account
    'app_bundle_id' => 'nl.samauto.ios-applicatie', // De bundleId van je Apple developer account
    'private_key_path' => __DIR__ . '/private_key.p8', // Bestandslocatie van de prive sleutel
    'private_key_secret' => null // Wachtwoord voor de private key (indien dit op je sleutel zit)
];

$authProvider = AuthProvider\Token::create($options);

$alert = Alert::create()->setTitle('SaMauto.nl Push Notificatie');
$alert = $alert->setBody('Kijk op SamAuto.nl voor meer tips');

$payload = Payload::create()->setAlert($alert);

//set notification sound to default
$payload->setSound('default');

//add custom value to your notification, needs to be customized
$payload->setCustomValue('key', 'value');

$deviceTokens = ['<apparaat_token_1>', '<apparaat_token_2>', '<apparaat_token_3>'];

$notifications = [];
// verstuur het bericht naar apparaat 1,2 en 3
foreach ($deviceTokens as $deviceToken) {
    $notifications[] = new Notification($payload,$deviceToken);
}

$client = new Client($authProvider, $production = false); // gebruik de sandbox.
$client->addNotifications($notifications);



$responses = $client->push(); // je krijg een array van ApnsResponseInterface's (een antwoord per verstuurde notificatie)

foreach ($responses as $response) {
    $response->getApnsId();
    $response->getStatusCode();
    $response->getReasonPhrase();
    $response->getErrorReason();
    $response->getErrorDescription();
}

Er zijn nog veel meer geweldige PHP packages gemaakt om notificaties te versturen. Maar als je echt behoefte hebt aan betrouwbare en snelle software die je leven makkelijker maakt dan kan ik je aanraden om toch eens te kijken naar bijvoorbeeld een package in Golang.

GoRush: Een Push Notificatie server met ingebouwde API (Apple IOS + Google Android)

  ________                              .__
 /  _____/   ____ _______  __ __  ______|  |__
/   \  ___  /  _ \\_  __ \|  |  \/  ___/|  |  \
\    \_\  \(  <_> )|  | \/|  |  /\___ \ |   Y  \
 \______  / \____/ |__|   |____//____  >|___|  /
        \/                           \/      \/

Usage: gorush [options]
GitHub
Bekijk GoRush op GitHub
(Klik op het logo)

Als je net als DevOps Dave liever niet het wiel opnieuw wil uitvinden, dan kan je ervoor kiezen om een kant en klare oplossing te gebruiken zoals GoRush.

Met o.a. IOS HTTP/2 ondersteuning, Firebase Cloud Messaging (Android), YAML Configuratie, CLI (Command Line), een Web API die je zo aan kan roepen (ook vanuit PHP), Statistieken over de notificaties, een HTTPS of SOCKS5 Proxy, gratis TLS certificaten via Let’s Encrypt. Beschikbaar voor Docker, Kubernetes en AWS Lambda (Draait native in Golang)