【问题标题】:Apple Wallet/Passbook notifications would not deliverApple Wallet/Passbook 通知无法发送
【发布时间】:2019-12-19 14:03:39
【问题描述】:

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

  • 使用相同的证书对通行证进行签名和更新
  • 在 Pushsharp 中禁用了生产/沙盒证书检查
  • 使用我从设备获得的 pushtoken。它的格式如下:d30720c34af46d65e02db3c3db6Ohae04d183dfaa105133f7c21b8d1963629fe
  • 使用本教程生成 .p12 证书,步骤 #10 除外:https://support.airship.com/hc/en-us/articles/213493683-How-to-make-an-Apple-Pass-Type-Certificate
  • telnet feedback.push.apple.com 2196 成功
  • pass.json 中的 PassTypeIdentifier 与 .p12 文件的通用名称相同
  • 卡在设备上完美打开
  • 设备向服务器发送注册请求
  • 下拉更新完美运行

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

注意:由于机密性,我已经从下面的代码中更改或删除了 url、令牌和路径

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

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.pkpass文件的pass.json

{
  "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"
}

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

感谢您的宝贵时间。

【问题讨论】:

  • 仔细检查您使用的是生产端点而不是沙盒端点。您看到推送到达设备了吗?您可以在开发菜单中启用设备上的其他 PassKit 日志记录。您应该会看到它收到推送消息,然后联系您的网络服务。
  • 是的,我已经双重检查我正在使用生产端点。它在代码new ApnsConfiguration(ApnsConfiguration.ApnsServerEnvironment.Production 中,推送也到达了电话上。但我看到了一些与 API 相关的错误。
  • API 相关的错误可能来自您的实现。如果未返回有效的连续剧列表,则不会请求新的通行证包。下拉刷新作品,所以我建议看看你的连续剧实现。
  • 是的,我返回了正确的序列,但 API 不接受 url 中的点。我将它配置为允许点,它工作正常。非常感谢您的帮助。

标签: apple-push-notifications passbook wallet pushsharp


【解决方案1】:

我发现了问题所在。有问题的代码是正确的。它没有错误。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-20
    • 1970-01-01
    • 1970-01-01
    • 2017-01-16
    • 1970-01-01
    相关资源
    最近更新 更多