Antom, leading provider of tailored payment solutions

快捷支付(iOS)

注意:本文档已停止维护并下线归档,请访问 https://docs.antom.com/ 获取最新内容。

本文为您介绍支持从桌面浏览器或移动浏览器接收付款的集成解决方案。集成后,您可以接入数字钱包、银行卡和银行转账等多种支付方式。

用户体验

以下图片分别展示了钱包和银行转账的用户体验。在首次支付时,买家可以启用免密支付,这样后续支付无需再输入支付密码。后续支付的全流程都将在您的网站或应用上进行。

钱包

当使用钱包付款时,整个支付流程会保留在您的网站或应用程序内,买家可以在首次付款时启用免密支付,后续付款无需再输入支付密码。

首次使用钱包支付

在首次支付时,买家完成支付授权流程以确保后续免密支付。

1.png

银行转账

对于银行转账支付方式,以下图表展示了首次支付和后续支付的用户体验。

首次使用银行转账支付

在首次支付时,用户需要输入支付密码和验证码。

4.png

支付流程

首次支付

当买家选择 Antom 提供的支付方式时,您需要采集支付请求 ID、订单金额、支付方式、订单详情、支付重定向链接和支付结果通知链接等必要信息。然后调用 支付会话创建(快捷支付)接口来下单,并调用 Antom SDK 中的相关方法完成支付流程。

流程图1中文.png

  1. 买家进入结账页面
  2. 创建支付会话请求
    在买家选择支付方式并提交订单后,您可以通过调用 支付会话创建(快捷支付)接口来获取支付会话。
  3. 调用客户端 SDK
    在客户端通过支付会话调用 SDK。SDK 会基于支付方式的特点收集支付要素、展示代码信息、进行重定向、调用,并引导买家完成支付。
  4. 获取授权结果
  1. 获取支付结果
    通过以下两种方法获取支付结果:

集成步骤

按照以下步骤开始集成:

  1. 创建支付会话
  2. 调用 SDK
  3. 获取授权或支付结果

步骤 1:创建支付会话 服务端

当买家选择由 Antom 提供的支付方式时,您需要收集支付请求 ID、订单金额、支付方式、订单描述、支付重定向页面链接和支付结果通知链接等必要信息。随后,通过以下步骤调用 支付会话创建(快捷支付)接口来创建支付会话:

  1. 安装接口库
  2. 初始化请求实例
  3. 调用 支付会话创建(快捷支付)接口

注意:Antom 提供多种语言的服务器端接口库。以下代码以 Java 为例,需要安装 Java 6 或更高版本。

安装接口库

您可以在 GitHub 上找到最新版本。

<dependency>
    <groupId>com.alipay.global.sdk</groupId>
    <artifactId>global-open-sdk-java</artifactId>
    <version>2.0.44</version>
</dependency>

初始化请求实例

创建一个单例资源以向 Antom 发起请求。

import com.alipay.global.api.AlipayClient;
import com.alipay.global.api.DefaultAlipayClient;
import com.alipay.global.api.model.constants.EndPointConstants;

public class Sample {
    public static final String        CLIENT_ID            = "";
    public static final String        ANTOM_PUBLIC_KEY     = "";
    public static final String        MERCHANT_PRIVATE_KEY = "";

    private final static AlipayClient CLIENT               = new DefaultAlipayClient(
            EndPointConstants.SG, MERCHANT_PRIVATE_KEY, ANTOM_PUBLIC_KEY, CLIENT_ID);

}

创建支付会话

首次支付

调用 支付会话创建(快捷支付)接口指定以下参数来创建支付会话:

参数

是否必需

说明

paymentRedirectUrl

✅

支付完成后,买家将被重定向至的商家页面链接。

authState

✅

您用于发起授权而分配的专属 ID,在后续免密支付中获取令牌。该参数仅在首次支付时传递,后续支付无需传递此参数。

paymentNotifyUrl

✅

支付结果通知地址。这个地址必须是 HTTPS。

paymentSessionExpiryTime

