How to send APNs push messages using APNs Auth Key and standard CLI tools?

流过昼夜 提交于 2019-12-02 15:08:18

If you have curl with HTTP/2 support and openssl with ECDSA support installed on your machine, you can use the following script to test push notifications using an APNs Auth Key:

#!/bin/bash

deviceToken=b27371497b85611baf9052b4ccfb9641ab7fea1d01c91732149c99cc3ed9342f

authKey="./APNSAuthKey_ABC1234DEF.p8"
authKeyId=ABC1234DEF
teamId=TEAM123456
bundleId=com.example.myapp
endpoint=https://api.development.push.apple.com

read -r -d '' payload <<-'EOF'
{
   "aps": {
      "badge": 2,
      "category": "mycategory",
      "alert": {
         "title": "my title",
         "subtitle": "my subtitle",
         "body": "my body text message"
      }
   },
   "custom": {
      "mykey": "myvalue"
   }
}
EOF

# --------------------------------------------------------------------------

base64() {
   openssl base64 -e -A | tr -- '+/' '-_' | tr -d =
}

sign() {
   printf "$1" | openssl dgst -binary -sha256 -sign "$authKey" | base64
}

time=$(date +%s)
header=$(printf '{ "alg": "ES256", "kid": "%s" }' "$authKeyId" | base64)
claims=$(printf '{ "iss": "%s", "iat": %d }' "$teamId" "$time" | base64)
jwt="$header.$claims.$(sign $header.$claims)"

curl --verbose \
   --header "content-type: application/json" \
   --header "authorization: bearer $jwt" \
   --header "apns-topic: $bundleId" \
   --data "$payload" \
   $endpoint/3/device/$deviceToken

NOTE: I use a slight variation of this script for testing on macOS with homebrew versions of curl and openssl: http://thrysoee.dk/apns/

You can send push notification by NODE JS using Apple Push Notification Authentication Key (Sandbox & Production). Apple has provided a tutorial in this link

This tutorial has all steps of creating the Apple Push Notification Authentication Key and setting up a local server to run Node JS code for sending push notification. You can run the code in your local machine and test the push notification.

Hope this will help.

Voilà in PHP what it looks like with curl and HTTP/2. This script return the 200 ok status code along with the generated token id.

// THE FINAL SCRIPT WITHOUT DEPENDENCIES!!! ...except curl with http2
$device_token = "a0abd886etc...";
//echo $key;
$kid      = "YOURKEYID";
$teamId   = "YOURTEAMID";
$app_bundle_id = "your.app.bundle";
$base_url = "https://api.development.push.apple.com";

$header = ["alg" => "ES256", "kid" => $kid];
$header = base64_encode(json_encode($header));

$claim = ["iss" => $teamId, "iat" => time()];
$claim = base64_encode(json_encode($claim));

$token = $header.".".$claim;
// key in same folder as the script
$filename = "KeyFromApple.p8";
$pkey     = openssl_pkey_get_private("file://{$filename}");
$signature;
openssl_sign($token, $signature, $pkey, 'sha256');
$sign = base64_encode($signature);

$jws = $token.".".$sign;

$message = '{"aps":{"alert":"You are welcome.","sound":"default"}}';

function sendHTTP2Push($curl, $base_url, $app_bundle_id, $message, $device_token, $jws) {

    $url = "{$base_url}/3/device/{$device_token}";
    // headers
    $headers = array(
        "apns-topic: {$app_bundle_id}",
        'Authorization: bearer ' . $jws
    );
    // other curl options
    curl_setopt_array($curl, array(
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
        CURLOPT_URL => $url,
        CURLOPT_PORT => 443,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_POST => TRUE,
        CURLOPT_POSTFIELDS => $message,
        CURLOPT_RETURNTRANSFER => TRUE,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_SSL_VERIFYPEER => FALSE,
        CURLOPT_HEADER => 1
    ));
    // go...
    $result = curl_exec($curl);
    if ($result === FALSE) {
        throw new Exception("Curl failed: " .  curl_error($curl));
    }
    print_r($result."\n");
    // get response
    $status = curl_getinfo($curl);
    return $status;
}
// open connection
$curl = curl_init();
sendHTTP2Push($curl, $base_url, $app_bundle_id, $message, $device_token, $jws);

The answer provided by Nicolas Manzini, while helpful, did not fully work for me. I also wanted to use command line curl. In particular, reading in the .p8 file was causing some problems. A modified version:

<?php

$teamid = 'YOURTEAMID';
$keyid = 'A464FN6T93';     // in the name of the file downloaded from Apple Certs

// since it is a universal key, I wanted this in a location accessible to several accounts
$keyFile = '/path/to/file/AuthKey_A464FN6T93.p8';

$privateKey = openssl_pkey_get_private('file://' . $keyFile);

if (! $privateKey) {
    die('could not find: ' . $keyFile);
}

$header = ['alg' => 'ES256', 'kid' => $keyid];
$header = base64_encode(json_encode($header));

$claim = ['iss' => $teamid, 'iat' => time()];
$claim = base64_encode(json_encode($claim));

$tok = $header . '.' . $claim;

// pass in empty $signature, 2nd line below fills it
$signature = '';
$result = openssl_sign($tok, $signature, $privateKey, OPENSSL_ALGO_SHA256);      //  'sha256'
if (! $result) {
    die('unable to create signature');
}

$sign = base64_encode($signature);

openssl_free_key($privateKey);

$jwt = $tok . '.' . $sign;

foreach($tokens as $token) {
    $cmd = '\
    /usr/local/bin/curl -v \
    -d \'{"aps":{"alert":{"title":"Notification Title","body":"You are being notified!"},"sound":"default"}}\' \
    -H "apns-topic: com.app.bundle.id" \
    -H "authorization: bearer ' . $jwt . '" \
    -H "content-type:application/json" \
    --http2 \
    https://api.push.apple.com/3/device/' . $token . ' 2>&1';    // ending w/ 2>&1, sends output to $output

    exec($cmd, $output, $return);

    if ($return != 0) {
        // be notified of error
    }
    else {
        foreach($output as $line) {
            if (strpos($line, 'apns-id')) {
                $apns = $line;
            }
        }
    }
}

?>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!