Alipay, China's leading third-party online payment solutionAlipay, China's leading third-party online payment solution

APM 支付(Android)

Antom SDK 是一个预构建的用户界面组件,简化了集成 Antom 支付服务的过程。此组件提供了一种简单快捷的方式来集成 Antom 支持的所有支付方式,包括信用卡、数字钱包、银行转账、在线银行等。

SDK 组件可以自动适应买家的设备和位置,根据支付方式的特性执行信息收集、重定向、应用切换、显示二维码等任务。您可以在您的网站或应用上轻松提供全面的支付解决方案,节省构建每个支付界面和流程所需的时间和资源。

用户体验

以下图表展示了在应用程序中支付的用户流程:

image.png

注意:如果您希望为买家提供 Alipay+ 统一支付体验,而不是上述用户体验,请参阅 Alipay+ 统一支付收银台,并联系Antom 技术支持获取更多集成详情。

支付流程

每种支付方式的支付流程包括以下步骤:

WAP)-中@3x.png

  1. 买家进入结账页面。
  2. 创建支付会话请求。
    买家选择支付方式并提交订单后,您可以通过调用 支付会话创建(收银台)接口获取支付会话。
  3. 调用客户端SDK。
    在客户端,通过支付会话调用 SDK。SDK 会根据支付方式的特性处理信息收集、重定向、应用调用、二维码显示、验证等流程。
  4. 获取支付结果。
    通过以下两种方法之一获取支付结果:

集成步骤

开始集成,请按照以下步骤开始集成:

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

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

当买家选择 Antom 提供的支付方式时,您需要收集关键信息,如支付请求 ID、订单金额、支付方式、订单描述、支付重定向链接和支付结果通知链接,调用 支付会话创建(收银台)接口来创建支付会话,并将支付会话返回给客户端。

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

安装接口库

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

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

初始化请求实例

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

copy
import com.alipay.global.api.AlipayClient;
import com.alipay.global.api.DefaultAlipayClient;

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);

}

创建支付会话

创建支付会话涉及以下参数:

参数名称

是否必需

描述

productCode

值设置为 CASHIER_PAYMENT

paymentRequestId

由商户生成的专属 ID,每次发起支付时需使用新的 ID。

paymentAmount

支付金额,应根据订单货币的最小单位设置,例如,CNY 为分,KRW 为元。

paymentMethod

支付方式枚举

paymentRedirectUrl

商户的支付结果页面,根据服务器端的结果,不是一个固定的成功页面。

order

订单信息,包括商户侧的订单金额、订单 ID 和订单描述。

paymentNotifyUrl

支付结果通知地址,可通过接口传入,也可通过门户设置为固定值。

settlementStrategy

支付的结算货币,如果业务签约了多个结算货币,需在接口中指定。

以上参数是创建支付会话的基本参数,完整参数和特定支付方式的额外要求请参考 支付会话创建(收银台)

调用支付会话创建接口的示例代码

以下示例代码展示了如何调用 支付会话创建(收银台)接口:

copy
private static void createPaymentSession() {
    AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
    alipayPaymentSessionRequest.setProductCode(ProductCodeType.CASHIER_PAYMENT);

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

    // set amount
    Amount amount = Amount.builder().currency("SGD").value("4200").build();
    alipayPaymentSessionRequest.setPaymentAmount(amount);

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

    // replace with your orderId
    String orderId = UUID.randomUUID().toString();

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

    // set order info
    Order order = Order.builder().referenceOrderId(orderId)
        .orderDescription("antom testing order").orderAmount(amount).buyer(buyer).build();
    alipayPaymentSessionRequest.setOrder(order);

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

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

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

以下代码显示了一个请求报文的示例:

copy
{
  "order": {
    "buyer": {
      "referenceBuyerId": "yourBuyerId"
    },
    "orderAmount": {
      "currency": "SGD",
      "value": "4200"
    },
    "orderDescription": "antom testing order",
    "referenceOrderId": "referenceOrderId01"
  },
  "paymentAmount": {
    "currency": "SGD",
    "value": "4200"
  },
  "paymentMethod": {
    "paymentMethodType": "SHOPEEPAY_SG"
  },
  "paymentNotifyUrl": "https://www.yourNotifyUrl.com",
  "paymentRedirectUrl": "https://www.yourMerchantWeb.com",
  "paymentRequestId": "paymentRequestId01",
  "productCode": "CASHIER_PAYMENT"
}

以下代码显示了一个响应的示例,其中包含以下参数:

  • paymentSessionData :需要返回给前端的支付会话数据
  • paymentSessionExpiryTime :支付会话的过期时间。
copy
{
  "paymentSessionData": "gM5Y/Go6+IXMPSOZrYtukCdodtwxuSFsn1vRPSB8CzkDqlb1g2W7dDipOkoMRs/x2W7g7qVhjEM7RUGroIT8Cw==&&SG&&188&&eyJhY3Rpb24iOnsiYXBwIjp7fSwibmVlZFZlcmlmeUFuZFJlc3VtZSI6ZmFsc2UsInNraXBTZGtRdWVyeSI6ZmFsc2UsIndhcCI6e30sIndlYiI6e319LCJjbGllbnRJZCI6IlNBTkRCT1hfNVlCWjBMMlpIUjhSMDg5NzgiLCJleHRlbmRJbmZvIjoie1widmVyc2lvbk1hcFwiOntcIndlYlwiOntcIjEuMS4wXCI6e1widGFyZ2V0V2ViVmVyaXNvblwiOlwiMS4xLjBcIn0sXCIxLjIuMFwiOntcInRhcmdldFdlYlZlcmlzb25cIjpcIjEuMi4wXCJ9fSxcImlPU1wiOntcIjEuMS4wXCI6e1widGFyZ2V0V2ViVmVyaXNvblwiOlwiMS4xLjBcIn0sXCIxLjIuMFwiOntcInRhcmdldFdlYlZlcmlzb25cIjpcIjEuMi4wXCJ9fSxcIkFuZHJvaWRcIjp7XCIxLjEuMFwiOntcInRhcmdldFdlYlZlcmlzb25cIjpcIjEuMS4wXCJ9LFwiMS4yLjBcIjp7XCJ0YXJnZXRXZWJWZXJpc29uXCI6XCIxLjIuMFwifX19fSIsInBheW1lbnRTZXNzaW9uQ29uZmlnIjp7InBheW1lbnRNZXRob2RDYXRlZ29yeVR5cGUiOiJBUE0iLCJwcm9kdWN0U2NlbmUiOiJDQVNISUVSX1BBWU1FTlQiLCJwcm9kdWN0U2NlbmVWZXJzaW9uIjoiMS4wIn19",
  "paymentSessionExpiryTime": "2024-01-01T00:00:00+08:00",
  "paymentSessionId": "gM5Y/Go6+IXMPSOZrYtukCdodtwxuSFsn1vRPSB8Czn6HfgqNzo2ogbIk1NUQS35",
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}

常见问题

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

答:为了避免特定支付方式的兼容性问题,请求中的字段请勿使用中文字符。

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

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

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

Antom SDK 是用于处理支付流程的组件。为了收集信息、在应用间切换以及根据 支付会话创建(收银台)接口中指定的支付方式显示二维码,您需要通过创建支付会话来启动 SDK。

当买家在页面上选择支付方式后,您需要创建并使用支付会话初始化 SDK。

安装

版本要求:目标至少为 Android 4.4(API level 19)或更高版本。

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

初始化 SDK

使用 AMSCashierPayment 创建 SDK 实例并指定基本配置。创建配置对象包括以下方法:

方法名称

必需

描述

setLocale

用于传递语言信息。有效值如下所示。您可以根据支付方式的地区选择要传递的值。如果传递其他值,默认使用本地语言:

  • en_US:英语
  • pt_BR葡萄牙语
  • ko_KR韩语
  • es_ES西班牙语
  • ms_MY马来语
  • in_ID印尼语
  • tl_PH他加禄语
  • th_TH泰语
  • vi_VN越南语
  • fr_FR法语
  • nl_NL荷兰语
  • it_IT意大利语
  • de_DEGerman
  • zh_CN简体中文
  • zh_HK繁体中文

setOption

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

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

setOnCheckoutListener

创建一个 OnCheckoutListener 接口实例,用于后续过程中的事件处理。该接口包括以下方法:

  • onEventCallback:必须。一个监听结账页面支付事件的回调函数,返回 eventCodeeventResult

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

copy
AMSCashierPaymentConfiguration configuration = new AMSCashierPaymentConfiguration();
configuration.setLocale(new 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.
configuration.setOption("showLoading", "true");
onfiguration.setOption("showLoading", "true");
// Set the sandbox environment. If you leave it empty, the production environment is used by default.
configuration.setOption("sandbox", "true");
// Set the callback to monitor payment events on the checkout page.
configuration.setOnCheckoutListener(new OnCheckoutListener() {
    @Override
    public void onEventCallback(String eventCode, AMSEventResult eventResult) {
        Log.e(TAG, "onEventCallback eventCode=" + eventCode + " eventResult=" + eventResult.toString());
    }
});
// Instantiate AMSCashierPayment.
AMSCashierPayment checkout = new AMSCashierPayment.Builder(activity, configuration).build();

调用 SDK

调用 createComponent 方法:

参数名称

是否必需

描述

sessionData

使用 sessionData 参数创建配置对象:将通过 支付会话创建(收银台)接口在响应中获取的完整 paymentSessionData 参数传递给 sessionData

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

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

copy
checkout.createComponent(activity, sessionData);

//Free SDK component resources
checkout.onDestroy();

显示支付结果

您可以使用支付组件处理需要重定向的支付方式(异步支付)和不需要的(同步支付)。

重定向支付

某些支付方式的支付过程需要离开原网页,跳转到机构页面完成支付,例如网银支付。在这种情况下,买家在完成支付后会被重定向到您在 支付会话创建(收银台)接口中提供的 paymentRedirectUrl 。您可以通过主动查询获取支付结果,并在该链接上向买家展示。

非重定向支付

对于不需要跳转的支付,支付结果将通过 onEventCallback 函数给出。这里的支付结果仅用于前端显示,最终订单状态以服务器端为准。您需要通过 onEventCallback 返回的数据自定义每个支付结果的处理流程。

以下是由 onEventCallback 返回的支付结果可能的事件代码。

事件代码

消息

解决方案

SDK_PAYMENT_SUCCESSFUL

支付成功。

建议将买家重定向到支付结果页面。

SDK_PAYMENT_PROCESSING

支付正在处理中。

建议您检查在onEventCallback结果数据中 paymentResultCode 的值以获取详细信息。根据提供的信息,引导买家重新尝试支付。

SDK_PAYMENT_FAIL

支付失败。

建议您检查在onEventCallback结果数据中 paymentResultCode 的值以获取详细信息。根据提供的信息,引导买家重新尝试支付。

SDK_PAYMENT_CANCEL

买家在未提交订单的情况下退出了支付页面。

在有效期内,可以使用 paymentSessionData 重新调用SDK;如果已过期,需要重新请求paymentSessionData

SDK_PAYMENT_ERROR

支付状态异常。

建议您检查在onEventCallback结果数据中 paymentResultCode 的值以获取详细信息。根据提供的信息,引导买家重新尝试支付。

以下示例代码展示了如何处理回调事件 onEventCallback

copy
@Override
public void onEventCallback(String eventCode, AMSEventResult eventResult) {
    AlipayLog.e(TAG, "onEventCallback eventCode=" + eventCode + " eventResult=" + eventResult.toString());

    if (!TextUtils.isEmpty(eventCode)) {
        if ("SDK_PAYMENT_SUCCESSFUL".equals(eventCode)) {
            // Payment was successful. Redirect buyers to the payment result page.
        } else if ("SDK_PAYMENT_PROCESSING".equals(eventCode)) {
            // Payment was being processed. Guide buyers to retry the payment based on the provided information.
        } else if ("SDK_PAYMENT_FAIL".equals(eventCode)) {
            // Payment failed. Guide buyers to retry the payment based on the provided information.
        }else if ("SDK_PAYMENT_CANCEL".equals(eventCode)) {
            // Guide buyers to retry the payment.
        } else if ("SDK_PAYMENT_ERROR".equals(eventCode)) {
            // The payment status was abnormal. Guide buyers to retry the payment based on the provided information.
        } else if ("SDK_END_OF_LOADING".equals(eventCode)) {
            // End your custom loading animation.
        }
    }
}

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

在买家完成支付或支付超时后, Antom 会通过服务器交互将相应的支付结果发送给您,您可以通过以下方法之一获取支付结果:

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

接收异步通知

当支付成功或失败时,Antom会向您在 支付会话创建(收银台)接口的 paymentNotifyUrl 参数中指定的地址发送异步通知(支付通知)。收到 Antom 的通知后,您需要按照返回收到确认信息返回响应。

Antom允许您在 支付会话创建(收银台)接口的 paymentNotifyUrl 参数中指定链接。如果每个支付的地址相同,您也可以在 Antom Dashboard 中配置该地址。

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

copy
{
  "notifyType": "PAYMENT_RESULT",
  "result": {
    "resultCode": "SUCCESS",
    "resultStatus": "S",
    "resultMessage": "success"
  },
  "paymentRequestId": "paymentRequestId01",
  "paymentId": "20240101123456789XXXX",
  "paymentAmount": {
    "value": "4200",
    "currency": "SGD"
  },
  "paymentCreateTime": "2024-01-01T00:00:00+08:00",
  "paymentTime": "2024-01-01T00:01:00+08:00"
}

如何验证通知的签名并做出响应,请参阅签名与验签

常见问题

问:何时会发送通知?

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

  • 如果支付成功完成,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:表示支付金额。

查询结果

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

参数名

是否必需

描述

paymentRequestId

商户生成的支付请求ID。

完整的参数集,请参考 支付结果查询 接口文档,获取全部参数及特定支付方式的额外要求。

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

copy
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
    }
}

