服务器端使用dotnet-passbook v3.2.0生成的Pkpass无法打开问题
问题说明
- 基于dotnet-passbook 3.2.0版本生成Pkpass文件,本地环境生成的文件可正常打开,部署到服务器后生成的文件无法打开
- 将服务器生成的Pkpass文件上传到Pkpass验证工具检测,仅返回
Failed to process the Pkpass file.的通用报错,无具体错误指向 - 核心生成代码如下:
public static FileContentResult GetPass(Shopper account) { try { if (account == null) { return null; } PassGenerator generator = new PassGenerator(); PassGeneratorRequest request = new PassGeneratorRequest(); // 基础配置 request.PassTypeIdentifier = "PassTypeIdentifier"; request.TeamIdentifier = "TeamIdentifier"; request.SerialNumber = "SerialNumber"; request.Description = "Description"; request.OrganizationName = "OrganizationName"; request.LogoText = "LogoText"; WebClient webClient = new WebClient(); // 加载Pass签名证书 try { X509KeyStorageFlags flags = X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable; request.PassbookCertificate = new X509Certificate2(webClient.DownloadData(CertificatesBucket + "/Certificates.p12"), S3_AppleCertificatePassword, flags); } catch (Exception e) { throw new Exception("加载证书异常: " + e.Message); } // 加载Apple WWDR根证书 try { request.AppleWWDRCACertificate = new X509Certificate2(webClient.DownloadData(CertificatesBucket + "/AppleWWDRCAG2.cer")); } catch (Exception e) { throw new Exception("加载AppleWWDRCA证书异常: " + e.Message); } // 加载Pass图片资源 try { request.Images.Add(PassbookImage.Logo, webClient.DownloadData(AppleImageBucket + "/logo.png")); request.Images.Add(PassbookImage.Icon, webClient.DownloadData(AppleImageBucket + "/icon.png")); request.Images.Add(PassbookImage.Icon2X, webClient.DownloadData(AppleImageBucket + "/icon%402x.png")); request.Images.Add(PassbookImage.Strip, webClient.DownloadData(AppleImageBucket + "/strip.png")); request.Images.Add(PassbookImage.Strip2X, webClient.DownloadData(AppleImageBucket + "/strip%402x.png")); } catch (Exception e) { throw new Exception("加载图片资源异常: " + e.Message); } // 添加条形码 request.AddBarcode(BarcodeType.PKBarcodeFormatCode128, account.Id, "ISO-8859-1"); // 关联应用ID request.AssociatedStoreIdentifiers.Add(121212); request.Style = PassStyle.StoreCard; // 添加卡片展示字段 request.AddHeaderField(new StandardField("StandardField", "TEXT", account.Id)); request.AddSecondaryField(new StandardField("StandardField", "TEXT", account.Name)); request.AddSecondaryField(new StandardField("StandardField", "TEXT", "TEXT")); request.TransitType = TransitType.PKTransitTypeAir; byte[] generatedPass = generator.Generate(request); return new FileContentResult(generatedPass, "application/vnd.apple.pkpass"); } catch (Exception ex) { throw new Exception("生成Apple Pass异常: " + ex.Message); } }
排查与修复方案
按问题出现概率从高到低排查:
- 第一优先级修复证书加载标记,这是本地正常、服务器生成失败的最高发原因,占同类问题的90%以上。你当前的X509KeyStorageFlags缺少
PersistKeySet标记,服务器IIS环境下运行应用池的服务账号没有持久化密钥权限,私钥加载后会被系统立刻回收,导致签名流程生成的signature文件无效,整个pkpass包结构损坏。修改证书加载代码如下:
本地调试时因为用的是当前登录用户的上下文,密钥存储在用户个人目录下不会被回收,所以不会触发这个问题,一到服务器用服务账号跑必现。X509KeyStorageFlags flags = X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet; - 修复Pass类型配置冲突:你设置的Pass类型是
StoreCard(商店卡),但额外配置了仅交通卡、登机牌类Pass才允许出现的TransitType字段,非交通类Pass包含这个字段会直接导致pass.json格式校验失败,直接删掉request.TransitType = TransitType.PKTransitTypeAir;这行即可。 - 替换WWDR根证书:Apple已经停用了G2版本的WWDR根证书,你现在加载的AppleWWDRCAG2.cer已经过期,需要替换为最新的G4版本WWDR证书,否则签名会被判定为无效。
- 修复图片资源加载问题:
- 2x分辨率的图片路径不要手动写URL编码的
%40,直接写icon@2x.png、strip@2x.png即可,WebClient会自动处理路径编码,手动写%40会导致实际请求路径重复编码,下载到错误的内容 - 加日志打印下载到的图片字节长度,确认服务器网络策略没有拦截对象存储的请求,不会下载到403/404的错误页内容
- 2x分辨率的图片路径不要手动写URL编码的
- 手动校验生成文件:把服务器生成的pkpass后缀改成.zip解压,检查三个核心点:
- 包内是否包含
signature文件,且文件大小不为0 manifest.json里是否列出了包内所有文件的哈希值,没有遗漏pass.json里的PassTypeIdentifier、TeamIdentifier是实际申请的证书对应值,不是占位符
- 包内是否包含
- 确认服务器环境的系统编码不会篡改生成的json内容,所有文本输出用UTF-8无BOM编码。
内容的提问来源于stack exchange,提问作者Shahryar Faraji
相关产品推荐
相关产品推荐