支付会话超时。默认为 1 小时,可以设置在 1 小时内。该值的格式遵循 ISO 8601 标准。例如,2019-11-27T12:01:01+08:00。

userLoginId

买家支付方式的登录账户,可能是买家的邮箱地址或者手机号码。

order.buyer: referenceBuyerId/buyerPhoneNo/buyerEmail

传递买家信息以供风险决策。传递 referenceBuyerId、buyerPhoneNo、buyerEmail 其中一个参数即可。

以上参数并非完整参数,请参阅 支付会话创建(快捷支付)接口以获取完整参数列表以及特定支付方式的额外要求。

以下示例代码展示如何调用 支付会话创建(快捷支付)接口:

public static void createPaymentSession() {
    AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
    alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
    alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);

    // replace with your paymentRequestId
    String paymentRequestId = UUID.randomUUID().toString();
    alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);

    // set amount
    // you should convert amount unit(in practice, amount should be calculated on your serverside)
    Amount amount = Amount.builder().currency("HKD").value("98080").build();
    alipayPaymentSessionRequest.setPaymentAmount(amount);

    //set settlement currency
    SettlementStrategy settlementStrategy = new SettlementStrategy();
    settlementStrategy.setSettlementCurrency("USD");
    alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);

    // set paymentMethod
    PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("ALIPAY_HK").build();
    alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);

    // set agreementInfo
    // replace with your authState
    String authState = UUID.randomUUID().toString();
    // The login ID that the user used to register in the payment method client. The login ID can be the user's email address or phone number.
    // Specify this parameter to free users from manually entering their login IDs.
    String userLoginId = "852-91234567";
    AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).userLoginId(userLoginId).build();
    alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);

    // set buyer info
    Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();

    // replace with your orderId
    String orderId = UUID.randomUUID().toString();
    // set order Info
    Order order = Order.builder().referenceOrderId(orderId).
            orderDescription("antom api testing order").orderAmount(amount).buyer(buyer).build();
    alipayPaymentSessionRequest.setOrder(order);

    // replace with your notify url
    alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");

    // replace with your redirect url
    alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");

    AlipayPaymentSessionResponse alipayPaymentSessionResponse;
    try {
        alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
    } catch (AlipayApiException e) {
        String errorMsg = e.getMessage();
        // handle error condition
    }
}

以下代码是请求报文的示例:

{
    "agreementInfo": {
        "authState": "2b7a4a24-b909-4633-8ffe-8ed3648e99b4",
        "userLoginId": "852-91234567"
    },
    "order": {
        "buyer": {
            "referenceBuyerId": "yourBuyerId"
        },
        "orderAmount": {
            "currency": "HKD",
            "value": "98080"
        },
        "orderDescription": "antom api testing order",
        "referenceOrderId": "1a57b8cd-9a25-4d44-94f7-3467a4ebe532"
    },
    "paymentAmount": {
        "currency": "HKD",
        "value": "98080"
    },
    "paymentMethod": {
        "paymentMethodType": "ALIPAY_HK"
    },
    "paymentNotifyUrl": "http://www.yourNotifyUrl.com",
    "paymentRedirectUrl": "http://www.yourRedirectUrl.com",
    "paymentRequestId": "bc93d19e-e1f6-4b68-b6b1-3d6ddc2a792a",
    "productCode": "AGREEMENT_PAYMENT",
    "productScene": "EASY_PAY",
    "settlementStrategy": {
        "settlementCurrency": "USD"
    }
}

以下代码是包含了以下参数的响应示例:

  • paymentSessionData:需要转发给您客户端的支付会话数据。
  • paymentSessionExpiryTime:支付会话的过期时间。
{
    "paymentSessionData": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3cjK3CVpnMXY7BfQlIvwNqQWtXHEMUo0R5pQwnSyNtxTA==&&SG&&188&&eyJh***",
    "paymentSessionExpiryTime": "2024-09-27T15:57:30+08:00",
    "paymentSessionId": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3fI21eGbgq240lFVquZsLrM",
    "result": {
        "resultCode": "SUCCESS",
        "resultMessage": "success.",
        "resultStatus": "S"
    }
}

