ENJOY的Apple Pay应用内支付接入实践

转载 2016年08月29日 10:55:03

导读: Apple Pay的应用内支付提供了一种全新的在线支付形式,如果将Apple Pay应用内支付自身的特点与App本身的产品形态相结合,用户的在线支付体验将得到大幅提升。ENJOY作为Apple Pay中国区首发的支持ApplePay应用内支付的App之一,在跟Apple Pay的接入时与产品功能做了深度集成,本文基于此对包括可用性、payment sheet、服务器解密、交易处理等在内的Apple Pay技术接入要点进行了经验上的深度分享。

Apple Pay已经在大陆地区正式上线,但大家的关注点大多集中在其线下支付的体验上。对于我们应用开发者而言,Apple Pay的应用内支付给我们提供了一种全新的在线支付形式。如果将Apple Pay应用内支付自身的特点跟App本身的产品形态相结合,用户的在线支付体验可以得到大幅提升。

Apple Pay与现有支付方式对比

在国内开发包含在线支付功能的应用,目前可用的选择就是接入第三方支付平台,比如支付宝或者微信支付。这些支付方式在接入方式上大同小异,就是在App中引入对应平台的SDK,在将支付信息组织好之后,调用对应第三方平台的SDK来完成支付。不同平台的SDK对支付的请求处理各不相同,总的来说完成支付有两种方式:调起对应的App或者打开一个网页。比如微信,就只支持打开微信App来进行支付这一种形式。
Apple Pay与现有第三方支付平台相比的优点有:

  1. 系统级支持,支付过程不需要跳转到第三方App;
  2. 支付过程可以获取用户信息,比如手机号、送货地址等。

Apple Pay应用内支付的接入方式跟微信等第三方平台不一样。作为iOS系统原生支持的特性,Apple Pay的相关功能包含在系统的PassKit这个Framework里,不需要引入第三方SDK便可集成。

Apple Pay深度集成

拿我们的产品ENJOY来说,作为Apple Pay中国区首发的支持Apple Pay应用内支付的App之一,在跟Apple Pay的接入时与产品功能做了深度集成。除了Apple Pay有着目前最短的支付路径这一特点,还有一个我们认为的最大优点,就是Apple Pay提供了系统级的由用户自行维护的个人信息。基于这些特点,与我们现有的用户系统和支付系统相结合,应用内支付体验有了很大提升。

ENJOY与Apple Pay集成后特点:

  • 未登录用户通过Apple Pay直接购买商品;
  • 首页商品一键购买;
  • 闪购商品一键购买;
  • 比第三方支付提前一步完成购买。

其中最有亮点的地方就是第一点,未登录用户可以直接购买商品。就目前的电商应用来说,用户只有在登录应用之后,才能购买商品。而ENJOY之所以能做到这一点,是因为对ENJOY来说,只要能够拿到用户的手机号,便可以与我们的用户体系相关联,并完成购买流程。正是利用了手机号可以由Apple Pay提供给应用的这一特性,ENJOY实现了未登录用户通过 Apple Pay可以直接购买商品这一功能(如图1所示)。

payment_sheet_logout_update

图1 未登录状态下购买商品时payment sheet截图,可以看到其中的联系方式字段

Apple Pay技术接入要点

首先来看一下Apple Pay应用内支付的时序图(如图2所示)。

Apple Pay时序图

图2 Apple Pay时序图

从时序图中可以清楚地看到,应用内支付流程分为以下几个步骤:

  1. App显示Payment Sheet,提示用户进行支付验证操作(指纹和 PIN 码);
  2. 用户支付验证完成,iOS系统与Apple的服务器进行交互,处理支付信息(主要是加密);
  3. App收到系统回调,然后将回调里包含的支付信息传给自己的服务器;
  4. 自己服务器收到App发来的信息,进行解密处理后,将需要的信息组织成银联报文,然后调用银联扣款接口,完成扣款;
  5. 服务器通知App支付结果,App更新相应的UI。

