What's new in Wallet and Apple Pay
System Frameworks 进阶 20m

Wallet 和 Apple Pay 的新变化

What's new in Wallet and Apple Pay

2024年6月10日

在 Apple 官方观看视频

一句话判断

Apple Pay 终于跨出了 Safari 的围墙——iOS 18 用户可以在任何浏览器上通过扫码用 Apple Pay 完成支付,这对电商转化率的提升是实打实的。

这场 Session 讲了什么

Apple Pay 一直是苹果生态里”好用但封闭”的典型代表。你在 Safari 里用 Apple Pay 体验丝滑,但一旦用户用的是 Chrome、Firefox 或者非 Apple 设备,你就得准备另一套支付流程。很多电商站点为此做了复杂的浏览器检测逻辑,体验割裂。据统计,非 Safari 浏览器在移动端的市场份额相当可观——这意味着大量潜在用户在结账时根本看不到 Apple Pay 按钮,白白流失了转化机会。

iOS 18 打破了这个局面。用户在任何浏览器(不限于 Safari)上点击 Apple Pay 按钮时,页面会弹出一个二维码,用 iPhone 扫码即可完成支付。背后的交易流程和 Safari 内的 Apple Pay 完全一致——开发者收到的 payment response 数据格式一样,已有的服务端处理代码不需要改。开发者只需要做两件事:引入 Apple Pay JavaScript SDK 1.2.0+ 并使用 SDK 提供的按钮组件(而不是 CSS 实现的按钮)。Session 中的现场演示很直观:在一台非 Mac 电脑的非 Safari 浏览器上打开宠物商店网站,结账时点击 Apple Pay,弹出二维码,用 iPhone 扫码确认,支付完成。

Session 还介绍了另一个重要更新:资金转出(Funds Transfer/Disbursement)能力扩展到了 web 平台。去年 iOS 端上线的提现功能现在在 macOS 15 的 Safari 上也能用了,用户可以把余额从 app 内的账户转到绑定的银行卡。

这两个更新传递了一个明确的信号:苹果在支付领域不再执着于”只有 Safari 才能用 Apple Pay”的围墙策略。通过扫码方案巧妙地绕开了浏览器兼容性问题,同时保持了用户体验和安全标准。对于电商和金融类 app 的开发者来说,这意味着你可以把 Apple Pay 的覆盖面从”只有 Safari 用户”扩展到”所有用户”,转化率的提升是可以预期的。

值得深挖的点

跨浏览器 Apple Pay 的技术方案:扫码 + 设备端交易

这个功能的实现方式很聪明。它没有走”在非 Safari 浏览器里嵌入 Apple Pay sheet”这条死路(技术上太复杂,各家浏览器也不会配合),而是用一个扫码流程把交易”转移”到 iPhone 上完成。用户在 Chrome/Firefox 等浏览器上看到 Apple Pay 按钮,点击后页面展示一个二维码,用 iPhone 相机扫码后,iPhone 端弹出标准的 Apple Pay 确认界面——双击侧键、Face ID 验证、支付完成。

对开发者来说,服务端逻辑零改动。无论用户从哪个浏览器发起,你收到的 payment token 格式都一样。苹果用了一种很”苹果”的方式解决了跨平台问题:不是去适配所有浏览器,而是让 iPhone 成为所有浏览器的支付终端。这和 Apple Watch 上的 Apple Pay 思路一致——你不需要商户的 POS 终端支持 Apple Watch 协议,而是让 Watch 和 iPhone 共享同一个安全元件(Secure Element)。在这里,iPhone 本身就是跨平台的支付安全模块。

不过有一个前提条件:用户的 iPhone 必须运行 iOS 18,并且同一 Apple ID 下有支持 web 支付的银行卡。新的 applePayCapabilities() API 可以帮你判断当前环境是否适合展示 Apple Pay 按钮。

applePayCapabilities() 取代 canMakePaymentsWithActiveCard()

旧的 canMakePaymentsWithActiveCard() API 被废弃了。新 API 返回一个结构化的对象,包含 paymentCredentialStatus 字段,有四种状态:

  • paymentCredentialsAvailable:设备支持且卡就绪,Apple Pay 应该作为首选支付方式展示。
  • paymentCredentialsUnavailable:设备支持但没有可用的卡,不应该显示按钮。
  • paymentCredentialStatusUnknown:通常出现在非 Safari 浏览器或非 Apple 设备上,应该显示按钮但排序由开发者决定。
  • applePayUnsupported:直接不显示。