常见问题

问:请求参数的值可以使用中文字符吗?

答:为避免某些支付方式的不兼容,不要在请求的字段中使用中文字符。

问:如何设置接收支付通知的链接?

答:在 支付会话创建(快捷支付)接口中指定参数 paymentNotifyUrl,以接收支付结果的异步通知(支付通知),或者在 Antom Dashboard 中配置接收链接。如果请求和 Antom Dashboard 中都指定了链接,请求中指定的值优先。

步骤 2:创建并调用 SDK 客户端

安装

版本要求:

  • 安装 Xcode 12 或更高版本。
  • 使用 iOS 11 或更高版本。

注意:暂不支持 ‌Flutter 和 React Native(RN)开发框架。

请查阅 iOS 端集成 SDK 资源包文档来集成 SDK 资源包。

初始化客户端 SDK

创建 SDK 实例并指定基本配置。创建一个 AMSEasyPayConfiguration 对象包括以下参数:

参数

是否必需

说明

locale

否

用于指定语言信息。根据支付方式的地区选择合适的值。此参数的有效值如下所示,如果使用了以下列表中未列出的值,将使用本地语言代替。

  • en_US:英语
  • in_ID:印尼语
  • ms_MY:马来语
  • tl_PH:菲律宾语
  • ko_KR:韩语
  • zh_CN:简体中文
  • zh_HK:繁体中文

options

否

用于指定是否使用默认加载模式和沙箱环境。有效值包括:

  • "sandbox", "true":沙箱环境
  • "sandbox", "false":生产环境
  • "showLoading", "true":使用默认加载模式。
  • "showLoading", "false":不使用默认加载模式。

实现 AMSPaymentProtocol ,用于处理后续流程中的相应事件。它包含以下方法:

方法

是否必需

说明

onEventCallback

否

一个回调函数,用于监听结账页面的支付事件,返回 eventCode 和 eventResult 。

实现 AMSLoggerProtocol ,用于管理日志输出。它包含以下方法:

方法

是否必需

说明

logWithName

否

默认的日志输出回调函数。

以下示例代码展示了如何实例化 SDK:

#import <AMSComponent/AMSComponent-Swift.h>

AMSEasyPayConfiguration *componentConfig = [AMSEasyPayConfiguration new];
componentConfig.locale = @"en_US";
// Specify showLoading as true (default value) to use the default loading pattern. Specify it as false to customize the loading animation based on onEventCallback.
// Set the sandbox environment. If you leave it empty, the production environment is used by default.
NSDictionary *options = @{@"showLoading": @"true", @"sandbox": @"true"};
componentConfig.options = options;

[[AMSEasyPay shared] initConfiguration:componentConfig];

// Set the callback to monitor payment events on the checkout page.
[AMSEasyPay shared].paymentDelegate = self;
[AMSEasyPay shared].loggerDelegate = self;

// The server calls the createPaymentSession API to obtain paymentSessionData.

调用 SDK

调用 createComponent 方法:

参数

是否必需

说明

sessionData

是

使用 sessionData 参数创建配置对象:将 支付会话创建(快捷支付)接口响应中的 paymentSessionData 完整数据作为此参数的值。

在以下情况调用 onDestroy 释放 SDK 组件资源:

以下示例代码展示了如何调用 SDK:

[[AMSEasyPay shared] createComponent:sessionData];

// 回收组件资源
[[AMSEasyPay shared] onDestroy];

步骤 3:获取授权结果或支付结果 服务端

对于首次支付,您可以获取授权和支付结果,而对于后续支付,仅提供支付结果。

您可以通过以下方法之一获取授权或支付结果:

  • 接收异步通知
  • 查询结果

接收异步通知

获取授权结果

授权成功后, Antom 会通过 授权结果通知 接口给您发送异步通知。当您收到通知,您需要按照返回收到确认信息返回响应。同时,您必须在系统中更新买家的授权状态,并在您的授权管理页面上显示从通知中获取的买家无敏感信息账户。

以下代码是通知请求的示例:

