Apple Wallet/Passbook 通知无法送达

Apple Wallet/Passbook notifications would not deliver

我正在尝试使用 Pushsharp 发送通知以更新 wallet/passbook 中的数字卡。我仔细检查了所有这些:

但是当我向 APNs 发送通知请求时,设备没有回击。

注意:出于保密原因,我已经更改或删除了以下代码中的网址、标记和路径

下面是我用来发送通知的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using PushSharp.Apple;

namespace NotificationPushsharp01
{
    class Program
    {
        static void Main(string[] args)
        {
            string certificatePath = @"PATH_OF_CERTIFICATE.p12";
            X509Certificate2 clientCertificate = new X509Certificate2(System.IO.File.ReadAllBytes(certificatePath), "12345");

            // Configuration (NOTE: .pfx can also be used here)
            var config = new ApnsConfiguration(ApnsConfiguration.ApnsServerEnvironment.Production, clientCertificate, validateIsApnsCertificate: false);

            // Create a new broker
            var apnsBroker = new ApnsServiceBroker(config);

            System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;

            // Wire up events
            apnsBroker.OnNotificationFailed += (notification, aggregateEx) =>
            {

                aggregateEx.Handle(ex =>
                {

                    // See what kind of exception it was to further diagnose
                    if (ex is ApnsNotificationException notificationException)
                    {

                        // Deal with the failed notification
                        var apnsNotification = notificationException.Notification;
                        var statusCode = notificationException.ErrorStatusCode;

                        Console.WriteLine($"Apple Notification Failed: ID={apnsNotification.Identifier}, Code={statusCode}");

                    }
                    else
                    {
                        // Inner exception might hold more useful information like an ApnsConnectionException           
                        Console.WriteLine($"Apple Notification Failed for some unknown reason : {ex.InnerException}");
                    }

                    // Mark it as handled
                    return true;
                });
            };

            apnsBroker.OnNotificationSucceeded += (notification) =>
            {
                Console.WriteLine("Apple Notification Sent!");
            };

            // Start the broker
            apnsBroker.Start();

            apnsBroker.QueueNotification(new ApnsNotification
            {
                DeviceToken = "d30710c34af48d65e02db4c3db60fae04d283efaa105633f7c41b8d1963628fe",                 
                Payload = JObject.Parse("{\"aps\":\"\"}")
            });

            // Stop the broker, wait for it to finish   
            // This isn't done after every message, but after you're
            // done with the broker
            apnsBroker.Stop();

            Console.ReadLine();
        }
    }
}

以上代码运行的输出

2019-12-19 08:39:24.AM [DEBUG] Scaled Changed to: 1
2019-12-19 08:39:24.AM [INFO] Stopping: Waiting on Tasks
2019-12-19 08:39:24.AM [INFO] Waiting on all tasks 1
2019-12-19 08:39:25.AM [INFO] APNS-Client[1]: Sending Batch ID=1, Count=1
2019-12-19 08:39:25.AM [INFO] APNS-Client[1]: Connecting (Batch ID=1)
2019-12-19 08:39:25.AM [INFO] APNS-Client[1]: Connected (Batch ID=1)
2019-12-19 08:39:25.AM [INFO] APNS-Client[1]: Sent Batch, waiting for possible response...
2019-12-19 08:39:26.AM [INFO] APNS-Client[1]: Received -1 bytes response...
2019-12-19 08:39:26.AM [INFO] APNS-Client[1]: Batch (ID=1) completed with no error response...
2019-12-19 08:39:26.AM [INFO] APNS-Client[1]: Done Reading for Batch ID=1, reseting batch timer...
Apple Notification Sent!
2019-12-19 08:39:26.AM [INFO] All Tasks Finished
2019-12-19 08:39:26.AM [INFO] Passed WhenAll
2019-12-19 08:39:26.AM [INFO] Broker IsCompleted
2019-12-19 08:39:26.AM [DEBUG] Broker Task Ended
2019-12-19 08:39:26.AM [INFO] Stopping: Done Waiting on Tasks

API 的控制器,负责处理通行证的注册和更新

//Sorry for the comments
public class DevicesController : ApiController
{
    // GET request to webServiceURL/version/devices/deviceLibraryIdentifier/registrations/passTypeIdentifier
    [HttpGet]
    public HttpResponseMessage GetSerialNumber(string deviceLibraryIdentifier, string passTypeIdentifier)
    {
        System.IO.File.AppendAllText(@"updates.txt", "Device requested serial numbers S");
        System.IO.File.AppendAllText(@"updates.txt", System.Environment.NewLine);

        // For example...
        SerialNumbers lastUpdateToSerialNumDict = new SerialNumbers();
        // LastUpdated timestamp set to current datetime
        lastUpdateToSerialNumDict.lastUpdated = String.Format("{0:MM/dd/yyyy HH:mm:ss}", DateTime.Now);
        // A list of serial numbers got from database
        lastUpdateToSerialNumDict.serialNumbers = new List<string>();
        lastUpdateToSerialNumDict.serialNumbers.Add("123456789");
        string jsonRes = JsonConvert.SerializeObject(lastUpdateToSerialNumDict);
        HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
        response.Content = new StringContent(jsonRes, Encoding.UTF8, "application/json");
        return response;
    }

