介绍 Payment Request API 用于 Apple Pay

我们很高兴地宣布,macOS 上的 Safari 11.1 和 iOS 11.3 上的 Safari 现已支持 W3C Payment Request API,用于在网络上进行 Apple Pay 交易。

我们首次在 macOS Sierra 和 iOS 10 中引入了 Apple Pay on the Web。Apple Pay 为在线交易带来了全新的易用性、安全性和隐私性,因此我们很高兴看到它在这些年被商家广泛采用。然而,我们认识到商家需要支持多种支付方式,而这样做会增加复杂性。Payment Request 旨在通过使用标准 API 在多个浏览器中支持支付方式来降低这种复杂性。

今天我将逐步带您了解如何使用 Payment Request 进行 Apple Pay 交易。如果您已经使用过 Apple Pay JS,这应该看起来很熟悉。如果您还没有,这是一个很好的入门机会!

先决条件

本文假设您已经注册了商家标识符设置了您的服务器环境来处理 Apple Pay 交易。您可以在Apple Pay on the Web 文档中找到详细说明。

显示 Apple Pay 按钮

Apple Pay 交易总是由您的客户发起,因此您需要显示一个 Apple Pay 按钮供他们轻触或点击。为了保持一致的视觉外观,WebKit 提供了内置支持来渲染 Apple Pay 按钮。以下是显示最基本类型的 Apple Pay 按钮的方法

<button style="-webkit-appearance: -apple-pay-button;"></button>

还有其他几种不同样式的按钮可用。以下是您可能在 Safari 中购物时见过的一些按钮

Apple Pay Buttons

有关可用的按钮类型和样式的更多信息,请参阅显示 Apple Pay 按钮

根据Apple Pay on the Web 人机界面指南,每当您的客户使用受支持的设备时,都应显示 Apple Pay 按钮。要检查您的客户设备是否支持 Apple Pay,请调用ApplePaySession.canMakePayments()

if (window.ApplePaySession && ApplePaySession.canMakePayments())
    // Show Apple Pay button.

如果您的客户轻触或点击 Apple Pay 按钮,您应始终呈现 Apple Pay 支付表单。如果他们尚未在 Apple Pay 中注册您可以接受的支付卡,Safari 会提示他们注册,然后才继续进行您的交易。由于这些规则是 Apple Pay 特有的,因此此步骤需要使用 Apple Pay JS 的ApplePaySession API。交易的其余部分可以使用标准的 Payment Request API 进行。

构建 PaymentRequest

当您的客户轻触或点击 Apple Pay 按钮时,您可以通过构建新的 PaymentRequest 来启动交易

var request = null;
if (window.PaymentRequest)
    request = new PaymentRequest(methods, details, options);
else
    // Consider using Apple Pay JS instead.

PaymentRequest 构造函数接受三个参数:您支持的支付方式、向客户显示的详细信息(如配送选项和总金额)以及您要求的任何选项。

支付方式

支付方式表示您可以使用 Payment Request 接受客户付款的方式。您将接受的支付方式指定为一系列PaymentMethodData 字典,每个字典包含一个标识符(supportedMethods)以及相关的data

要将 Apple Pay 与 Payment Request 一起使用,请将其包含作为支付方式。Apple Pay 基于 URL 的支付方式标识符是 "https://apple.com/apple-pay",其相关的 data 是一个 ApplePayRequest 字典。以下是 Apple Pay 的 PaymentMethodData 字典可能的样子

const applePayMethod = {
    supportedMethods: "https://apple.com/apple-pay",
    data: {
        version: 3,
        merchantIdentifier: "merchant.com.example",
        merchantCapabilities: ["supports3DS", "supportsCredit", "supportsDebit"],
        supportedNetworks: ["amex", "discover", "masterCard", "visa"],
        countryCode: "US",
    },
};

Safari 仅支持 Apple Pay 支付方式,但其他浏览器可能支持额外的支付方式。当您在请求中指定多种支付方式时,浏览器会根据设备可用性和用户偏好决定向您的客户呈现哪种方式。

支付详情

支付详情由 PaymentDetailsInit 字典表示。它包含您的交易总金额、显示项、配送选项以及支付方式特定的修改器(更多关于修改器的内容见下文)。以下是一个 20 美元的商品加上税费和两个配送选项的有效支付详情示例

const paymentDetails = {
    total: {
        label: "My Merchant",
        amount: { value: "27.50", currency: "USD" },
    },
    displayItems: [{
        label: "Tax",
        amount: { value: "2.50", currency: "USD" },
    }, {
        label: "Ground Shipping",
        amount: { value: "5.00", currency: "USD" },
    }],
    shippingOptions: [{
        id: "ground",
        label: "Ground Shipping",
        amount: { value: "5.00", currency: "USD" },
        selected: true,
    }, {
        id: "express",
        label: "Express Shipping",
        amount: { value: "10.00", currency: "USD" },
    }],
};

您可以通过将 selected 属性设置为 true 来选择默认配送选项,就像我们在上面为 "Ground Shipping" 所做的那样。总金额不能是负数,并且在使用 Apple Pay 时,您请求中的所有支付金额必须使用相同的 ISO 4217 货币代码。您有责任确保支付详情的正确性;Safari 不会代表您进行任何货币计算。

