前言
根据目前系统钱包中的能够添加的卡,大致可分为三类
- 银行卡/交通卡
- 电子卡(例如:美团闪付/京东闪付)
- 消费凭证 (电影票/机票/优惠券)
消费凭证
消费凭证,大致分为五类,具体请看下图,对于每种凭证的包含信息,点我
制作凭证并添加到Wallet
创建pass包
先学习一波,----> 请看大屏幕
创建一个 Pass 包
首先要明白 Pasees 是以 Pass 包 形式创建的,Pass 包里面包含一个 pass.json 文件,一些图片资源(像 icon, logo 等)
创建一个 Pass 包:
(1)在 Finder 的 Desktop 初 创建一个 名为 Lollipop.pass 的文件夹
(2)下载苹果提供的资源文件(包括一些 Pass 包例子, 一个签名工具, 一个测试服务器)
下载资源:在官方文档中点击 developer downloads area ,即可下载
(3)在苹果资源处将 Event.pass 文件夹中的所有内容拷贝到 Lollipop.pass 文件夹中。
- 设置 Pass Type Identifier 和 Team ID
每一个 pass 都有和开发者账号相关连的 Pass Type Identifier
官方文档如下:
To register a pass type identifier, do the following:
In Certificates, Identifiers & Profiles, select Identifiers.
Under Identifiers, select Pass Type IDs.
Click the plus (+) button.
Enter the description and pass type identifier, and click Submit.
To find your Team ID, do the following:
Open Keychain Access, and select your certificate.
Select File > Get Info, and find the Organizational Unit section under Details. This is your Team ID.
The pass type identifier appears in the certificate under the User ID section.
按照苹果的意思在自己的开发账号内生成一个 Pass Type ID, 然后在 pass.json 文件内替换生成的Pass Type ID, Team ID 同理,开发者账号内找到并且在 pass.json 文件内替换。
步骤如下:
在 Certificates, Identifiers & Profiles, 选择 Identifiers
在 Identifiers 下,选择 Pass Type IDs.
选择你已经创建好的 pass type identifier, 点击编辑。
如果已经存在证书文件,直接点击下载即可。如果没有,点击创建,按照提示创建一个(与创建 APNs 推送证书基本一样)。
如果有选择已经有的,如果没有则从电脑导出来
生成好之后如下:
下载之后,双击安装到电脑。
- 修改pass.json文件的ID
查看 Team ID:
到开发者账号下,选择 MemberShip 。
- 添加 PassTypeID 和 Team ID 到 pass.json
PassTypeID: pass.com.cuilinhao.TestPassKit
Team ID: P6E2X8E5T9
打开 Lollipop.pass 文件夹下的 pass.json , 将 PassTypeID 和 Team ID 替换为自己开发者账号下的。
{
...
"passTypeIdentifier" : "your pass type identifier",
"teamIdentifier" : "your Team ID",
...
}
- 生成 .pkpass 后缀的压缩文件
找到之前下载的文件,WalletDemo-master/WalletTest.xcodeproj
使用xcode运行选中 Xcode 中 Products 文件夹下的 signpass 文件,右击鼠标,Show in Finder。
拷贝 signpass 文件到 filmTicket.pass 文件夹的同级目录(Desktop)下。
执行以下语句:
cd ~/Desktop
./signpass -p Lollipop.pass
创建Xcode 项目 添加凭证到Wallet
直接放代码,其他文件配置可下载查看,点我
- (void)viewDidLoad {
[super viewDidLoad];
PKAddPassButton *pkAddBtn = [[PKAddPassButton alloc] initWithAddPassButtonStyle:PKAddPassButtonStyleBlack];
pkAddBtn.titleLabel.font = [UIFont systemFontOfSize:12];
pkAddBtn.frame = CGRectMake(100, 100, 220, 40);
[self.view addSubview:pkAddBtn];
[pkAddBtn addTarget:self action:@selector(pkClick:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)pkClick:(PKAddPassButton *)sender
{
NSString *passPath = [[NSBundle mainBundle] pathForResource:@"Lollipop" ofType:@"pkpass"];
NSData *passData = [[NSData alloc] initWithContentsOfFile:passPath];
NSError *error = nil;
PKPass *pass = [[PKPass alloc] initWithData:passData error:&error];
if (error) {
NSLog(@"创建pass 过程中发生错误,错误信息:%@", error.localizedDescription);
}
PKAddPassesViewController *vc = [[PKAddPassesViewController alloc] initWithPass:pass];
vc.delegate = self;
[self presentViewController:vc animated:YES completion:nil];
}
#pragma mark - delegate
- (void)addPassesViewControllerDidFinish:(PKAddPassesViewController *)controller
{
NSLog(@"add pass finished");
[self dismissViewControllerAnimated:YES completion:nil];
}
修改凭证信息,重新生成
- 原有pass.json 文件,
{
"formatVersion" : 1,
"passTypeIdentifier" : "pass.com.cuilinhao.TestPassKit",
"serialNumber" : "nmyuxofgna",
"teamIdentifier" : "P6E2X8E5T9",
"webServiceURL" : "https://example.com/passes/",
"authenticationToken" : "vxwxd7J8AlNNFPS8k0a0FfUFtq0ewzFdc",
"relevantDate" : "2011-12-08T13:00-08:00",
"associatedStoreIdentifiers" : [728326385],
"appLaunchURL" : "http://www.xingshulin.com",
"locations" : [
{
"longitude" : -122.3748889,
"latitude" : 37.6189722
},
{
"longitude" : -122.03118,
"latitude" : 37.33182
}
],
"barcode" : {
"altText" : "订单号:123456",
"message" : "123456789",
"format" : "PKBarcodeFormatQR",
"messageEncoding" : "iso-8859-1"
},
"organizationName" : "Apple Inc.",
"description" : "Apple Event Ticket",
"foregroundColor" : "rgb(255, 255, 255)",
"backgroundColor" : "rgb(60, 65, 76)",
"headerFields" : [
{
"key" : "filmName",
"label" : "影片",
"value" : "加勒比海盗5:死无对证",
"textAlignment" : "PKTextAlignmentNatural"
}
],
"eventTicket" : {
"primaryFields" : [
{
"key" : "filmName",
"label" : "影片",
"value" : "test1111111",
"textAlignment" : "PKTextAlignmentNatural"
}
],
"secondaryFields" : [
{
"key" : "orderNumber",
"label" : "订单号",
"value" : "test2",
"textAlignment" : "PKTextAlignmentLeft"
},
{
"key" : "verificationNumber",
"label" : "验证码",
"value" : "test222",
"textAlignment" : "PKTextAlignmentRight"
}
],
"auxiliaryFields" : [
{
"key" : "site",
"label" : "影院",
"value" : "test333",
"textAlignment" : "PKTextAlignmentLeft"
},
{
"key" : "order",
"label" : "场次",
"value" : "test3",
"textAlignment" : "PKTextAlignmentCenter"
},
{
"key" : "seat",
"label" : "座位",
"value" : "test333333",
"textAlignment" : "PKTextAlignmentRight"
}
],
"backFields" : [
{
"numberStyle" : "PKNumberStyleSpellOut",
"label" : "spelled out",
"key" : "numberStyle",
"value" : 200
},
{
"label" : "in Reals",
"key" : "currency",
"value" : 200,
"currencyCode" : "BRL"
},
{
"dateStyle" : "PKDateStyleFull",
"label" : "full date",
"key" : "dateFull",
"value" : "1980-05-07T10:00-05:00"
},
{
"label" : "full time",
"key" : "timeFull",
"value" : "1980-05-07T10:00-05:00",
"timeStyle" : "PKDateStyleFull"
},
{
"dateStyle" : "PKDateStyleShort",
"label" : "short date and time",
"key" : "dateTime",
"value" : "1980-05-07T10:00-05:00"
},
{
"dateStyle" : "PKDateStyleShort",
"label" : "relative date",
"key" : "relStyle",
"value" : "2013-04-24T10:00-05:00",
"isRelative" : true
}
]
}
}
上述代码和制作出的卡包是对应的,test11111对应代码如下:
"eventTicket" : {
"primaryFields" : [
{
"key" : "filmName",
"label" : "影片",
"value" : "test1111111",
"textAlignment" : "PKTextAlignmentNatural"
}
],
其他部分,依次类推,其中下方的二维码部分,对应代码如下:
// 修改前
"barcode" : {
"message" : "123456789",
"format" : "PKBarcodeFormatPDF417",
"messageEncoding" : "iso-8859-1"
}
// 修改后
"barcode" : {
"altText" : "订单号:123456",
"message" : "123456789",
"format" : "PKBarcodeFormatQR",
"messageEncoding" : "iso-8859-1"
}
- 更新好pass.json 之后再次执行
cd Desktop/
./signpass -p Lollipop.pass
然后将下面三个文件替换,Xcode运行项目安装
- pass.json 官方说明
更新凭证信息
流程图如下:
- pass 被设置为支持更新和安装,并且用户设备注册到你的服务器获取更新。
- 如果有变更,则触发更新,你的服务器发送推送通知。
- 用户收到推送后,从你的服务器查询更新的列表。
- 用户从你的服务器获取每个 pass 的最新版本到自己的设备。
附上Demo OC版&& Swift版本
京东闪付卡/美团闪付卡/银行卡
这一类的卡,是通过公司接入银联支付产生的,具体可参考银联官网,并可直接电话联系咨询,京东和美团的闪付卡都是接入银联中的一个手机闪付业务做成闪付卡,然后添加到系统钱包。
在iOS Developer Wallet中,也介绍到,使用PKAddPaymentPassViewController可以添加这类卡,苹果官方描述如下:
Adding payment passes requires a special entitlement issued by Apple. Your app must include this entitlement before this class can be instantiated. For more information on requesting this entitlement, see the Card Issuers section at [developer.apple.com/apple-pay/](https://developer.apple.com/apple-pay/).
>>>
添加付款通行证需要Apple颁发特殊权利。 您的应用程序必须在此类可实例化之前包含此权利。有关请求此权利的更多信息,请参阅“发卡机构”部分
如何做一个凭证,从钱包跳回App
In your pass.json file you can include a key to define an associated app:
"associatedStoreIdentifiers" : [Adam ID],
where Adam ID can be obtained from the link to the app in the app store:
[https://itunes.apple.com/app/id](https://itunes.apple.com/app/id)<Adam ID> ..
e.g. to get the Facebook App, go to:
[https://itunes.apple.com/us/app/facebook/id284882215](https://itunes.apple.com/us/app/facebook/id284882215)
To include it in a Pass, add this to pass.json:
"associatedStoreIdentifiers" : [284882215],
步骤如下:
拿到你的App 上架的时候的App ID
在制作凭证的.json文件中 设置该ID 为associatedStoreIdentifiers的value值,即:
"associatedStoreIdentifiers" : [1395841695]官方文档说明如下:
passKit 库用到的API
PKAddPassButton : 添加钱包按钮,主要有两种类型,PKAddPassButtonStyleBlack 、 PKAddPassButtonStyleBlackOutline
创建方式有两种:
- (instancetype)addPassButtonWithStyle:(PKAddPassButtonStyle)addPassButtonStyle;
- (instancetype)initWithAddPassButtonStyle:(PKAddPassButtonStyle)style NS_DESIGNATED_INITIALIZER;
PKPass 该类集成自 PKObject
PKPassType:枚举类型,
PKPassTypeBarcode:条码
PKPassTypePayment:支付
PKPassTypeAny:其它类型
构造方法:
- (instancetype)initWithData:(NSData *)data error:(NSError *)error;
PKPassLibrary 提供用户传递库
检测PKPassLibrary 是否可用
- (BOOL)isPassLibraryAvailable API_AVAILABLE(ios(6.0), watchos(3.0));
根据passtypeID 和serialNumber 返回pass
- (nullable PKPass *)passWithPassTypeIdentifier:(NSString *)identifier serialNumber:(NSString *)serialNumber;
根据passType返回pass
- (NSArray<PKPass *> *)passesOfType:(PKPassType)passType API_AVAILABLE(ios(8.0), watchos(3.0));
移除pass
- (void)removePass:(PKPass *)pass;
判断是否包含pass - (BOOL)containsPass:(PKPass *)pass;
替换一个pass - (BOOL)replacePassWithPass:(PKPass *)pass;
添加pass - (void)addPasses:(NSArray<PKPass *> *)passes withCompletionHandler:(nullable void(^)(PKPassLibraryAddPassesStatus status))completion API_AVAILABLE(ios(7.0), watchos(3.0));
PKPaymentPass 继承自 PKPass
PKPaymentPassActivationState 枚举类型,
PKPaymentPassActivationStateActivated,(已激活)
PKPaymentPassActivationStateRequiresActivation,(需要被激活)
PKPaymentPassActivationStateActivating,(正在激活)
PKPaymentPassActivationStateSuspended, (挂起)
PKPaymentPassActivationStateDeactivated (停用)
PKAddPaymentPassRequestConfiguration
该类包含初始化一个新的PKAddPaymentPassViewController实例的配置数据。加密机制,持卡人姓名,卡号后四位需要被提供。配置信息仅用来设置和显示。它不包含任何的敏感信息
重要说明:
添加Payment Pass支付卡需要一个特殊的由苹果发行的授权。在使用这个类之前app中必须包括这个授权
- (nullable instancetype)initWithEncryptionScheme:(PKEncryptionScheme)encryptionScheme
初始化一个新的配置对象
emcryptionScheme 用于该请求的加密机制。所有可能的值可以查看Encryption Schemes.
返回值:一个新的实例化的配置对象。
当实例化一个配置对象之后,在使用它创建一个PKAddPaymentPassViewController实例之前,也必须设置cardholderName和primaryAccountSuffix属性
cardholderName
显示在卡上面的姓名
encryptionScheme
用于该请求的加密机制
localizedDescription
对卡片简短的描述。
paymentNetwork
支付系统,默认为nil。该属性判断哪些卡片可以展示在PKAddPaymentPassViewController类的实例中并显示到屏幕上。PKAddPaymentPassViewController展示卡片区域的所有支持的系统。为了指定一个单一的系统,可指派给该属性一个常量。可查看PKPyamentRequest类的Payment Networks的介绍。
primaryAccountSuffix
后四位或五位卡号
Filtering Pass Libraries 筛选卡库
primaryAccountIdentifier
卡号账户的标识,筛选卡库(来自不同的设备 iPhone,iPhone Watch)
Constants 常量
Encryption Schemes
加密体制
NSString * const PKEncryptionSchemeECC_V2
PKAddPaymentPassViewController
使用提供的配置和代理,返回一个初始化的添加支付的视图控制器实例
/* This controller should be presented with -[UIViewController presentViewController:animated:completion:].
*/
- (nullable instancetype)initWithRequestConfiguration:(PKAddPaymentPassRequestConfiguration *)configuration
delegate:(nullable id<PKAddPaymentPassViewControllerDelegate>)delegate
configuration 配置实例:定义视图控制器的外观
delegate 添加支付视图控制器的代理
返回值:一个新的添加支付的视图控制器
添加Payment Pass支付卡需要一个特殊的由苹果发行的授权。如果app中不包括这个授权,该方法返回值为nil
PKAddPaymentPassViewControllerDelegate 代理
PKAddPaymentPassViewController类的代理必须遵守该协议。该协议定义了两个必需实现的方法。这些方法使系统提示添加支付请求和当请求失败或成功的时候法通知app。
- (void)addPaymentPassViewController:(PKAddPaymentPassViewController *)controller
generateRequestWithCertificateChain:(NSArray<NSData *> *)certificates
nonce:(NSData *)nonce
nonceSignature:(NSData *)nonceSignature
completionHandler:(void(^)(PKAddPaymentPassRequest *request))handler;
controller 添加支付请求的视图控制器
certificates NSData对象的数组。每个对象包括一个DER编码的证书。必须下载根目录CA验证整个链。
nonce 苹果服务器生成的一次性随机值,该随机值必须被包含在添加支付请求的加密数据中。
nonceSignature 有特定设备的签名的随机值。该签名必须被包含在添加支付请求的加密数据中。
handler 完工的处理者。当创建支付请求之后回调该Block。Block中的参数:request 一个新创建的添加支付请求,必须20秒之内传送该请求实例给处理者否则该请求将失败,系统将为用户显示一个错误信息。
该方法提供需要创建一个添加支付请求的书。通过证书束缚在发行者服务器上。该服务器返回一个包含卡数据的加密的JSON文件。当收到加密数据之后,创建一个添加支付请求并回调处理者。
更多关于加密卡数据的信息,可以查看PKPaymentRequest类里的encryptedPassData属性。
- (void)addPaymentPassViewController:(PKAddPaymentPassViewController *)controller didFinishAddingPaymentPass:(nullable PKPaymentPass *)pass error:(nullable NSError *)error;
controller 添加支付请求的视图控制器
pass 完成的卡,如果有错误,返回nil
error如果请求失败,该参数包含错误对象(PKPassKitErrorDomamin域错误) 。更多可能的错误代码,可查看枚举PKAddPaymentPassError。
当请求成功地添加卡片到Apple Pay或者失败时,调用该方法。
//----苹果支付-----
PKPaymentRequest 订单请求对象
PKPaymentSummaryItem 商品订单信息对象
配置商品价格,送货方式等
- (instancetype)summaryItemWithLabel:(NSString *)label amount:(NSDecimalNumber *)amount;
- (instancetype)summaryItemWithLabel:(NSString *)label amount:(NSDecimalNumber *)amount type:(PKPaymentSummaryItemType)type API_AVAILABLE(ios(9.0), watchos(3.0));
PKPaymentAuthorizationViewController 苹果支付请求控制器
初始化方法
- (nullable instancetype)initWithPaymentRequest:(PKPaymentRequest *)request NS_DESIGNATED_INITIALIZER;
PKPaymentAuthorizationViewControllerDelegate 代理方法
//支付银行卡回调,如果需要根据不同的银行调整付费金额,可以实现该代理
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didSelectPaymentMethod:(PKPaymentMethod *)paymentMethod completion:(void (^)(NSArray<PKPaymentSummaryItem *> * _Nonnull))completion
//支付凭据,发给服务端进行验证支付是否真实有效
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didAuthorizePayment:(PKPayment *)payment completion:(void (^)(PKPaymentAuthorizationStatus status))completion
//支付完成
- (void) paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller