Frame 4.3.7

Frame 4.3.7

Checkout.com IntegrationCheckout 移动 SDK 团队 维护。



 
依赖项
PhoneNumberKit>= 0
CheckoutEventLoggerKit~> 1.2.4
Checkout= 4.3.7
 

Frame 4.3.7

  • 作者:
  • Checkout.com Integration

Frames iOS

CocoaPods Compatible GitHub release (latest by date) GitHub release (latest by date)

Bitrise Platform license

系统需求

  • iOS 12.0+
  • Xcode 12.4+
  • Swift 5.3+

 

文档

Frames for iOS 对消费者数据进行令牌化,以便在 Checkout.com 的支付基础设施中使用。我们希望将移动应用程序中的支付操作和构建支付屏幕的所有复杂性抽象化,让您能够专注于您的核心业务。

  • 集成: 如何在您的 iOS 应用程序中消费我们的 SDK 的指南

  • 示例项目: 我们在测试每种提供的分发方式时,创建了一些项目来展示 SDK 中的功能范围

  • 开始使用: 通过开始在您的应用程序界面中呈现测试您可以实现的效果

  • 定制: 自定义 UI,使其成为您应用程序的一部分

  • 其他功能我们如何帮助解决 Apple Pay 和 3D Secure 难题

  • 迁移如果您之前使用过 3.5.x 版本

  • 许可协议

完整信息可以在 Checkout 文档 中找到。

您可以在我们的 Jazzy 文档中找到 Frames API 参考 此处

 

集成

我们已尽力支持 iOS 上的最常见分发方法。我们强烈支持 SPM(Swift 包管理器),但如果由于任何原因此方法不适合您,我们还支持 CocoapodsCarthage

Swift 包管理器

Swift 包管理器与 Swift 构建系统集成,以自动化依赖项的下载、编译和链接过程。自 Xcode 11 开始,它应该可以在最新的 Xcode 项目中直接使用,并得到了社区的大力支持,近年来采用率大幅上升。这使得它成为我们首选的分发方法,同时也是最易于集成、保持更新和构建的方法。