{
    "accessToken": "28288803001319861727421828000Cv96OFlYoi17100****",
    "accessTokenExpiryTime": 2145916817000,
    "authState": "36a38e87-0453-495e-ad17-b46553b918da",
    "authorizationNotifyType": "TOKEN_CREATED",
    "userLoginId": "852-91****67",
    "result": {
        "resultCode": "SUCCESS",
        "resultMessage": "success.",
        "resultStatus": "S"
    }
}

如何验证通知的签名并对此作出响应,请参阅签名与验签。

常见问题

问:支付结果通知何时发送?

答:这取决于支付是否完成:

  • 如果支付成功完成,Antom 通常会在 3 到 5 秒内发送异步通知。对于像 OTC 这样的支付方式,通知可能会稍有延迟。
  • 如果支付未完成,Antom 需要先关闭订单,然后发送异步通知。不同支付方式关闭订单所需的时间会有所不同,通常默认为 14 分钟。

问:异步通知会被重新发送吗?

答:是的,对于以下情况,异步通知将在 24 小时内自动重新发送:

  • 如果由于网络原因没有收到异步通知;
  • 如果您收到 Antom 的异步通知,但您没有按照处理通知的示例代码格式进行响应。

通知可以重发最多 8 次,或者直到收到正确的响应以终止传递。发送间隔如下:0 分钟,2 分钟,10 分钟,10 分钟,1 小时,2 小时,6 小时,15 小时。

问:在响应异步通知时,我需要添加数字签名吗?

答:如果您收到 Antom 的异步通知,您需要按照处理通知的示例代码格式返回响应,但不需要对响应进行签名。

问:在支付结果通知中,我需要使用哪些关键参数?

答:请注意以下关键参数:

  • result:表示订单的支付结果。
  • paymentRequestId:用于咨询、取消和对账的支付请求 ID。
  • paymentId:由 Antom 生成的支付订单 ID,用于退款和对账。
  • paymentAmount:表示支付金额。

问:授权结果通知中我需要使用哪些关键参数?

答:请注意以下关键参数:

  • result:表示订单的支付结果。
  • authState:由商户生成的资产绑定请求 ID。
  • accessToken:由 Antom 生成的代扣 ID,用于后续支付。
  • userLoginId:用户的无敏感信息账户 ID。

支付结果查询

您可以调用 支付结果查询 接口来发起对订单结果的查询。

参数

是否必需

说明

paymentRequestId

否

由您生成的支付请求 ID。

以上参数并非完整参数,请参考 支付结果查询 接口以获取完整参数集以及特定支付方式的额外要求。

以下示例代码展示了如何调用 支付结果查询 接口:

public static void inquiryPayment() {
    AlipayPayQueryRequest alipayPayQueryRequest = new AlipayPayQueryRequest();

    // replace with your paymentRequestId
    alipayPayQueryRequest.setPaymentRequestId("yourPaymentRequestId");

    AlipayPayQueryResponse alipayPayQueryResponse = null;
    try {
        alipayPayQueryResponse = CLIENT.execute(alipayPayQueryRequest);
    } catch (AlipayApiException e) {
        String errorMsg = e.getMessage();
        // handle error condition
    }
}

以下是请求报文的示例:

{
  "paymentRequestId": "bc93d19e-e1f6-4b68-b6b1-3d6ddc2a792a"
}

以下是响应报文的示例:

{
    "cardInfo": {},
    "paymentResultCode": "SUCCESS",
    "paymentRequestId": "bc93d19e-e1f6-4b68-b6b1-3d6ddc2a792a",
    "paymentResultInfo": {},
    "paymentAmount": {
        "currency": "HKD",
        "value": "98080"
    },
    "result": {
        "resultStatus": "S",
        "resultCode": "SUCCESS",
        "resultMessage": "success."
    },
    "actualPaymentAmount": {
        "currency": "HKD",
        "value": "98080"
    },
    "paymentId": "202409271940108001001881E0211235544",
    "paymentResultMessage": "success",
    "pspCustomerInfo": {
        "pspName": "ALIPAY_HK"
    },
    "paymentTime": "2024-09-27T00:23:46-07:00",
    "customsDeclarationAmount": {},
    "paymentStatus": "SUCCESS"
}

