OnlinePaymentsSDK 2.1.0

OnlinePaymentsSDK 2.1.0

Worldline维护。



  • Worldline

Online Payments Objective-C SDK

Online Payments Objective-C SDK可以帮助您在iOS应用程序中接收支付,通过Online Payments平台支持iOS 9.0及以上版本。

SDK的主要功能是在iOS应用程序和我们的服务器之间建立安全通道。此通道处理安全凭证,以保证支付过程中客户数据的传输安全。

Online Payments SDK可以帮助您:

  • 处理支付上下文的加密
  • 方便的Objective-C包裹API响应
  • 用户友好的格式化支付数据,例如卡号和到期日期
  • 验证用户输入
  • 确定关联的支付服务提供商

目录

安装


在线支付 Objective-C SDK 可以通过以下软件包管理器获取:CocoaPods 或 Carthage。

CocoaPods

您可以将 Objective-C SDK 添加到项目中,方法是在您的 Podfile 中添加以下内容

$ pod 'OnlinePaymentsSDK'

之后,运行以下命令

$ pod install

Carthage

您可以使用 Carthage 添加 Objective-C SDK,方法是在您的 Cartfile 中添加以下内容

$ github "wl-online-payments-direct/sdk-client-objc"

之后,运行以下命令

$ carthage update --use-xcframeworks

导航到 Carthage/Build 目录,它位于与 .xcodeproj.xcworkspace 同级的目录中。在此目录中,存储了 .xcframework 托管包。将 .xcframework 拖到所需目标的“框架、库和嵌入内容”部分。请确保将其设置为“嵌入并签名”。

示例应用

为了您的方便,我们还提供了一个示例应用,可以用作您自己的实现的依据。如果您对示例应用的外观和感觉满意,您不需要做任何修改。示例应用可以在此处找到。请注意,Objective-C 示例使用了 Swift SDK,因此在示例应用与 Objective-C SDK 一起工作之前,您可能需要进行一些小的调整。

开始使用

要使用SDK接收第一条支付,请完成以下步骤。有关此步骤的详细信息,请参阅支付步骤部分。

  1. 请使用我们的可用服务器SDK之一,请求服务器创建一个客户端会话。将会话详情返回到您的应用程序。
  2. 使用会话详情初始化SDK。
OPSession *session = [OPSession sessionWithClientSessionId:clientSessionId customerId:customerId baseURL:baseURL assetBaseURL:assetsBaseURL appIdentifier:@"objc Example Application/v1.0.0"];
  1. 配置您的支付上下文。
// amount in cents & three letter currency code as defined in ISO 4217
OPPaymentAmountOfMoney *amountOfMoney = [[OPPaymentAmountOfMoney alloc] initWithTotalAmount:1298 currencyCode:@"EUR"];

// two letter country code as defined in ISO 3166-1 alpha-2
OPPaymentContext *paymentContext = [[OPPaymentContext alloc] initWithAmountOfMoney:1298 isRecurring:NO countryCode:@"EUR"];
  1. 检索可用的支付产品。显示OPBasicPaymentItemOPAccountOnFile列表,并请求客户选择一个。
[self.session
    paymentItemsForContext:paymentContext
    groupPaymentProducts:NO
    success:^(OPPaymentItems *paymentItems) {
        // Display the contents of paymentItems & accountsOnFile to your customer
    }
    failure:^(NSError *error) {
        // Inform the customer that something went wrong while retrieving the available Payment Products
    }
];
  1. 一旦客户选择了所需的支付产品,请检索包含客户需要提供以授权支付的信息的丰富OPPaymentProduct。向客户显示所需的信息字段。
[self.session
    paymentProductWithId:@"1"
    context:paymentContext
    success:^(OPPaymentProduct *paymentProduct) {
        // Display the fields to your customer
    }
    failure:^(NSError *error) {
        // Handle failure of retrieving a Payment Product by id
    }
];
  1. OPPaymentRequest中保存客户所需信息字段的数据。
OPPaymentRequest *request = [[OPPaymentRequest alloc] init];

[paymentRequest setValue:@"1245 1254 4575 45" forField:@"cardNumber"];
[paymentRequest setValue:@"123" forField:@"cvv"];
[paymentRequest setValue:@"12/25" forField:@"expiryDate"];
  1. 验证并加密支付请求。加密的顾客数据应随后发送到您的服务器。
[self.session
    preparePaymentRequest:paymentRequest
    success:^(OPPreparedPaymentRequest *preparedPaymentRequest) {
        // Forward the encryptedFields to your server
    }
    failure:^(NSError *error) {
        // Handle failure of encrypting Payment Request
    }
];
  1. 使用服务器API的创建支付调用,请求服务器创建支付请求。在encryptedCustomerInput字段提供加密数据。

类型定义

OPSession

对于与SDK的所有交互,都需要一个OPSession实例。以下代码片段展示了如何初始化OPSession。会话详情是通过使用服务器API执行创建客户端会话调用来获得的。

OPSession *session = [OPSession sessionWithClientSessionId:clientSessionId customerId:customerId baseURL:baseURL assetBaseURL:assetsBaseURL appIdentifier:@"objc Example Application/v1.0.0" loggingEnabled:YES];

OPSession提供的大多数方法都是客户端API的简单封装。它们发送请求并将响应转换为可能包含便利函数的Objective-C对象。

请求和响应的记录

您能够记录对服务器发出的请求和从服务器接收到的响应。默认情况下,记录是禁用的,在产品环境中始终禁用它非常重要。您可以通过两种方式启用记录。一种是在创建会话时设置其值,如上面代码片段所示;另一种是在会话创建之后设置其值。

session.loggingEnabled = YES;

OPPaymentContext

OPPaymentContext是一个包含即将发生的支付上下文/设置的文件对象。它是对于OPSession实例的一些方法的参数所必需的。该对象可以包含以下详细信息

@interface OPPaymentContext

@property (strong, nonatomic) OPPaymentAmountOfMoney *amountOfMoney; // contains the total amount and the ISO 4217 currency code
@property (nonatomic, readonly) BOOL isRecurring; // Set `true` when payment is recurring. Default false.
@property (strong, nonatomic, readonly) NSString *countryCode; // ISO 3166-1 alpha-2 country code
@property (strong, nonatomic) NSString *locale; // IETF Language Tag + ISO 15897, example: 'nl_NL'

OPPaymentItems

此对象包含当前支付的可用支付项。可以使用[会话paymentItemsForContext]函数请求数据。

您将接收到的对象是OPPaymentItems,它包含两个列表。一个用于所有可用的OPBasicPaymentItem,另一个用于所有可用的OPAccountOnFile

下面代码片段展示了如何获取OPPaymentItems实例。

[self.session
    paymentItemsForContext:paymentContext
    groupPaymentProducts:NO
    success:^(OPPaymentItems *paymentItems) {
        // Display the contents of paymentItems & accountsOnFile to your customer
    }
    failure:^(NSError *error) {
        // Inform the customer that something went wrong while retrieving the available Payment Products
    }
];

OPBasicPaymentProduct

该SDK提供了两种类型来表示支付产品的信息:OPBasicPaymentProductOPPaymentProduct。实际上,OPBasicPaymentProduct 实例仅包含显示简单的支付产品列表所必需的信息,客户可以从中选择一个。

OPPaymentProduct 类型包含额外的信息,例如客户必须填写的具体表单字段。此类型通常用于创建要求客户提供其详细信息的表单。有关更多信息,请参阅OPPaymentProduct部分。

以下是一个如何获取Visa产品显示名称和资产的示例。

NSObject<OPBasicPaymentItem> *basicPaymentProduct = [self.paymentItems paymentItemWithIdentifier:@"1"];

NSString *identifier = basicPaymentProduct.identifier; // 1
NSString *label = [basicPaymentProduct.displayHintsList firstObject].label; // VISA
NSString *logoPath = [basicPaymentProduct.displayHintsList firstObject].logoPath; // https://assets.com/path/to/visa/logo.gif

OPAccountOnFile

OPAccountOnFile 实例表示当前客户存储的卡产品的信息。当前支付必须提供的OPAccountOnFile ID必须在服务器API的创建客户端会话调用的请求正文中提供。如果客户希望使用现有的OPAccountOnFile进行支付,所选的OPAccountOnFile应添加到OPPaymentRequest中。以下代码片段显示了如何检索文件中的账户的显示数据。此标签可以与相应的支付产品标志一起显示给客户。

// All available accounts on file for the payment product
 NSArray<OPAccountOnFile *> *allAccountsOnFile = basicPaymentProduct.accountsOnFile.accountsOnFile;

// Get specific account on file for the payment product
OPAccountOnFile *accountOnFile = [basicPaymentProduct accountOnFileWithIdentifier:@"123"];

// Shows a mask based formatted value for the obfuscated cardNumber.
// The mask that is used is defined in the displayHints of this accountOnFile
// If the mask is {{9999}} {{9999}} {{9999}} {{9999}} {{999}}, then the result would be **** **** **** 7412
NSString *maskedValue = [accountOnFile maskedValueForField:@"cardNumber"];

OPPaymentProduct

OPBasicPaymentProduct 仅包含客户区分一个支付产品与另一个产品所需的信息。但是,一旦选择了一个支付产品或文件中的账户,在处理支付之前,客户必须提供额外信息,例如银行账号、信用卡号或到期日。每个支付产品都可以有多个字段需要填写以处理支付。OPBasicPaymentProduct 实例不包含有关这些字段的信息。

支付产品字段的信息由OPPaymentProductField的实例表示,这些实例包含在OPPaymentProduct的实例中。下面将详细介绍OPPaymentProductField类。可以使用OPSession实例来检索OPPaymentProduct的实例,如以下代码片段所示。

[self.session
    paymentProductWithId:@"1"
    context:paymentContext
    success:^(OPPaymentProduct *paymentProduct) {
        // Display the fields to your customer
    }
    failure:^(NSError *error) {
        // Handle failure of retrieving a Payment Product by id
    }
];

OPPaymentProductField

支付产品字段通过OPPaymentProductField的实例表示。每个字段都有一个标识符、一个类型、一个适用于字段值的限制定义,以及如何将字段图形化展示给客户的信息。此外,可以使用字段实例来决定给定值是否适用于该字段。

在下面的代码片段中,从支付产品中检索了标识符为"cvv"的字段。检查字段的限制数据以确定该字段是否为必填字段或可选字段。此外,也检查了字段的显示提示以确定客户提供的值是否应在用户界面中模糊化显示。

OPPaymentProductField *cvvField = [paymentProduct paymentProductFieldWithId:@"cvv"];

BOOL isRequired = cvvField.dataRestrictions.isRequired; // state if value is required for this field
BOOL shouldObfuscate = cvvField.displayHints.obfuscate; // state if field value should be obfuscated

OPPaymentRequest

一旦选择了支付产品并获取了一个OPPaymentProduct实例,就可以构造一个支付请求。此类必须用作存储客户提供的所有值的容器。

OPPaymentRequest *paymentRequest = [[OPPaymentRequest alloc] init];
paymentRequest.paymentProduct = paymentProduct;

Tokenize payment request

OPPaymentProduct有一个名为tokenize的属性,用于指示支付请求是否应存储为文件中的账户。下面的代码片段显示当请求不应作为文件中的账户存储时如何构建支付请求。默认情况下,tokenize设置为false

OPPaymentRequest *paymentRequest = [[OPPaymentRequest alloc] init]; // tokenize is false by default
paymentRequest.paymentProduct = paymentProduct;

// you can set the request's tokenize property after having initialized the paymentRequest
paymentRequest.tokenize = YES;

如果客户选择了一个文件中的账户,构建支付请求时必须同时提供该文件中的账户和相应的支付产品,如下面的代码片段所示。可以从OPBasicPaymentProductOPPaymentProduct实例中检索OPAccountOnFile实例。

OPPaymentRequest *paymentRequest = [[OPPaymentRequest alloc] init]; // accountOnFile is nil by default
paymentRequest.paymentProduct = paymentProduct;

// you can set the request's accountOnFile property after having initialized the paymentRequest
paymentRequest.accountOnFile = accountOnFile;

设置支付请求字段值

一旦配置了支付请求,可以根据以下示例设置支付产品的字段值。如以下示例中的"cardNumber"和"cvv"字段标识符,用于通过支付请求设置字段的值。

[paymentRequest setValue:@"1245 1254 4575 45" forField:@"cardNumber"];
[paymentRequest setValue:@"123" forField:@"cvv"];
[paymentRequest setValue:@"12/25" forField:@"expiryDate"];

验证支付请求

一旦提供所有值,即可验证支付请求。在幕后,验证使用添加到OPPaymentRequest的每个字段的OPDataRestrictions类进行。验证后,可以获取错误列表,表示验证过程中发生的任何问题。如果没有错误,则可以使用您的服务器将加密的支付请求发送到我们的平台。如果存在验证错误,应向客户提供关于这些错误的反馈。

// validate all fields in the payment request
[paymentRequest validate];

// check if the payment request is valid
if (paymentRequest.errors.count == 0) {
    // payment request is valid
} else {
    // payment request has errors
}

验证错误是与OPPaymentProductField链接的OPValidator,并作为值返回,例如

for (OPValidationError *error in paymentRequest.errors) {
    // do something with the error, like displaying it to the user
}

加密支付请求

一旦设置了OPPaymentProduct,提供了并验证了OPPaymentProductField的值,以及可能设置了选定的OPAccountOnFiletokenize属性,OPPaymentRequest即可准备加密。使用[session preparePaymentRequest]进行OPPaymentRequest加密。这会返回一个包含加密支付请求字段和编码客户端元信息的OPPreparedPaymentRequest

[self.session
    preparePaymentRequest:paymentRequest
    success:^(OPPreparedPaymentRequest *preparedPaymentRequest) {
        // Pass the encrypted payment request to your server which should then forward it to the Server API
    }
    failure:^(NSError *error) {
        // Handle failure of encrypting a Payment Request
    }
];

尽管可以使用您自己的加密算法来加密支付请求,但我们建议您使用SDK提供的加密功能。

IINDetails

支付卡号码的前六位数字称为发行者标识号码(IIN)。一旦捕获卡号的前六位数字,您就可以使用[session IINDetailsForPartialCreditCardNumber]调用来检索与提供的IIN关联的支付产品和网络。然后您可以验证卡类型并检查是否可以接受这张卡。

可以使用OPSession类实例来检查与IIN关联的支付产品。这是通过[session IINDetailsForPartialCreditCardNumber]函数完成的。此检查的结果是OPIINDetailsResponse类的一个实例。该类有一个属性status,表示检查的结果,以及一个属性paymentProductId,表示与IIN关联的支付产品。返回的paymentProductId可以用来向客户显示适当的支付产品标志,以便提供视觉反馈。

OPIINDetailsResponse有一个通过OPIINStatus枚举表示的状态属性。OPIINStatus枚举值如下:

  • OPSupported表示IIN关联的支付产品是由我们的平台支持的。
  • OPUnknown表示IIN未被识别。
  • OPNotEnoughDigits表示提供的数字少于六位,无法执行IIN检查。
  • OPExistingButNotAllowed表示提供的IIN被识别,但相应的产品对于当前支付不允许。
[self.session
    IINDetailsForPartialCreditCardNumber:@"123456"
    context:self.context
    success:^(OPIINDetailsResponse *response) {
        // check the status of the associated payment product
        OPIINStatus iinStatus = iinDetailsResponse.status;
    }
    failure:^(NSError *error) {
        // Handle failure of retrieving IIN details
    }
];

有些卡是双品牌卡,可以作为本地卡(具有本地品牌)或国际卡(具有国际品牌)处理。如果您没有设置处理这些本地卡,此API调用将在其响应中不返回该卡类型。

OPStringFormatter

为了根据掩码格式化字段值,SDK提供了OPStringFormatter类。它允许您格式化字段值并在字符串上应用和取消应用掩码。

OPStringFormatter *formatter = [[OPStringFormatter alloc] init];

NSString *mask = @"{{9999}} {{9999}} {{9999}} {{9999}} {{999}}";
NSString *value = @"1234567890123456";

// apply masked value
NSString *maskedValue = [self.formatter formatStringWithString:value mask:mask]; // "1234 5678 9012 3456"

// remove masked value
NSString *unmaskedValue = [self.formatter unformatString:value withMask:mask]; // "1234567890123456"

支付步骤

使用Objective-C SDK设置和完成支付涉及以下步骤

1. 为此支付初始化Objective-C SDK

这需要使用有关会话和客户标识符、连接URL以及支付上下文信息(如货币和总额)的信息。

OPSession *session = [OPSession sessionWithClientSessionId:clientSessionId customerId:customerId baseURL:baseURL assetBaseURL:assetsBaseURL appIdentifier:@"objc Example Application/v1.0.0"];

OPPaymentAmountOfMoney *amountOfMoney = [[OPPaymentAmountOfMoney alloc] initWithTotalAmount:1298 currencyCode:@"EUR"];

OPPaymentContext *paymentContext = [[OPPaymentContext alloc] initWithAmountOfMoney:1298 isRecurring:NO countryCode:@"EUR"];

