iOS推送,APNs Auth Key 的 bash 和 php 脚本

以前做推送一直是使用APNs证书文件的方式,但是这种方式有过期时间,而且每个App都需要重新创建证书,非常麻烦。
现在好了有了APNs Auth Key的验证方式,大大减少了工作量,也不用担心过期问题。

关于APNs Auth Key
APNs Auth Key 是服务端为开发者生成的一个 token,此 token 用于替代 APNs 请求证书。

APNs Auth Key 需要配合它的 KeyID,开发者的 TeamID,指定应用的 BundleID一起鉴权。

优势是可以被该开发者账户下多个 app 一起使用,并且永不过期。

生成APNs Auth Key的步骤很容易找到,许多第三方推送都有相关文档,不再赘述。
关于如何自己测试推送的相关资料比较难找,在此整理一下。

bash脚本的方式

#!/bin/bash
# config
deviceToken=deviceToken
authKey="./APNsAuthKey.p8"
authKeyId=KeyID
teamId=TeamID
bundleId=BundleID
endpoint=https://api.development.push.apple.com
#// "https://api.push.apple.com"

# 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,
      "sound": "default",
      "alert": {
         "title": "标题",
         "subtitle": "副标题",
         "body": "内容"
      }
   },
   "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

php的方式

<?php
// THE FINAL SCRIPT WITHOUT DEPENDENCIES!!! ...except curl with http2
$device_token = "deviceToken";
//echo $key;
$kid      = "Key ID";
$teamId   = "Team ID";
$app_bundle_id = "Bundle ID";
$base_url = "https://api.development.push.apple.com";
// "https://api.push.apple.com"

// key in same folder as the script
$filename = "APNsAuthKey.p8";

$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;


$pkey     = openssl_pkey_get_private("file://{$filename}");
$signature;
openssl_sign($token, $signature, $pkey, 'sha256');
$sign = base64_encode($signature);

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

$message = '{"aps":{"alert":"CC Test","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);

注意配置好相关参数
deviceToken=deviceToken
authKey="./APNsAuthKey.p8"
authKeyId=KeyID
teamId=TeamID
bundleId=BundleID
之后运行就可以了,mac自带php,不得不说还是很方便的。

推荐阅读更多精彩内容