以下是请求报文的示例:

copy
{
  "paymentRequestId": "paymentRequestId01"
}

以下是响应报文的示例:

copy
{
  "result": {
    "resultCode": "SUCCESS",
    "resultStatus": "S",
    "resultMessage": "Success"
  },
  "paymentStatus": "SUCCESS",
  "paymentRequestId": "paymentRequestId01",
  "paymentId": "20240101123456789XXXX",
  "paymentAmount": {
    "value": "4200",
    "currency": "SGD"
  },
  "paymentCreateTime": "2024-01-01T00:00:00+08:00",
  "paymentTime": "2024-01-01T00:01:00+08:00",
  "paymentMethodType": "SHOPEEPAY_SG"
}

常见问题

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

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

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

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

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

示例代码

前端完整样例代码:

copy
AMSCashierPaymentConfiguration configuration = new AMSCashierPaymentConfiguration();
configuration.setLocale(new 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.
configuration.setOption("showLoading", "true");
// Set the sandbox environment. If you leave it empty, the production environment is used by default.
configuration.setOption("sandbox", "true");
// Set the callback to monitor payment events on the checkout page.
configuration.setOnCheckoutListener(new OnCheckoutListener() {
    @Override
    public void onEventCallback(String eventCode, AMSEventResult eventResult) {
        AlipayLog.e(TAG, "onEventCallback eventCode=" + eventCode + " eventResult=" + eventResult.toString());

        if (!TextUtils.isEmpty(eventCode)) {
            if ("SDK_PAYMENT_SUCCESSFUL".equals(eventCode)) {
                // Payment was successful. Redirect buyers to the payment result page.
            } else if ("SDK_PAYMENT_PROCESSING".equals(eventCode)) {
                // Payment was being processed. Guide buyers to retry the payment based on the provided information.
            } else if ("SDK_PAYMENT_FAIL".equals(eventCode)) {
                // Payment failed. Guide buyers to retry the payment based on the provided information.
            }else if ("SDK_PAYMENT_CANCEL".equals(eventCode)) {
                // Guide buyers to retry the payment.
            } else if ("SDK_PAYMENT_ERROR".equals(eventCode)) {
                // The payment status was abnormal. Guide buyers to retry the payment based on the provided information.
            } else if ("SDK_END_OF_LOADING".equals(eventCode)) {
                // End your custom loading animation.
            }
        }
    }
});
// Instantiate AMSCashierPayment.
AMSCashierPayment checkout = new AMSCashierPayment.Builder(activity, configuration).build();

checkout.createComponent(activity, sessionData);

checkout.onDestroy();

事件代码

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

  • 状态代码:由组件运行时生命周期中的onEventCallback 返回。
  • 错误代码:由组件初始化阶段的onEventCallback 或onError 返回。

类型

代码

描述

后续操作

状态代码

SDK_START_OF_LOADING

在创建支付组件时开始播放加载动画。

无需进一步操作。

SDK_END_OF_LOADING

在创建支付组件时加载动画结束。

无需进一步操作。

错误代码

SDK_INTERNAL_ERROR

SDK 内部错误发生。

请联系 Antom 技术支持解决此问题。

SDK_CREATEPAYMENT_PARAMETER_ERROR

传递给 createComponent 方法的参数不正确。

确保参数传递正确并重新发送请求。

SDK_CALL_URL_ERROR

表示以下情况之一:

请联系Antom技术支持解决此问题。

SDK_INTEGRATION_ERROR

未找到依赖项。

请确保已正确添加依赖项,然后重试集成过程。