创建会话的成功响应可以直接用作Session构造函数的输入。

  • clientSessionId / customerId 属性用于身份验证目的。这些可以通过使用我们的可用Server SDK之一从服务器上获取。
  • baseURLassetBaseURL 是SDK应该连接的URL。SDK通过与两种类型的服务器通信来完成其任务。一类服务器提供上述讨论的客户API。另一类服务器存储SDK使用的静态资源,如支付产品的标志。
  • 支付信息(paymentContext)对于构建会话是不需要的,但在请求任何支付产品信息时需要提供。客户可以选择的支付产品取决于提供的支付信息,因此客户端SDK需要这些信息才能完成其任务。需要的支付信息包括
    • 支付的总金额,定义为属性amountOfMoney.totalAmount
    • 应使用的货币,定义为属性amountOfMoney.currencyCodeString
    • 执行支付的人所在的 国家,定义为属性 countryCodeString
    • 支付是一次性支付还是周期性支付

2. 获取支付项目

检索可用于此支付的支付产品和账户信息。应用程序可以使用这些数据来创建支付产品选择屏幕。

[self.session
    paymentItemsForContext:paymentContext
    groupPaymentProducts:NO
    success:^(OPPaymentItems *paymentItems) {
        // Display the contents of paymentItems & accountsOnFile to your customer
    }
    failure:^(NSError *error) {
        // Inform the customer that something went wrong while retrieving the available Payment Products
    }
];

对于某些支付产品,客户可以表明希望在线支付平台存储他们在使用该支付产品时输入的部分数据。例如,对于大多数信用卡支付产品,可以存储持卡人姓名和卡号。存储的数据被称为OPAccountOnFile或令牌。OPAccountOnFile ID 必须包含在服务器 API 的创建客户端会话调用的请求体中。当客户想要使用相同的支付产品进行另一笔支付时,可以为此支付选择存储的账户之一。在这种情况下,客户不需要输入已存储在OPAccountOnFile中的信息。SDK 从客户端 API 收到的可用的支付产品列表也包含每个支付产品的文件账户。您的应用程序可以向客户展示此支付产品及其文件账户列表。

如果客户希望在支付时使用现有的OPAccountOnFile,则应将选定的OPAccountOnFile添加到OPPaymentRequest中。

3. 检索支付产品详情

检索客户基于所选支付产品或文件账户所需提供的所有有关支付产品的详情,包括其字段。您的应用程序可以使用这些信息来创建支付产品详情屏幕。

[self.session
    paymentProductWithId:@"1"
    context:paymentContext 
    success:^(OPPaymentProduct *paymentProduct) {
        // Display the fields to your customer
    }
    failure:^(NSError *error) {
        // Handle failure of retrieving a Payment Product by id
    }
];

当客户已经选择了支付产品或存储的文件账户后,SDK 可以请求客户完成支付所需提供的信息。当一个产品被检索时,SDK 提供了应渲染的所有字段的列表,包括显示提示和验证规则。如果客户选择了文件账户,输入字段中可以预填已在此账户中存储的信息,而不是要求客户重新输入。代表客户存储和预填的数据当然符合适用的法规。例如,对于信用卡交易,客户还必须输入 CVC。客户输入的详情存储在OPPaymentRequest中。再次说明,示例应用程序可以作为创建您的屏幕的起点。如果没有其他需要输入的信息,则可以跳过此屏幕。

4. 加密支付信息

使用[session preparePaymentRequest]OPPaymentRequest中加密所提供的所有支付信息。此函数将返回一个包含加密的支付请求字段和编码的客户端元信息的OPPreparedPaymentRequest。加密字段的结果格式可以由服务器API处理。您需要向SDK提供的是客户在您的屏幕上提供的数据。一旦从[session preparePaymentRequest]函数中检索到OPPreparedPaymentRequest,您的应用程序应将其发送到您的服务器,然后服务器应将其转发到服务器API。

[self.session
    preparePaymentRequest:paymentRequest
    success:^(OPPreparedPaymentRequest *preparedPaymentRequest) {
        // Pass the encrypted payment request to your server which should then forward it to the Server API
    }
    failure:^(NSError *error) {
        // Handle failure of encrypting a Payment Request
    }
];

SDK会为您完成所有繁重的工作,例如从客户端API请求公钥,执行加密并将结果BASE-64编码为一个字符串,您只需要确保的OPPaymentRequest对象包含用户输入的所有信息。

从您的服务器,创建支付请求,在encryptedCustomerInput字段中提供加密数据。

5. 服务器API调用返回

根据服务器API调用的响应,您和您的应用程序需要显示正确的屏幕以供客户查看。在某些情况下,支付尚未完成,因为客户必须重定向到第三方(例如银行或PayPal)进行授权。请参阅服务器API文档了解服务器API可以返回哪些类型的响应。客户端API不参与支付的其他部分。