Clover SDK for iOS POS Integration
版本
版本:3.3.12
概述
此SDK允许您的iOS基础点-of-Sale (POS)系统与Clover®支付设备通信并处理付款。
它包括SDK和一个示例POS。要有效地使用项目,您需要以下条件:
- XCode 12.2
- 您的设备上iOS 10.0及以上
- Cocoapods
为了从商家和客户的角度体验端到端的交易,我们还建议订购Clover Go Developer Kit
该SDK使您的自定义移动点-of-Sale (POS)能够接受卡面交易、符合EMV标准的支付交易。Clover Go支持两种类型的读卡器:磁条、EMV芯片签名卡读卡器(音频插孔)和全功能读卡器(蓝牙),支持滑动、EMV插卡和非接触式支付。该SDK设计用于让商家在iOS智能手机和平板电脑上接受付款。
Clover Go SDK的核心功能包括:
- 卡片显示交易 – 在这种交易中,商家使用经批准的读卡器在连接的智能手机或平板电脑上接受物理贷记卡或借记卡。Clover Go平台支持以下支付方式:
- 磁条卡 – 一种带有磁条的传统的支付卡。
- EMV卡 – 一种含有计算机芯片的支付卡,提高了数据安全性。Clover Go的EMV兼容平台允许客户或商家将EMV卡插入读卡器。
- NFC非接触式支付 – 一种交易,客户可以通过将他们的移动设备触摸到读卡器,使用Apple Pay、Samsung Pay或Android Pay移动钱包来完成。
Clover Go SDK目前支持以下支付交易
- 销售 - 一种同时授权和捕获支付金额的交易。销售交易是最终的,金额不能调整。
- 授权 - 一种可以调整小费直至在批处理结账时最终确定交易。这是餐厅在刷卡后调整金额以包含小费的标准模式。
- 取消 - 一种取消或完全撤销支付交易的交易。
- 退款 - 一种将资金贷记给账户持有人的交易。
- 预授权 - 对一定金额的预授权。
- 预授权捕获 - 已最终确定的预授权以完成支付(例如,结账的酒吧账单)。
- 部分授权 - 部分授权。如果交易金额超出客户的信用卡或借记卡限额,支付网关可能会返回部分授权。
- 小费调整 - 一种在客户卡片处理(例如,在初始授权交易之后)后商家提取或编辑小费的交易。
入门指南
本部分将提供一些快速步骤以开始使用SDK。要集成到Clover Go设备,您需要使用正确的初始化值初始化CloverGoDeviceConfiguration对象,这包括通过OAuth流程获取的accesstoken。您需要遵循以下初始步骤
初始设置
1. 创建开发者账户: 访问Clover沙盒开发者门户 https://sandbox.dev.clover.com/developers/ 并创建一个开发者账户。
2. 创建新应用: 登录开发者门户并创建一个新的应用 - 输入应用名称、唯一的包名称,并勾选您的应用程序正常运行所需的所有Clover权限。
3. 应用设置/凭证: 创建应用后,您可以记下App ID和Secret,这些将在OAuth流程中在您的代码中使用。
4.为您的OAuth流程提供重定向URL:在Web配置设置中的网站URL字段中,输入Clover应该将授权响应重定向到的重定向URL。默认的OAuth响应应该是“Code”。
注意:目前开发者门户不接受非http(s) URL方案。如果您为原生iOS和Android应用程序(如myPaymentApp://clovergoauthresponse)有自定义URL方案,请发送一封电子邮件到[email protected],并提供您的App ID和重定向URL请求。
5.设置应用权限:您的应用程序需要Clover权限才能正常工作。通过转到设置,然后选择必需权限菜单来设置权限。
6.设置您的唯一应用程序ID:为您的应用程序提供唯一的应用程序ID,您可以使用您的包名或任何唯一标识您的应用程序交易的标识符。请在应用程序设置中的应用程序集成部分设置此ID。
请确保您的应用程序包标识符与此字段中定义的相同。
OAuth流程
本节描述了获取初始化CloverGoDeviceConfiguration对象所需的访问令牌的OAuth流程步骤。
步骤1。使用您的应用程序(如上所述的步骤#3)的App ID从您的pos应用程序调用Clover授权URL。此操作将提示用户登录到Clover商户账户。登录成功后,他们需要批准应用程序进行首次初始登录。沙盒环境的授权URL:https://sandbox.dev.clover.com/oauth/authorize?client_id={app_id}&response_type=code
步骤2。用户将被重定向到步骤4中设置的重定向URL。
步骤3。解析URI数据以获取商户ID、雇员ID、客户端ID和代码。
步骤4。在您的后端服务器上执行包含客户端ID(它是app id)、密钥和代码的REST调用以获取访问令牌。https://sandbox.dev.clover.com/oauth/token?client_id={appId}&client_secret={appSecret}&code={codeUrlParam}
注意请注意,本项目中的示例应用程序提供了一项托管服务作为步骤4。请使用自己的类似服务来执行此步骤。
步骤5。解析步骤4的响应并检索访问令牌。访问令牌为SDK提供了商户和雇员上下文,所有交易都将在此上下文中处理。
开发XCode iOS项目设置
add pod 'GoConnector', '3.0.0' in your PODFILE in target
For example -
platform :ios, '9.0'
use_frameworks!
target 'CloverConnector_Example' do
pod 'GoConnector', '~> 3.0.0'
end
在您的应用程序中使用SDK
AppDelegate.swift
文件中声明以下...
1. 在您的 public var cloverConnector:ICloverGoConnector?
public var cloverConnectorListener:CloverGoConnectorListener?
CloverGoConnectorListener.swift
继承自 ICloverGoConnectorListener
2. 创建 import GoConnector
weak var cloverConnector:ICloverGoConnector?
public init(cloverConnector:ICloverGoConnector){
self.cloverConnector = cloverConnector;
}
以下是在此类中添加的有用的方法 ... 实现所有 CardReaderDelegate
方法 ...
func onDevicesDiscovered(devices: [CLVModels.Device.GoDeviceInfo])
- 当检测到卡读取器并被从读取器列表中选择时,将调用此委托方法func onDeviceReady(merchantInfo: MerchantInfo)
- 当设备准备好通信时调用func onDeviceConnected () -> Void
- 当设备首次连接时调用func onDeviceDisconnected () -> Void
- 当设备断开连接或未响应时调用func onDeviceError( _ deviceErrorEvent: CloverDeviceErrorEvent ) -> Void
– 当连接到读取器出错时调用
在此处实现所有 TransactionDelegate
方法 ...
func onTransactionProgress(event: CLVModels.Payments.GoTransactionEvent) -> Void
- 当事务开始后,在卡读取器上发生任何事件时调用
参数 event: 提供有关交易过程中卡读取器事件的详细信息
switch event
{
case .EMV_CARD_INSERTED,.CARD_SWIPED,.CARD_TAPPED:
break
case .EMV_CARD_REMOVED:
break
case .EMV_CARD_DIP_FAILED:
break
case .EMV_CARD_SWIPED_ERROR:
break
case .EMV_DIP_FAILED_PROCEED_WITH_SWIPE:
break
case .SWIPE_FAILED:
break
case .CONTACTLESS_FAILED_TRY_AGAIN:
break
case .SWIPE_DIP_OR_TAP_CARD:
break
default:
break;
}
-
func onSaleResponse(response: SaleResponse)
– 当销售请求完成并且处于支付或取消状态时调用 -
func onAuthResponse(response: AuthResponse)
– 当授权请求完成并且处于支付或取消状态时调用 -
sale - 收集最终销售付款
-
auth - 收集可以调整小费的付款
注意:您必须在此添加 ICloverConnectorListener
类的其他方法,但可以留空,如 onRetrieveDeviceStatusResponse, onMessageFromActivity,
等。
3. 使用450读取器初始化SDK
以下参数是SDK初始化所必需的
- apiKey - 在注册时提供给开发者的密钥
- secret - 在注册时提供给开发者的密钥
- accessToken - 在注册时提供给开发者的访问令牌
- allowDuplicateTransaction - 为了黑客松的目的,设置为true
- allowAutoConnect - 为了黑客松的目的,设置为true
func connectToCloverGoReader() {
let config : CloverGoDeviceConfiguration = CloverGoDeviceConfiguration.Builder(apiKey: "", secret: "", env: .live).accessToken(accessToken: "").deviceType(deviceType: .RP450).allowDuplicateTransaction(allowDuplicateTransaction: true).allowAutoConnect(allowAutoConnect: true).build()
cloverConnector = CloverGoConnector(config: config)
cloverConnectorListener = CloverGoConnectorListener(cloverConnector: cloverConnector!)
cloverConnectorListener?.viewController = self.window?.rootViewController
(cloverConnector as? CloverGoConnector)?.addCloverGoConnectorListener(cloverConnectorListener: (cloverConnectorListener as? ICloverGoConnectorListener)!)
cloverConnector!.initializeConnection()
}
4. 执行销售交易
销售交易所需的参数
- amount – 实际交易的总金额
- externalId: 为此次交易生成一个随机唯一数字
其他可选参数在黑客松中可以忽略
@IBAction func doSaleTransaction(sender: AnyObject) {
let totalInInt = Int(totalAmount * 100) -- amount should be in cents
let saleReq = SaleRequest(amount:totalInInt, externalId:"\(arc4random())") – pass total amount in cents and random external Id
(UIApplication.sharedApplication().delegate as! AppDelegate).cloverConnector?.sale(saleReq) – make sale request
}
4. 执行授权交易
授权交易所需的参数
- amount – 实际交易的总金额
- externalId: 为此次交易生成一个随机唯一数字
其他可选参数在黑客松中可以忽略
@IBAction func doAuthTransaction(sender: AnyObject) {
let totalInInt = Int(totalAmount * 100) -- amount should be in cents
let authReq = AuthRequest(amount:totalInInt, externalId:"\(arc4random())") – pass total amount in cents and random external Id
(UIApplication.sharedApplication().delegate as! AppDelegate).cloverConnector?.auth(authReq) – make auth request
}
5. 处理重复和AVS交易错误
public func onConfirmPaymentRequest(_ request: ConfirmPaymentRequest)
-- 如果设备需要支付确认(重复验证),则会调用
处理重复交易的示例代码:如有重复交易返回,将弹出一个窗口询问用户是否继续(即提供2个选项“接受”或“拒绝”)
- 接受 -
strongSelf.cloverConnector?.acceptPayment(payment)
- 拒绝 –
strongSelf.cloverConnector?.rejectPayment(payment)
public func onConfirmPaymentRequest(_ request: ConfirmPaymentRequest) {
if let payment = request.payment,
let challenges = request.challenges {
confirmPaymentRequest(payment: payment, challenges: challenges)
} else {
showMessage("No payment in request..")
}
}
func confirmPaymentRequest(payment:CLVModels.Payments.Payment, challenges: [Challenge]) {
DispatchQueue.main.async { [weak self] in
guard let strongSelf = self else { return }
if challenges.count == 0 {
print("accepting")
strongSelf.cloverConnector?.acceptPayment(payment)
} else {
print("showing verify payment message")
var challenges = challenges
let challenge = challenges.removeFirst()
var alertActions = [UIAlertAction]()
alertActions.append(UIAlertAction(title: "Accept", style: .default, handler: { [weak self] action in
guard let strongSelf = self else { return }
strongSelf.confirmPaymentRequest(payment: payment, challenges: challenges)
}))
alertActions.append(UIAlertAction(title: "Reject", style: .cancel, handler: { [weak self] action in
guard let strongSelf = self else { return }
strongSelf.cloverConnector?.rejectPayment(payment, challenge: challenge)
}))
strongSelf.showMessageWithOptions(title: "Verify Payment", message: challenge.message ?? "", alertActions: alertActions)
}
}
}