由上面的步骤可以看出,虽然实际使用时Apple Pay支付的时间很短,但App从显示payment sheet一直到支付成功,其中的过程还是很复杂的。在实际开发中,有很多需要注意的地方,下面具体说明一下。

Apple Pay可用性判断

应用如果显示Apple Pay按钮,需要先判断Apple Pay功能是否可用。这项实现需要结合PassKit Framework中PKPaymentAuthorizationViewController类的两个类函数才能完成判断,它们分别是:

class func canMakePayments() -> Bool

class func canMakePaymentsUsingNetworks(supportedNetworks: [String]) -> Bool

第一个函数返回值代表当前设备是否支持 Apple Pay,是用来判断设备硬件的。就目前来说,只有iPhone 6、iPhone 6 Plus、iPhone 6s和iPhone 6s Plus这四款设备支持Apple Pay。

第二个函数则是判断指定的支付网络是否支持。Apple Pay在国内的支付网络就是银联,所以需要传入PKPaymentNetworkChinaUnionPay这个值。

同时,需注意API的版本可用性,以上两个函数都是iOS 8才开始支持的API,其中 PKPaymentNetworkChinaUnionPay这个支付网络更是从iOS 9.2才开始支持,所以判断是否支持Apple Pay的最终代码是这样的:

if #available(iOS 9.2, *) {
         if PKPaymentAuthorizationViewController.canMakePayments() && PKPaymentAuthorizationViewController.canMakePaymentsUsingNetworks([PKPaymentNetworkChinaUnionPay]) {
                // TODO: 支持 Apple Pay
            }
}

注意: 一定要把工程target设置的Capabilities里的Apple Pay选项打开,不然在真机调试的时候,以上代码判断结果肯定是不支持的。

Payment sheet显示

Payment sheet也就是Apple Pay支付的UI,有不少地方是可以自定义的。想要自定义payment sheet,需要对类PKPaymentAuthorizationViewController的初始化参数paymentRequest做相应的设置。paymentRequest参数是一个PKPaymentRequest类型的对象(如图3所示)。

iOS端Apple Pay结构

图3 iOS端Apple Pay结构

首先,初始化一个PKPaymentRequest对象,并设置必需内容:

let request = PKPaymentRequest()
request.merchantIdentifier = "merchant.xxxxx”
request.merchantCapabilities = [.Capability3DS, .CapabilityEMV, .CapabilityCredit, .CapabilityDebit]
request.countryCode = "CN"
request.currencyCode = "CNY"
request.supportedNetworks = [PKPaymentNetworkChinaUnionPay]

merchantIdentifier需要与苹果开发者后台的配置相对应。以上代码中还有一个必需属性 paymentSummaryItems没有设置,该属性代表在payment sheet中显示的价格列表,是一个PKPaymentSummaryItem类型的数组。该数组至少要有一个元素,并且最后一个元素所包含的价格,就是实际要支付的价格。如果需要显示手机号或者收货地址,则可以对 requiredShippingAddressFields这个属性做相应的设置。

设置完毕后,通过以下代码可以调起payment sheet:

let vc = PKPaymentAuthorizationViewController(paymentRequest: request)
vc.delegate = self
presentViewController(vc, animated: true, completion: nil)

关于payment sheet这个UI需要特别说明:这个UI的视图优先级相当高,连alert都会被盖住,App在处理这个UI的时候需要注意。当payment sheet显示和消失时,对应的App也相当于进入后台和切回前台,所以,系统通知和AppDelegate里的回调函数也都会有所响应。

服务器解密流程

在用户输入指纹和PIN码验证之后,回调函数func paymentAuthorizationViewController(_, didAuthorizePayment: completion: )将会被调用,其中参数didAuthorizePayment类型是 PKPayment, 里面包含两类信息。第一种是明文的用户信息,对应的是初始化payment sheet 时的设置。另外一种就是加密过的支付信息,PKPayment有一个token属性,该属性的类型是PKPaymentToken,其中的paymentData属性就是加密过的支付信息。paymentData的内容是一个JSON的二进制流,将其解析之后,结构如下:

{
    data = "xxxxx";
    header = {
        publicKeyHash = "xxxxx";
        transactionId = bce2f62f92cb1f5b16696f1ea3b1b375cbfe8fe45c9132ae381c77ed45202455;
        wrappedKey = "xxxx";
    };
    signature = "xxx";
    version = "RSA_v1";
}

使用signature字段对消息进行验签,防止信息被篡改。之后取出header.wrappedKey的内容,它是使用非对称加密算法加密过的对称秘钥。用在苹果开发者后台配置merchantID时的私钥进行解密,就能得到这个对称秘钥。然后,使用这个对称秘钥对data所包含的加密数据进行解密,取得Apple返回的支付信息。此支付信息是加密过的,包含了用户支付的卡号和 PIN码等信息,理论上只有银联才能解析出来真正的内容,对我们商户而言其内容是加密的。服务器端需要将这些解密过的信息组织成银联所需的报文内容,随后调用银联的扣款接口,完成扣款。

银联交易状态确认

在调用银联的扣款接口后,有一点非常重要,就是要确保扣款结果是否成功。只有确切的知道了扣款结果,才能正确地设置自己平台的用户订单状态。银联的扣款接口设计是这样的,在调用接口之后,返回同时有同步和异步两种形式。如果同步结果返回成功,只是说明银联成功收到并开始处理扣款请求,并不代表扣款成功。扣款是否成功,是通过异步形式来通知的。而扣款不成功的原因有很多,比如卡被冻结、PIN码错误、余额不足等等。

我们采用的做法是这样的,调用扣款接口后,如果3秒内没有收到本次调用的异步回调,则通过使用同步结果返回的银联流水号,开始轮询银联的另外一个交易状态接口来确保拿到交易结果。

交易失败的处理

如果发生交易失败的情况,App需要做相应的UI处理。按照Apple的交互要求,以下几种失败情况,payment sheet不能退出,其余的情况则需要退出payment sheet后,由App负责通知给用户。

  • 未输入PIN码;
  • PIN码错误;
  • PIN码失败次数超过限制。

payment sheet的显示结果是由func paymentAuthorizationViewController(_, didAuthorizePayment: completion: )这个回调函数中的completion这个参数来控制的。该参数是一个closure,它的第一个参数类型是PKPaymentAuthorizationStatus的枚举,打开该枚举的定义,可以看到上面的情况已经由操作系统定义好了,对应起来分别是:

  • PINRequired
  • PINIncorrect
  • PINLockout

UI显示的细节:在调用completion后,如果传入的PKPaymentAuthorizationStatus值是Success 或者Failure,payment sheet在展示出相应的结果之后都会自动dismiss掉。而如果传入的是上面三个有关PIN码的值,则payment sheet并不会消失,用户可以继续选择银行卡,然后进行指纹验证等支付操作。

交易撤销

在payment sheet显示出来到消失的这段时间内的任意时刻,用户都可以通过点击payment sheet右上角的「取消」按钮来手动取消支付,那这就涉及到了交易撤销的问题。交易撤销是由服务器来完成的,那么App要做的首先是把用户取消的事件通知给服务器。由于整个支付过程步骤很多,总的来说,服务器撤销交易要面临以下三种情况:

  • 还未向银联调用扣款接口;
  • 已调用扣款接口,但扣款结果还未返回;
  • 扣款成功。

第一种情况很容易处理,只要服务器之后不再调用银联扣款接口即可。第二种和第三种情况的处理方法一样,区别在于第二种情况的处理时机是在获取到扣款成功结果之后。如果是后两种情况,则调用银联的交易撤销接口,以撤销之前的交易,把已经扣除的用户款项返还给用户。

注意: 由于有些银行不支持交易撤销,所以调用交易撤销接口后需要判断一下返回结果,如果不支持,则还需调用退款接口来返回款项。

总结