如果您从未使用过它,请从 Apple 的逐步指南开始使用 将包依赖项添加到您的应用程序中,我们将在短时间内提高您项目的效能!只需在添加依赖项时使用此存储库的 URL(https://github.com/checkout/frames-ios)即可。

CocoaPods

CocoaPods 是传统苹果项目的依赖项管理器。我们仍然支持它,但并不总是能够验证其特殊的方式。

请确保您的机器上已安装 Cocoapods,方法是在命令行中运行

$ pod --version

任何高于 1.10.0 版本的都是好兆头。如果未安装或不受支持,请按照 Cocoapods 入门指南 操作。

如果您的机器上已安装了有效版本的CocoaPods,要将Frameworks集成到您的Xcode项目中,请更新您的Podfile

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '12.0'
use_frameworks!

# PhoneNumberKit has stopped publishing Cocoapods releases to Public Registry
# This workaround enables application to get the releases straight from source repository 
pod 'PhoneNumberKit', :git => 'https://github.com/marmelroy/PhoneNumberKit'

target '<Your Target Name>' do
    pod 'Frames', '~> 4'
end

然后,在终端中运行以下命令:

$ pod install

要更新您现有的CocoaPods依赖项,请使用

$ pod update

Carthage

Carthage 是一个去中心化的依赖项管理器,它构建您的依赖项并提供给您的二进制框架。

如果您还没有安装,请安装Carthage

要使用Carthage将Frameworks集成到您的Xcode项目中,在您的Cartfile中指定它。

github "checkout/frames-ios" ~> 4.0

运行carthage update --use-xcframeworks以构建框架,并将构建的Frames拖入您的Xcode项目中。

 

演示项目

我们已经与产品设计和设计团队合作创建了简单的演示应用程序,展示我们的SDK。您可以直接克隆存储库(无论是通过git直接访问还是使用建议的集成方法),并在本地运行这些应用程序。

我们的演示应用程序还测试了支持的集成方法(SPM、CocoaPods、Carthage),因此如果在这方面有任何问题,它们应该提供有效的示例。您可以在存储库根目录下 respective 文件夹中找到它们。

  • iOS 示例框架(使用 CocoaPods 分发)
  • iOS 示例框架 SPM(SPM 分发)
  • iOS 示例框架 Carthage(Carthage 分发)

启动后,您将看到一个带有多种设计选项的主屏幕。我们试图使它们具有强烈的对比,以便向您的UI/UX团队成员展示可以实现的效果。我们还尽量以最简单的方式编写代码,以跟踪和理解如何创建每个UI风格。请从HomeViewController.swift开始,并根据代码(@IBAction)中的按钮操作获取一些关于我们如何实现那些UI的示例。

 

开始使用

如果您到达这里,我们将假设您已完成集成或只是好奇。如果不是,请先完成集成

1. 导入 Frames

如果不确定在哪里进行,将要呈现旅行的 ViewController 是一个不错的开始

import Frames

 

2. 准备负责 Frames 配置的对象

这是逻辑配置

  • 确保您可以获得请求的访问权限
  • 使我们能够在输入阶段预先验证支持的方案
  • 预先填写用户信息(可选,但如果能提供的话,可能会极大地提升用户体验)
/** 
    This is optional and can use nil instead of this property. 
    But if you can provide these details for your user you can
        - make their checkout experience easier by prefilling fields they may need to do
        - improve acceptance success for card tokenisation
*/
let country = Country(iso3166Alpha2: "GB")
let address = Address(
    addressLine1: "221B Baker Street",
    addressLine2: "Marylebone",
    city: "London",
    state: "London",
    zip: "NW1 6XE",
    country: country)
let phone = Phone(number: "+44 2072243688",
    country: country)
let billingFormData = BillingForm(
    name: "Amazing Customer",
    address: address,
    phone: phone)

let configuration = PaymentFormConfiguration(
    apiKey: "<Your Public Key>",
    environment: .sandbox,
    supportedSchemes: [.visa, .maestro, .mastercard],
    billingFormData: billingFormData)

 

3. 准备 UI 的样式

我们将在后来介绍 Make it your own,现在我们使用默认样式

// Style applied on Card input screen (Payment Form)
let paymentFormStyle = DefaultPaymentFormStyle()

// Style applied on Billing input screen (Billing Form)
let billingFormStyle = DefaultBillingFormStyle()

// Frames Style
let style = PaymentStyle(
    paymentFormStyle: paymentFormStyle,
    billingFormStyle: billingFormStyle)

 

4. 准备流程完成的响应

如果用户完成流程而未取消,将会调用完成处理程序,如果成功,则带有卡片令牌;如果失败,则带有错误

let completion: ((Result<TokenDetails, TokenRequestError>) -> Void) = { result in
    switch result {
    case .failure(let failure):
        if failure == .userCancelled {
            // Depending on needs, User Cancelled can be handled as an individual failure to complete, an error, or simply a callback that control is returned
            print("User has cancelled")
        } else {
            print("Failed, received error", failure.localizedDescription)
        }
    case .success(let tokenDetails):
        print("Success, received token", tokenDetails.token)
    }
}

 

5. 使用我们的 PaymentFormFactory 生成 ViewController

使用第 2、3 和 4 步的属性,我们现在来创建 ViewController

let framesViewController = PaymentFormFactory.buildViewController(
    configuration: configuration, // Step 2
    style: style,                 // Step 3
    completionHandler: completion // Step 4
)

 

6. 向用户展示 ViewController

我们现在已经创建了所需的 ViewController,以启用用户的全功能令牌化。让我们来展示它。

/** 
    We are assuming you started the Walkthrough from the presenting ViewController 
        and that a Navigation Controller is available
    
    You will need to make minor adjustments otherwise. 
    
    For the best experience we recommend embedding the presenting ViewController inside an UINavigationController
*/
navigationController?.pushViewController(framesViewController, animated: true)

 

自定义样式

!!! 任何自定义都必须在创建 ViewController 之前完成。一旦将样式提交给工厂,对它的任何更改将不会反映在 UI 中 !!!

我们一直在努力提供多种方式来为您打造个性化界面。按照复杂度的顺序,我们首先从

修改默认样式

在我们的 入门 示例中,我们使用了默认样式来快速实现功能。如果您的大部分需求都是这样,那么您将很高兴地知道每个组件都是可变的,您应该能够轻松地自定义单个属性。这也在我们 Factory.swift 中的演示项目中作为示例使用,在 getDefaultPaymentViewController 方法中。

示例

var paymentFormStyle = DefaultPaymentFormStyle()

// Change background of page
paymentFormStyle.backgroundColor = UIColor.darkGray

// Change card number input placeholder value
paymentFormStyle.expiryDate.textfield.placeholder = "00 / 00"

// Add custom border style around the Payment Button
if var payButton = paymentFormStyle.payButton as? DefaultPayButtonFormStyle {
  let payButtonBorder = DefaultBorderStyle(
      cornerRadius: 26,
      borderWidth: 3,
      normalColor: .black,
      focusColor: .clear,
      errorColor: .red,
      corners: [.bottomLeft, .topRight])
  payButton.borderStyle = payButtonBorder
  paymentFormStyle.payButton = payButton
}

// Change Payment button text
paymentFormStyle.payButton.text = "Pay £54.63"

如果您需要覆盖许多值,我们不建议使用这种方法,因为您需要逐个识别并更改每个属性。但对于小幅调整,它仍然可行。

使用主题

在我们的演示项目中,我们还在 ThemeDemo.swift 中展示了这种方法。通过主题,我们旨在为您提供一个设计系统,您可以使用它通过提供少量属性来创建完整的UI样式,我们将这些属性共享到子组件中。由于您可能对我们映射方案不完全认同,您仍然可以在之后逐个更改每个组件(如修改默认示例所示)。

// Declare the theme object with the minimum required properties
var theme = Theme(
    primaryFontColor: UIColor(red: 0 / 255, green: 204 / 255, blue: 45 / 255, alpha: 1),
    secondaryFontColor: UIColor(red: 177 / 255, green: 177 / 255, blue: 177 / 255, alpha: 1),
    buttonFontColor: .green,
    errorFontColor: .red,
    backgroundColor: UIColor(red: 23 / 255, green: 32 / 255, blue: 30 / 255, alpha: 1),
    errorBorderColor: .red)

// Add border and corner radius around text inputs
theme.textInputBackgroundColor = UIColor(red: 36 / 255.0, green: 48 / 255.0, blue: 45 / 255.0, alpha: 1.0)
theme.textInputBorderRadius = 4

// Build complete payment form by providing only texts
var paymentFormStyle = theme.buildPaymentForm(
    headerView: theme.buildPaymentHeader(title: "Payment details",
                                        subtitle: "Accepting your favourite payment methods"),
    addBillingButton: theme.buildAddBillingSectionButton(text: "Add billing details",
                                                        isBillingAddressMandatory: false,
                                                        titleText: "Billing details"),
    billingSummary: theme.buildBillingSummary(buttonText: "Change billing details",
                                            titleText: "Billing details"),
    cardNumber: theme.buildPaymentInput(isTextFieldNumericInput: true,
                                        titleText: "Card number",
                                        errorText: "Please enter valid card number"),
    expiryDate: theme.buildPaymentInput(textFieldPlaceholder: "__ / __",
                                        isTextFieldNumericInput: false,
                                        titleText: "Expiry date",
                                        errorText: "Please enter valid expiry date"),
    securityCode: theme.buildPaymentInput(isTextFieldNumericInput: true,
                                        titleText: "CVV date",
                                        errorText: "Please enter valid security code"),
    payButton: theme.buildPayButton(text: "Pay now"))

// Override a custom property from the resulting payment form style
paymentFormStyle.payButton.disabledTextColor = UIColor.lightGray

let billingFormStyle = theme.buildBillingForm(
            header: theme.buildBillingHeader(title: "Billing information",
                                             cancelButtonTitle: "Cancel",
                                             doneButtonTitle: "Done"),
            cells: [.fullName(theme.buildBillingInput(text: "", isNumericInput: false, isMandatory: false, title: "Your name")),
                    .addressLine1(theme.buildBillingInput(text: "", isNumericInput: false, isMandatory: true, title: "Address")),
                    .city(theme.buildBillingInput(text: "", isNumericInput: false, isMandatory: true, title: "City")),
                    .country(theme.buildBillingCountryInput(buttonText: "Select your country", title: "Country")),
                    .phoneNumber(theme.buildBillingInput(text: "", isNumericInput: true, isMandatory: true, title: "Phone number"))])

我们认为这种方法在UI控制良好和简单简洁的代码之间实现了良好的平衡。字体大小甚至使用 preferredFont(forTextStyle: ...).pointSize 以提供与用户设备偏好相匹配的字体大小。然而,如果您仍然发现映射需要过度的定制,我们的最终方法可能更合您的心意。

声明所有组件

这绝不是一种简单的方法,但却是完全自定义每个属性并发现定制全面程度的方法。您将在演示项目中发现 Style.swiftCustomStyle1.swift 文件,它们遵循这种方法。

如果您决定这样做,请尝试

  • 使用编译器帮助。Xcode 的自动完成可以帮助您从最高级别导航到最低的定制选项
let style = PaymentStyle(paymentFormStyle: <#T##PaymentFormStyle#>,
                        billingFormStyle: <#T##BillingFormStyle#>)
  • 协议是关键词。从上面的代码开始,参数将是协议对象,直到最低级别。
// You will need to prepare your objects that conform to the required protocols
struct MyPaymentFormStyle: PaymentFormStyle {
    var backgroundColor: UIColor = ...
    var headerView: PaymentHeaderCellStyle = ...
    var editBillingSummary: BillingSummaryViewStyle? = ...
    var addBillingSummary: CellButtonStyle? = ...
    var cardholderInput: CellTextFieldStyle? = ...
    var cardNumber: CellTextFieldStyle = ...
    var expiryDate: CellTextFieldStyle = ...
    var securityCode: CellTextFieldStyle? = ...
    var payButton: ElementButtonStyle = ...
}

// Then feed them to your end PaymentStyle
let style = PaymentStyle(paymentFormStyle: MyPaymentFormStyle(),
                        billingFormStyle: <#T##BillingFormStyle#>)

 

其他功能

处理3D Secure

当您从服务器发送3D Secure充电请求时,您将收到一个3D Secure URL。这可以在JSON响应中的_links.redirect.href找到。然后您可以将3D Secure URL传递给ThreedsWebViewController以处理验证。

重定向URL(success_urlfailure_url)在Checkout.com Hub中设置,但可以从您服务器发送的充电请求中覆盖。提供正确的URL对于确保成功的支付流程非常重要。

让我们假设我们现在在YourViewController.swift内部工作,并且我们正在处理3DS挑战

// Ensure you know the fail & success URLs
private enum Constants {
    static let successURL = URL(string: "http://example.com/success")!
    static let failureURL = URL(string: "http://example.com/failure")
}

// Prepare the service
let checkoutAPIService = CheckoutAPIService(publicKey: "<Your Public Key>", environment: .sandbox)

// Create the ThreedsWebViewController
let threeDSWebViewController = ThreedsWebViewController(
    checkoutAPIService: checkoutAPIService,
    // If the payment response provided new success_url or failure_url, use those. Otherwise default to Checkout provided values as documented previously
    successUrl: serverOverridenSuccessURL ?? Constants.successURL,
    failUrl: serverOverridenFailureURL ?? Constants.failureURL)
threeDSWebViewController.delegate = self
threeDSWebViewController.authURL = challengeURL // This is coming from the payment response

// Present threeDSWebViewController
present(threeDSWebViewController, animated: true, completion: nil)

之前我们已经添加了这一行:threeDSWebViewController.delegate = self。这将引发编译器错误,因为我们现在需要让YourViewController符合所需的协议。这样做,我们能够找到挑战的结果,并相应地反应。

extension YourViewController: ThreedsWebViewControllerDelegate {
    func threeDSWebViewControllerAuthenticationDidSucceed(_ threeDSWebViewController: ThreedsWebViewController, token: String?) {
        
        // Congratulations, the Challenge was successful !

        threeDSWebViewController.dismiss(animated: true, completion: nil)
    }

    func threeDSWebViewControllerAuthenticationDidFail(_ threeDSWebViewController: ThreedsWebViewController) {
        
        // Oooops, the payment failed !
        
        threeDSWebViewController.dismiss(animated: true, completion: nil)
    }
}

使用Apple Pay

我们可以处理来自Apple Pay的PKPayment令牌数据。

// Prepare the service
let checkoutAPIService = CheckoutAPIService(publicKey: "<Your Public Key>", environment: .sandbox)

func handle(payment: PKPayment) {
    // Get the data containing the encrypted payment information.
    let paymentData = payment.token.paymentData

    // Request an Apple Pay token.
    checkoutAPIService.createToken(.applePay(ApplePay(paymentData))) { result in
        switch result {
        case .success(let tokenDetails):
            // Congratulations, payment token is available
        case .failure(let error):
            // Ooooops, an error ocurred. Check `error.localizedDescription` for hint to what went wrong
        }
    }
}

电话号码验证

账单地址电话号码验证将使用设备本地设置电话号码的前缀。例如,英国电话号码将自动前缀为+44。

如果用户想要输入不同于设备本地的电话号码(即当设备本地设置为英国时输入美国电话号码),则应在输入电话号码时首先提供国家代码(例如,+1)。

 

迁移

3DS和Apple Pay处理不受影响,因此应该仍按相同方式工作。

如果您使用的是v4之前的Frames iOS版本(我们强烈建议使用最新版本),此更新将带来破坏性的变化,需要一点开发时间。

由于我们努力大幅改善Frames的用户界面并允许您进行高度自定义,所需的方法也非常不同。这需要您

  • 从您的代码库中移除旧版Frames的使用。这可能是一次移除屏幕以及其他仅为了支持旧版Frames集成而创建的对象的机会!
  • 开始行动

我们要指出,我们认为v4+版带给我们的SDK的巨大好处,比如

  • 可定制的UI,专注于使用户能够无缝过渡到支付流程
  • 更新和改进的验证逻辑,与我们的支持卡支付方法一致
  • 使用我们的更新UI为您的客户提供额外安全优势

 

许可

Frames iOS采用MIT许可发布。有关详细信息,请参阅LICENSE