SendEmptyPushNotification to gateway.push.apple.com no longer working

Solution 1:

Me too man. Let's figure this out together like Apex Legends.

I have submitted a TSI to Apple. They sent out an email on feb 10 saying:

On March 29, 2021, token and certificate-based HTTP/2 connections to the Apple Push Notification service must incorporate the new root certificate (AAACertificateServices 5/12/2020) which replaces the old GeoTrust Global CA root certificate. To ensure a seamless transition and to avoid push notification delivery failures, verify that both the old and new root certificates for the HTTP/2 interface are included in the Trust Store of each of your notification servers before March 29.

Note that Apple Push Notification service SSL provider certificates issued to you by Apple do not need be to updated at this time.

Learn more about connecting to APNs.

If you have any questions, contact us.

Best regards, Apple Developer Relations

Update - Mon May 3, after submitting a TSI to Apple Dev

  1. Push notifications stopped working for developers on March 31, 2021 after Apple migrated to a new APNS provider API (http/2 protocol).

  2. To continue using push, see this page: https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns/

    • On that page, these 3 items are of special interest to me:

      Registering Your App with APNs

      Establishing a Token-Based Connection to APNs

      Generating a Remote Notification

What I learned?

Revoke all developer account certificates related to APNS Make new certs and this time don't make any PEM files when installing them to your providing server. Also, make sure to stop using port 2195 when making a connection to APNS and use 443 or 2197.

The great news? The new APNS provider API is still compatible with Objective C!

🐆

<?php
// Put your device token here (without spaces):
$deviceToken = '09a0c8ff92b3621c5f5032c1fa031f2851d01dd99beaf1446c281c5458fe2ffd';
// Put your private key's passphrase here:
$passphrase = 'pushchat';
// Put your alert message here:
$message = 'Hello!';

$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);
echo 'Connected to APNS' . PHP_EOL;
// Create the payload body
$body['aps'] = array(
'alert' => $message,
'sound' => 'default'
);
// Encode the payload as JSON
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', 
strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered' . PHP_EOL;
// Close the connection to the server
fclose($fp);

Update: I was wrong about the PEM aspect. Creating a PEM file is still necessary for APNs connections using the new APNs Provider API.

Solution 2:

To get this to work in a non .Net Core Solution, I had to upgrade from Asp.net 4.6.1 to 4.7.2. I then created a folder in my Project called AppleAPNS. I added all the files found here.

NOTE: I had to upgrade to 4.7.2 in order to get the Project to recognize CreateFromValue found in the AppleCryptoHelper file.

https://github.com/andrei-m-code/net-core-push-notifications/tree/master/CorePush/Apple

I then added the files found here to the AppleAPNS folder.

https://github.com/andrei-m-code/net-core-push-notifications/tree/master/CorePush/Utils

I then added the WinHttpHandler Project along with this helper to my AppleAPNS folder. This will ensure that you are calling APNS with an HTTP client capable of 2.0.

public class Http2CustomHandler : WinHttpHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            request.Version = new Version("2.0");

            return base.SendAsync(request, cancellationToken);
        }
    }

Next, add the AppleNotification class found here and use the calling method in the program.cs file.

https://github.com/andrei-m-code/net-core-push-notifications/tree/master/CorePush.Tester

To use the Http2CustomHandler, make these changes.

ApnSender.cs

//private readonly HttpClient http;
        private readonly HttpClient http = new HttpClient(new Http2CustomHandler());

In your calling method make this change.

//private static readonly HttpClient http = new HttpClient();
        private static readonly HttpClient http = new HttpClient(new Http2CustomHandler());

Finally, make this change to send an empty push notification to update passes.

ApnSender.cs

//var json = JsonHelper.Serialize(notification);
            var json = "{\"aps\":\"\"}";

NOTE: Copy the contents of the p8 file as string into the apnP8PrivateKey in your calling method. Do not open/read the file.

Hope this helps! I know this is not a detailed explanation, but hopefully it will help somebody.