dotnet-passbook
dotnet-passbook copied to clipboard
PKPass files won't open in Safari Mobile
Passes generated with this tool can't be opened with Safari Mobile, but can be opened on a Mac laptop. Logs obtained from XCode don't show anything useful.
error 16:14:47.923573-0600 MobileSafari PassBook Pass download failed: (null)
Passes created with @walletpass/pass-js
work just fine. Both coupons pass all checks in the pkpass validator. https://pkpassvalidator.azurewebsites.net/
This is the pass.json generated with this tool. This coupon doesn't open.
{
"semantics": {},
"passTypeIdentifier": "redacted",
"formatVersion": 1,
"serialNumber": "637957668378982586",
"description": "Buy one New 20oz Coke Orange Vanilla, get one free.",
"organizationName": "Distributer Company, LLC",
"teamIdentifier": "redacted",
"sharingProhibited": false,
"labelColor": "rgb(255,255,255)",
"coupon": {
"headerFields": [
{
"key": "header",
"label": "Date",
"value": "Placeholder"
}
],
"primaryFields": [
{
"key": "offer",
"label": " ",
"value": " "
}
],
"secondaryFields": [
{
"key": "details",
"label": "OFFER",
"value": "Buy one New 20oz Coke Orange Vanilla, get one free."
}
],
"auxiliaryFields": [
{
"key": "details",
"label": "OFFER",
"value": "Buy one New 20oz Coke Orange Vanilla, get one free."
}
],
"backFields": [
{
"key": "terms",
"label": "Terms and Conditions",
"value": "Valid at Participating locations.\n\nCoupon values are as specified on the coupon.\n\nLimit of one coupon per customer.\n\nCoupons are intended for single use only.\n\nEach coupon is valid for a limited time only and expires on the date specified in the offer.\n\nWe reserve the right to modify or cancel coupons at any time."
},
{
"key": "signer",
"label": "Developer",
"value": " "
}
]
}
}
This is the pass.json generated with the pass-js library. This downloads and opens in Mobile Safari.
{
"passTypeIdentifier": "redacted",
"formatVersion": 1,
"serialNumber": "121212",
"organizationName": "redacted",
"teamIdentifier": "redacted",
"description": "No description",
"labelColor": "rgb(255, 255, 255)",
"coupon": {
"backFields": [
{
"key": "terms",
"label": "Terms and Conditions",
"value": "Valid at Participating locations.\n\nCoupon values are as specified on the coupon.\n\nLimit of one coupon per customer.\n\nCoupons are intended for single use only.\n\nEach coupon is valid for a limited time only and expires on the date specified in the offer.\n\nWe reserve the right to modify or cancel coupons at any time."
},
{
"key": "signer",
"label": "Development",
"value": " "
}
],
"headerFields": [
{
"key": "date",
"label": "Expiration",
"dateStyle": "PKDateStyleShort",
"timeStyle": "PKDateStyleShort",
"value": "2022-08-10T06:00+00:00"
}
],
"primaryFields": [
{
"key": "offer",
"label": " ",
"value": " "
}
],
"secondaryFields": [
{
"key": "details",
"label": "OFFER",
"value": "Buy one New 20oz Coke Orange Vanilla, get one free."
}
]
},
"barcodes": [
{
"message": "https://google.com",
"format": "PKBarcodeFormatQR",
"messageEncoding": "iso-8859-1"
}
]
}
Here is the code I'm using to generate the pass.
string certsPath = AppDomain.CurrentDomain.BaseDirectory + "/Certs";
PassGenerator generator = new PassGenerator();
PassGeneratorRequest request = new PassGeneratorRequest();
X509KeyStorageFlags flags = X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable;
request.PassbookCertificate = new X509Certificate2(
certsPath + "/portal-coupon-cert.p12",
_config.GetSection("AWSSettings")["CouponService"],
flags);
request.AppleWWDRCACertificate = new X509Certificate2(certsPath + "/AppleWWDRCAG6.cer");
request.Style = PassStyle.Coupon;
request.PassTypeIdentifier = "redacted";
request.TeamIdentifier = "redacted";
request.SerialNumber = DateTime.UtcNow.Ticks.ToString();
request.Description = couponData.Offer;
request.OrganizationName = couponData.Provider;
request.BackgroundColor = couponData.BackgroundColor;
request.LabelColor = couponData.LabelColor;
request.ForegroundColor = couponData.LabelColor;
request.AddHeaderField(new StandardField("header", "Date", "Placeholder"));
request.AddPrimaryField(new StandardField("offer", " ", " "));
request.AddSecondaryField(new StandardField("details", "OFFER", couponData.Offer));
request.AddBackField(new StandardField("terms", "Terms and Conditions", couponData.CouponDisclaimer));
request.AddBackField(new StandardField("signer", "Developer", " "));
request.Images.Add(PassbookImage.Icon, images["iconSmall"]);
request.Images.Add(PassbookImage.Icon2X, images["iconLarge"]);
request.Images.Add(PassbookImage.Strip, images["stripSmall"]);
request.Images.Add(PassbookImage.Strip2X, images["stripLarge"]);
request.Images.Add(PassbookImage.Logo, images["logoSmall"]);
request.Images.Add(PassbookImage.Logo2X, images["logoLarge"]);
if (!string.IsNullOrWhiteSpace(couponData.BarcodeMessage))
{
switch (couponData.BarcodeType)
{
case "pdf417":
request.AddBarcode(BarcodeType.PKBarcodeFormatPDF417, couponData.BarcodeMessage, "ISO-8859-1");
break;
case "azteccode":
request.AddBarcode(BarcodeType.PKBarcodeFormatAztec, couponData.BarcodeMessage, "ISO-8859-1");
break;
case "code_128":
request.AddBarcode(BarcodeType.PKBarcodeFormatCode128, couponData.BarcodeMessage, "ISO-8859-1");
break;
port
case "qrcode":
case "qr":
default:
request.AddBarcode(BarcodeType.PKBarcodeFormatQR, couponData.BarcodeMessage, "ISO-8859-1");
break;
}
}
var generatedPass = generator.Generate(request);
Any help would be very much appreciated.
In order to get more information from the iPhone logs, you can enable debug logging from the developer settings on your iPhone.
Typically when a pass doesn't open it's related to the certificates being invalid or missing keys/duplicate keys.
My pkpassvalidator is not comprehensive, so there are lots of things it's doesn't check.
Enable the debug logging and try again. I don't have access to a Mac at present, but if you send me the pass that isn't working, I can have a look next week.
Hi, I'm just following up on this - could you send me the pass that is failing please?
Sorry for the late reply. We managed to get this working. It was my fault, I failed to see that the MIME type was actually being set to application/vnd.apple.pkpasses
instead of application/vnd.apple.pkpass
. Thanks for your help.
Marvelous