    // GET request to webServiceURL/version/devices/deviceLibraryIdentifier/registrations/passTypeIdentifier?passesUpdatedSince=tag
    [HttpGet]
    public HttpResponseMessage GetSerialNumber(string deviceLibraryIdentifier, string passTypeIdentifier, string passesUpdatedSince)
    {
        System.IO.File.AppendAllText(@"updates.txt", "Device requested serial numbers C");
        System.IO.File.AppendAllText(@"updates.txt", System.Environment.NewLine);

        // For example...
        SerialNumbers lastUpdateToSerialNumDict = new SerialNumbers();
        // LastUpdated timestamp set to current datetime
        lastUpdateToSerialNumDict.lastUpdated = String.Format("{0:MM/dd/yyyy HH:mm:ss}", DateTime.Now);
        // A list of serial numbers got from database
        lastUpdateToSerialNumDict.serialNumbers = new List<string>();
        lastUpdateToSerialNumDict.serialNumbers.Add("123456789");
        string jsonRes = JsonConvert.SerializeObject(lastUpdateToSerialNumDict);
        HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
        response.Content = new StringContent(jsonRes, Encoding.UTF8, "application/json");
        return response;
    }

    // POST request to webServiceURL/version/devices/deviceLibraryIdentifier/registrations/passTypeIdentifier/serialNumber
    [HttpPost]
    public HttpResponseMessage RegisterDevice(string deviceLibraryIdentifier, string passTypeIdentifier, string serialNumber, [FromBody]HR.CardApi.Api.Models.DevicesPayload payload)
    {


        //ApiLog
        System.IO.File.AppendAllText(@"ApiLog.txt", "devices/register was used");
        System.IO.File.AppendAllText(@"D:\FGC-Microservice\HR.CardApi.DDC_31072019\HR.CardApi.Api\bin\ApiLog.txt", System.Environment.NewLine);
        //ApiLog

        System.IO.File.AppendAllText(@"data.txt", deviceLibraryIdentifier);
        System.IO.File.AppendAllText(@"data.txt", System.Environment.NewLine);

        System.IO.File.AppendAllText(@"data.txt", passTypeIdentifier);
        System.IO.File.AppendAllText(@"data.txt", System.Environment.NewLine);

        System.IO.File.AppendAllText(@"data.txt", serialNumber);
        System.IO.File.AppendAllText(@"data.txt", System.Environment.NewLine);

        System.IO.File.AppendAllText(@"data.txt", payload.pushToken);
        System.IO.File.AppendAllText(@"data.txt", System.Environment.NewLine);
        System.IO.File.AppendAllText(@"data.txt", System.Environment.NewLine);

        System.Net.Http.HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
        return response;
    }

    // DELETE request to webServiceURL/version/devices/deviceLibraryIdentifier/registrations/passTypeIdentifier/serialNumber
    [HttpDelete]
    public HttpResponseMessage UnRegisterDevice(string deviceLibraryIdentifier, string passTypeIdentifier, string serialNumber)
    {
        //Udpate Devices and Register table
        System.Net.Http.HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
        return response;
    }
}

pass.json 个 pass.pkpass 个文件

{
  "passTypeIdentifier": "SAME_AS_IN_KEYCHAIN",
  "formatVersion": 1,
  "serialNumber": "123456789",
  "description": "CONFIDENTIAL",
  "organizationName": "CONFIDENTIAL",
  "teamIdentifier": "CONFIDENTIAL",
  "voided": false,
  "barcodes": [
    {
      "format": "PKBarcodeFormatPDF417",
      "message": "1234587568464654",
      "messageEncoding": "ISO-8859-1"
    }
  ],
  "storeCard": {
    "headerFields": [],
    "primaryFields": [],
    "secondaryFields": [],
    "auxiliaryFields": [
      {
        "key": "offer",
        "label": "Initial Pass",
        "value": "8979787645464654"
      }
    ],
    "backFields": [
      {
        "key": "CONFIDENTIAL",
        "label": "CONFIDENTIAL",
        "attributedValue": "CONFIDENTIAL",
        "value": "CONFIDENTIAL"
      }
    ]
  },
  "authenticationToken": "wxyzd7J8AlYYFPS0k0a0FfVFtq0ewzEfd",
  "webServiceURL": "https://CONFIDENTIAL.com"
}

您可以提出任何与代码相关的问题。目前,我正在检查设备日志。如果我发现有用的东西,我会更新。

感谢您的宝贵时间。

我明白问题出在哪里了。有问题的代码是正确的。它没有错误。

当设备请求序列号时,API 返回 HTTP 404。这是因为我的通行证的 passTypeIdentifier 中包含点。就像 pass.acbcd.abcd。 我刚刚将我的 API 配置为允许 url 中的点,一切都开始正常工作。