这个 API 比 canMakePaymentsWithActiveCard() 更精确,特别是在跨浏览器场景下。以前你只能做”能用/不能用”的二选一,现在可以精细控制按钮的展示策略。

值得单独说一下 Funds Transfer on the web 的细节。去年 iOS 端推出的提现 API 今年扩展到了 web,支持普通提现和即时提现两种模式。即时提现需要在 merchantCapabilities 中额外声明 supportsInstantFundsOut,并且可以在 payment sheet 中展示手续费。整个 payment sheet 的展示方式对用户来说很直观:选卡、看金额(含手续费)、确认。提现场景必须把 requestShipping 设为 false,否则用户会看到不必要的配送信息,造成困惑。

代码片段

引入 Apple Pay JS SDK 并使用 SDK 按钮

<!-- 在 head 标签中引入 SDK 1.2.0+ -->
<head>
  <script src="https://applepay.cdn-apple.com/jsapi/v1.2.0/apple-pay-sdk.js"></script>
</head>
<body>
  <!-- 使用 SDK 按钮组件,不要用 CSS 版本 -->
  <apple-pay-button
    id="apple-pay-btn"
    buttonstyle="black"
    type="pay"
    locale="zh-CN"
  ></apple-pay-button>
</body>

场景:支持非 Safari 浏览器的 Apple Pay。坑:如果你之前用 CSS 自定义的按钮样式渲染 Apple Pay logo,必须换成 SDK 提供的组件,否则跨浏览器功能不生效。

使用 applePayCapabilities API

// 新 API:精细判断支付能力
const capabilities = await ApplePaySession.applePayCapabilities(
  { merchantIdentifier: "your.merchant.id" }
);

switch (capabilities.paymentCredentialStatus) {
  case "paymentCredentialsAvailable":
    // 作为首选支付方式展示
    showApplePayAsDefault();
    break;
  case "paymentCredentialStatusUnknown":
    // 非 Safari 环境,仍然展示但排序由你决定
    showApplePayAsOption();
    break;
  case "applePayUnsupported":
  case "paymentCredentialsUnavailable":
    // 不展示 Apple Pay
    hideApplePay();
    break;
}

场景:决定在结账页面上 Apple Pay 按钮的展示策略。坑:canMakePayments() 如果返回 true,你必须显示 Apple Pay 按钮——这是苹果的使用规范。

Web 端 Funds Transfer(提现)

const paymentRequest = {
  countryCode: "US",
  currencyCode: "USD",
  merchantCapabilities: ["supports3DS", "supportsInstantFundsOut"],
  paymentMethodData: {
    supportedNetworks: ["visa", "masterCard"],
  },
  // 提现不需要配送
  requestShipping: false,
  modifiers: [{
    additionalLineItems: [
      { label: "账户余额", amount: "100.00", type: "final" },
      { label: "即时提现手续费", amount: "1.50", type: "instantFundsOutFee" },
      { label: "到账金额", amount: "98.50", type: "disbursement" }
    ],
    // 即使不需要收件人信息,也必须有 disbursementRequest 对象
    disbursementRequest: {}
  }]
};

场景:在 web 上实现提现功能。坑:即使不收手续费,instantFundsOutFee 行项也必须存在,金额设为 0。

最佳实践

新项目:直接用 Apple Pay JS SDK 1.2.0+,不要用 CSS 按钮实现。用 applePayCapabilities() 决定按钮展示策略,替代 canMakePaymentsWithActiveCard()。如果你的产品有余额提现场景,在 web 端也加上 disbursement 支持。

已有项目:如果你已经集成了 Apple Pay on the web,改动很小——把 SDK 版本升到 1.2.0+,把 CSS 按钮换成 SDK 组件,用 applePayCapabilities() 替换旧的检测逻辑。服务端代码完全不需要动。苹果特别强调了”如果你之前只用了 canMakePayments() 且返回 true 时已经展示了按钮”,那你什么都不用改,功能自动生效。

还有什么值得关注

  • W3C Payment Request API 在部分浏览器上不支持 Apple Pay,如果你的集成基于 W3C 标准,需要注意兼容性。
  • Apple Pay 的 Acceptable Use Guidelines 和 HIG 对按钮展示位置有明确规范,值得重新检查一遍。
  • 提现功能需要和支付处理方确认他们是否支持 disbursement,不是所有支付网关都支持。
WWDC 2024