关于修改器?

您可以在支付详情中选择性地包含一系列 modifiers(修改器)。当满足您为给定支付方式指定的条件时,修改器会更新您的交易显示项和总金额。在 Apple Pay 中,您可以使用修改器根据在 Apple Pay 支付表单中选择的支付卡类型来调整价格。例如,以下修改器在您的客户在 Apple Pay 中选择借记卡时应用 1.00 美元的折扣

const debitModifier = {
    supportedMethods: "https://apple.com/apple-pay",
    data: { paymentMethodType: "debit" },
    total: {
        label: "My Merchant",
        amount: { value: "26.50", currency: "USD" },
    },
    additionalDisplayItems: [{
        label: "Debit Card Discount",
        amount: { value: "-1.00", currency: "USD" },
    }],
};

修改器提供了 Apple Pay JS 中 paymentmethodselected 事件的一些功能。更多信息请参阅ApplePayModifier

支付选项

支付选项由 PaymentOptions 字典表示。如果您需要请求客户的姓名、电子邮件地址或电话号码,或者请求某种类型的配送方式,您可以在这里设置

const paymentOptions = {
    requestPayerName: true,
    requestPayerEmail: true,
    requestPayerPhone: true,
    requestShipping: true,
    shippingType: "shipping",
};

如果您将 requestShipping 设置为 true,您在支付详情中指定的配送选项将显示在支付表单中供您的客户选择。客户授权支付后,您将收到请求的信息。

异常

在构建新的 PaymentRequest 时,Safari 可能会抛出异常。异常可能由以下原因引起

  • 框架不在安全上下文中。
  • 框架是跨域子框架。
  • 未指定支付方式。
  • 支付方式标识符无效
  • 对支付方式数据调用 JSON.stringify() 失败。
  • 指定了无效的货币金额(例如,负数总额或多种货币)。

canMakePayment() 方法

构建 PaymentRequest 后,您可以询问您的客户是否能够使用您接受的支付方式授权交易。您可以通过调用 canMakePayment() 方法来执行此操作,该方法返回一个解析为 truefalse 的 Promise。在 Safari 中,当 Apple Pay 是支付方式之一时,canMakePayment() 仅在您的客户在 Apple Pay 中注册了活动卡时解析为 true。这相当于 ApplePaySession.canMakePaymentsWithActiveCard() 在 Apple Pay JS 中的行为方式。

正如我们在显示 Apple Pay 按钮中所讨论的,Apple Pay 人机界面指南要求您在客户使用受支持的硬件时显示 Apple Pay 按钮,无论他们是否注册了活动卡。因此,当 canMakePayment() 解析为 false 时,您不应该隐藏 Apple Pay 按钮。如果 ApplePaySession.canMakePayments() 返回 true,请始终显示 Apple Pay 按钮,并在客户轻触或点击按钮时始终呈现 Apple Pay 支付表单。如果您的客户尚未注册支付卡,Safari 会在继续交易之前提示他们注册。更多信息请参阅人机界面指南 > Apple Pay on the Web

show() 方法

当您的客户轻触或点击 Apple Pay 按钮时,您应该呈现 Apple Pay 支付表单。您可以通过调用 show() 方法来执行此操作,该方法返回一个 Promise,一旦您的客户授权支付,该 Promise 将解析为 PaymentResponse。如果您的客户取消交易,Promise 将以 AbortError 拒绝。

您可以选择调用带有 PaymentDetailsUpdate Promise 的 show() 方法。有时,当您的客户轻触或点击 Apple Pay 按钮时,您可能仍在计算支付详情的过程中。在这种情况下,您可以构建一个带有占位符详细信息的新 PaymentRequest,然后调用 show() 并带有一个 Promise,以便稍后提供最新的详细信息。当您解析此 Promise 时,Safari 会在 Apple Pay 支付表单中显示更新后的详细信息。

Safari 可能会以异常拒绝 show() 返回的 Promise。异常可能由以下原因引起

  • show() 未由用户激活(例如,轻触或点击)触发。
  • 请求已被中止。
  • Apple Pay 会话已处于活动状态。
  • 支付方式数据无效(例如,缺少必填字段)。

abort() 方法

如果您需要中止已呈现的交易,可以调用 abort() 方法。执行此操作时,Safari 会关闭 Apple Pay 支付表单,并使用 AbortError 拒绝 show() 返回的 Promise。如果交易已被中止,或者尚未调用 show(),调用 abort() 将抛出 InvalidStateError

商家验证

在 Safari 呈现 Apple Pay 支付表单之前,您必须从 Apple 获取支付会话。此过程称为商家验证

在您调用 show() 后不久,Safari 会向您的 PaymentRequest 对象分派 merchantvalidation 事件。该事件定义了一个 validationURL 属性,表示您的服务器用于联系 Apple 以接收支付会话的 URL。您必须使用一个 Promise 调用事件的 complete() 方法,并在接收到支付会话后解析该 Promise。