常见问题

问:我应该多久调用一次 支付结果查询 接口?

答:以 2 秒为间隔持续调用 支付结果查询 接口,直到获取最终的支付结果或收到异步支付结果通知。

问:我在通知中需要使用哪些关键参数?

答:请注意这些关键参数:

  • result:表示此 支付结果查询 接口调用的结果,需要根据 paymentStatus 来判断订单状态:
    • SUCCESS 和 FAIL 表示最终结果;
    • PROCESSING 表示处理中。
  • paymentAmount:表示支付的金额。

示例代码

使用客户端 SDK 的完整示例代码:

#import <AMSComponent/AMSComponent-Swift.h>

// 步骤一:创建AMSEasyPayConfiguration类
AMSEasyPayConfiguration *componentConfig = [AMSEasyPayConfiguration new];
componentConfig.locale = @"en_US";

// 设置showLoading参数为true(默认值)时使用内部loading页面,false时商户可通过onEventCallback中的事件自定义loading动画
// 设置沙箱环境,不设置为线上正式环境
NSDictionary *options = @{@"showLoading": @"true", @"sandbox": @"true"};
componentConfig.options = options;

[[AMSEasyPay shared] initConfiguration:componentConfig];

// 设置收银台回调监听
[AMSEasyPay shared].paymentDelegate = self;
[AMSEasyPay shared].loggerDelegate = self;

// 步骤二:服务端调用支付会话创建接口,获取paymentSessionData


// 步骤三:创建渲染卡组件
[[AMSEasyPay shared] createComponent:paymentSessionData];

#pragma AMSPaymentProtocol
- (void)onEventCallback:(NSString *)eventCode eventResult:(AMSEventResult *)eventResult
{
    NSLog(@"eventCode%@ eventResult%@", eventCode, eventResult);
}

#pragma AMSLogProtocol
- (void)logWithName:(NSString *)name parameter:(NSDictionary<NSString *,id> *)parameter
{
    NSLog(@"name%@ parameter%@", name, parameter);
}

事件码

您可能会看到两种类型的事件码:

  • 状态码:在组件运行生命周期内,通过 onEventCallback 回调函数返回。
  • 错误码:在组件初始化阶段,通过 onEventCallback 或 onError 回调函数返回。

类型

代码

说明

后续操作

状态码

SDK_START_OF_LOADING

配置 showLoading 为 false 时,使用自定义动画,您可在这个时机渲染并展示自定义加载动画。

无需进一步操作。

SDK_END_OF_LOADING

配置 showLoading 为 false 时,使用自定义动画,您可在这个时机结束自定义加载动画。

无需进一步操作。

SDK_CALL_URL_ERROR

此事件码代表以下事件信息中的一种情况:

Web/WAP 场景下通常不会出现跳转异常,如果出现异常建议您校验重定向链接。在 App 场景下,如果频繁出现跳转异常,请联系 Antom 技术支持,排查跳转或唤端问题。

无需进一步操作。

SDK_PAYMENT_CANCEL

表示用户取消支付,即用户未提交订单退出支付页面。您可使用有效期内的 paymentSessionData 重新调用 SDK。如已过期,需要重新发起 支付会话创建(快捷支付)请求。

无需进一步操作。

错误码

SDK_INTERNAL_ERROR

SDK 内部错误。

请联系 Antom 技术支持。

SDK_CREATEPAYMENT_PARAMETER_ERROR

createComponent 函数传入参数异常。

请检查参数是否正确并重新初始化组件。

SDK_INIT_PARAMETER_ERROR

AMSEasyPay 函数传入参数异常。

请检查参数是否正确并重新初始化组件。

SDK_CREATECOMPONENT_ERROR

组件初始化异常。

请联系 Antom 技术支持。

SDK_SUBMIT_NETWORK_ERROR

因网络原因,接口调用失败。在 submit 函数提交中可能会出现。

请尝试再次提交。