版本:3.3.12
此 SDK 允许您的基于 iOS 的 POS(销售点)系统与 Clover® 支付设备通信并处理支付。
它包括 SDK 和一个示例 POS。为了高效地与该项目协同工作,您将需要以下内容:
- XCode 12.2
- 您的设备上的 iOS 10.0 及以上
- Cocoapods
为了从商家和客户的视角体验从头到尾的交易,我们还建议订购 Clover Go 开发套件
SDK 允许您的自定义移动 POS 接受信用卡、EMV 兼容的支付交易。Clover Go 支持两种类型的卡读卡器:磁条、EMV芯片签名卡读卡器(音频插孔)和全功能读卡器(蓝牙),支持挥卡、EMV 插入和NFC 联系式支付。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. 创建开发者账户: 访问 https://sandbox.dev.clover.com/developers/ 上的 Clover 沙盒开发者门户,并创建一个开发者账户。
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与此字段中定义的相同。
本节描述了获取初始化 CloverGoDeviceConfiguration 对象所需的访问令牌的 OAuth 流步骤。
第一步。 使用您的应用程序的 App ID(如上所述第 #3 步)从 POS 应用程序中调用 Clover 授权 URL。此操作将提示用户登录到 Clover 商家账户,一旦成功登录,他们将需要在首次登录时批准应用程序。沙盒环境的授权URL:https://sandbox.dev.clover.com/oauth/authorize?client_id={app_id}&response_type=code
第二步。 用户将被重定向到上面第 4 步中设置的.redirect URL。
第三步。 解析URI数据以获取商户ID、员工ID、客户端ID和代码。
第四步。 在您的后端服务器上制作包括客户端ID(它是应用的ID)、机密和代码的 REST 调用来获取访问令牌。https://sandbox.dev.clover.com/oauth/token?client_id={appId}&client_secret={appSecret}&code={codeUrlParam}
注意 请注意,此项目中的示例应用程序包括为第 4 步提供托管服务。请使用自己此类服务执行此步骤。
第五步。 解析第 4 步的响应并检索访问令牌。访问令牌为 SDK 提供商和员工上下文,所有处理的交易都将在此上下文中。
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
public var cloverConnector:ICloverGoConnector?
public var cloverConnectorListener:CloverGoConnectorListener?
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:提供CardReaderEvent在交易期间的详细信息
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,
等。
SDK初始化所需的参数以下列出
- apiKey - 在注册时提供开发人员
- secret - 在注册时提供开发人员
- accessToken - 在注册时提供开发人员
- allowDuplicateTransaction - 设置为true(仅供Hackathon使用)
- allowAutoConnect - 设置为true(仅供Hackathon使用)
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()
}
所需参数为销售交易
- amount – 您要进行交易的总额
- externalId:此交易的随机唯一编号
其他可选参数在Hackathon中可以忽略
@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
}
所需的参数为授权交易
- amount – 您要进行交易的总额
- externalId:此交易的随机唯一编号
其他可选参数在Hackathon中可以忽略
@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
}
public func onConfirmPaymentRequest(_ request: ConfirmPaymentRequest)
-- 如果设备需要确认付款(重复验证),则调用
处理重复交易的示例代码:如果有重复交易返回,用户将会有一个弹出窗口提示是否继续(例如,两个选项“接受”或“拒绝”)
- 接受 -
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)
}
}
}