以下是一个 merchantvalidation 事件处理程序的示例

request.onmerchantvalidation = function (event) {
    const sessionPromise = fetchPaymentSession(event.validationURL);
    event.complete(sessionPromise);
};

您可以从请求 Apple Pay 支付会话了解更多关于商家验证的信息。

配送事件

收到商家会话后,Safari 会向您的客户呈现 Apple Pay 支付表单。如果您请求了配送信息,客户可以在您的配送选项中进行选择并提供配送地址。当他们在支付表单中进行这些选择时,Safari 会向您的 PaymentRequest 对象分派 shippingoptionchangeshippingaddresschange 事件。

shippingoptionchange(配送选项更改)

当用户选择配送选项时,Safari 会分派 shippingoptionchange 事件。在您的事件处理程序中,您可以通过检查 PaymentRequestshippingOption 属性来确定选定的配送选项。要根据选定的配送选项更新支付详情,请在事件对象上调用 updateWith(),并带有一个解析为 PaymentDetailsUpdate 的 Promise。

使用 Apple Pay 请求配送时,您必须始终监听 shippingoptionchange 事件,并调用 updateWith() 并带有一个在 30 秒内解析的 Promise,否则交易将超时。

shippingaddresschange(配送地址更改)

当您的客户选择配送地址时,Safari 会分派 shippingaddresschange 事件。在您的事件处理程序中,您可以通过检查 PaymentRequestshippingAddress 属性来确定选定的配送地址。要根据选定的配送地址更新支付详情,请在事件对象上调用 updateWith(),并带有一个解析为 PaymentDetailsUpdate 的 Promise。如果您无法配送到选定的地址,您可以在 PaymentDetailsUpdate 中提供一条错误消息,Safari 会将其显示给您的客户。

使用 Apple Pay 时,Safari 可能会从配送地址中删除一些详细信息。例如,在美国,仅提供城市、州、5 位数邮政编码和国家/地区。一旦您的客户授权支付,Safari 才会提供完整的、未删除的配送地址。

使用 Apple Pay 请求配送时,您必须始终监听 shippingaddresschange 事件,并调用 updateWith() 并带有一个在 30 秒内解析的 Promise,否则交易将超时。

处理支付授权

当您的客户授权支付时,Safari 会使用 PaymentResponse 解析您通过调用 show() 收到的 Promise。根据您在 PaymentOptions 中请求的内容,响应可能包含您客户选定的配送选项、配送地址、姓名、电子邮件和电话号码。

响应还包含用于执行交易的支付方式标识符(methodName)以及相关的 details。当 Apple Pay 是选定的支付方式时,相关的 details 是一个 ApplePayPayment 字典。ApplePayPayment 包含您用于处理支付授权的 Apple Pay token。如果您在 ApplePayRequest 中要求了客户的账单和配送联系信息,它还会包含这些信息,形式为 ApplePayPaymentContacts

完成处理支付授权后,您可以调用 PaymentResponse 上的 complete() 方法来指示处理结果。您可以调用 complete() 并指定状态为 "success""failure"。此时,Apple Pay 支付表单将被关闭。

演示

现在您已经具备了使用 Payment Request 进行 Apple Pay 交易所需的所有要素。以下是使用 Payment Request 进行 Apple Pay 会话的示例

async function applePayButtonClicked()
{
    // Consider falling back to Apple Pay JS if Payment Request is not available.
    if (!window.PaymentRequest)
        return;

    try {
        const request = new PaymentRequest([applePayMethod], paymentDetails, paymentOptions);

        request.onmerchantvalidation = function (event) {
            // Have your server fetch a payment session from event.validationURL.
            const sessionPromise = fetchPaymentSession(event.validationURL);
            event.complete(sessionPromise);
        };

        request.onshippingoptionchange = function (event) {
            // Compute new payment details based on the selected shipping option.
            const detailsUpdatePromise = computeDetails();
            event.updateWith(detailsUpdatePromise);
        };

        request.onshippingaddresschange = function (event) {
            // Compute new payment details based on the selected shipping address.
            const detailsUpdatePromise = computeDetails();
            event.updateWith(detailsUpdatePromise);
        };

        const response = await request.show();
        const status = processResponse(response);
        response.complete(status);
    } catch (e) {
        // Handle errors
    }
}

让我们在一个实时演示中看看这是如何工作的。如果您正在使用支持 Apple Pay 的设备查看此文章,您应该会在下方看到一个 Apple Pay 按钮。请随意点击!别担心,无论您在支付表单中做什么,您的卡都不会被扣款。

可用性

Payment Request API 在 macOS Sierra 和 macOS High Sierra 上的 Safari 11.1、iOS 11.3 上的 Safari 以及 Safari Technology Preview 中可用。

更多信息

Apple 为 Apple Pay on the Web 提供了全面的文档。以下是一些您可能会觉得有用的链接

反馈

我们很乐意听取您的反馈!如果您发现了 Payment Request 的 bug,请在 bugs.webkit.org 报告。在 Twitter 上,您可以联系 WebKit 团队 @webkit,或我们的 Web 技术布道师 Jonathan Davis @jonathandavis