Apple Pay应用内支付的在技术上并不难,但所涉及的细节非常多,需要花费不少功夫处理好各种情况。如果对Apple Pay应用内支付定制化需求并不强,有不少第三方支付平台目前已经提供了自己封装的SDK来供开发者使用,比如银联的CUP SDK等。这些SDK屏蔽了支付过程中的很多细节,可以方便地接入到App中。但如果需要接入原生的Apple Pay来实现好的应用内支付体验,那么本文可以给你提供一些帮助。

作者简介: 陈乘方(@webfrogs),严肃科技iOS项目负责人,ENJOY和饭本的应用架构和主要开发者。专注于iOS应用架构、动画以及新技术的使用与实践。
责任编辑: 唐小引(@唐门教主),欢迎技术投稿、约稿,给文章纠错,请邮件至tangxy@csdn.net

本文为《程序员》杂志3月版特约文章,版权归CSDN所有,未经允许,不得转载,订阅详情可点击:http://dingyue.programmer.com.cn/

第一时间掌握最新移动开发相关信息和技术,请关注mobilehub公众微信号(ID: mobilehub)。

mobilehub

举报

相关文章推荐

ENJOY的Apple Pay应用内支付接入实践

导读: Apple Pay的应用内支付提供了一种全新的在线支付形式,如果将Apple Pay应用内支付自身的特点与App本身的产品形态相结合,用户的在线支付体验将得到大幅提升。ENJOY作为Apple...

iOS Apple Pay支付

1.申请MerchantID 登录苹果开发者中心:https://developer.apple.com/account/ 在Identifiers 下面的 Merchant IDs 创建,Descr...

精选:深入理解 Docker 内部原理及网络配置

网络绝对是任何系统的核心,对于容器而言也是如此。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker的网络一直以来都比较薄弱,所以我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

App集成ApplePay的一些资料整理

首先apple pay不是苹果自己的事,所以,除了要看苹果的资料,把代码写进ios客户端app,还需要看银联的接口,把钱弄到你的卡里。 而且发现银联的网站上居然有比苹果更易懂的文档,但是银联资料下载下...

An App ID with Identifier "xxx" is not available . Please enter a different string.解决方法

在调试applePay的时候遇到这个问题 ,点击fix issue 完全不管用。 解决方法: 1.去开发者中心,找到对应的appleId ,看看这个appleId对应的apple pay支付这个功...

Apple Pay强势来袭,开发者应做的事情

转自 http://www.cocoachina.com/ios/20160219/15345.html "iOS8.1就已经有这个功能了,只是木有现在这么的火,现在的趋势是要火的节...
  • args_
  • args_
  • 2016-02-29 14:23
  • 296

Apple Pay接入详细教程

Apple Pay接入详细教程 2016-02-26 11:19 编辑: suiling 分类:iOS开发 来源:Yasin 投稿 10 5577 iOSApple ...
  • Lu_Ca
  • Lu_Ca
  • 2016-03-14 15:01
  • 325

Apple pay初探

做iOS开发的亲们,最近是不是发现Apple Pay很火啊?迫不及待的想写个demo试一试了。 首先什么是Apple Pay? 它不是应用内支付,Apple Pay用于销售物理商品,比如食品杂货、衣服...

Apple Pay 应用内支付流程分析

简介Apple Pay 已经正式上线,ENJOY 作为国内首批接入 Apple Pay 应用内支付的 App,并且是为数不多的直接使用 PassKit Framework 和银联接口的形式接入的应用,...

Apple Pay 技术分享_陈hong_鑫

知识体系 1.  什么是 Apple Pay? Apple Pay,是苹果公司在2014苹果秋季新品发布会上发布的一种基于NFC的手机支付功能,于2014年10月20日在美国正式上线。20...

Apple Pay支付流程详解

前不久Apple Pay开始了,大家做好接入的准备了吗?今天写了个demo,悲催的是开发者账号上设备满了,只能用模拟器给大家看了。。。疑问是:在开发Apple Pay的时候,Xcode 7无法 无证书...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)