如何使用 Web Payments API 更新您的 Android 付款应用,以提供送货地址和付款人联系信息。
通过网络表单输入收货地址和联系信息 为客户带来繁琐的体验这可能会导致错误并降低转化率 。
正因如此,Payment Request API 支持请求运费的功能 地址和联系信息这样做有诸多好处:
- 用户只需点按几下就能选择正确的地址。
- 地址始终以标准化 格式。
- 提交错误的地址不太可能会发生。
浏览器可以延迟收集送货地址和联系信息, 付款应用,以提供统一的付款体验。此功能是 称为委托。
Chrome 会尽可能委托客户收取运费 调用的 Android 付款应用的地址和联系信息。通过 委托可减少结账过程中的不便
商家网站可以动态更新运费选项和总价 具体取决于客户选择的送货地址和送货方式 选项。
<ph type="x-smartling-placeholder">要为现有的 Android 付款应用添加委托支持,请按以下步骤操作: 实现以下步骤:
- 声明支持的委托。
- 解析了所需付款的
PAY
intent extra 选项。 - 提供付款所需的信息 响应。
- [可选] 支持动态流程: <ph type="x-smartling-placeholder">
声明支持的委托
浏览器需要知道您的付款
以便其将收集该信息的权限委托给
应用。在应用的<meta-data>
AndroidManifest.xml。
<activity
android:name=".PaymentActivity"
…
<meta-data
android:name="org.chromium.payment_supported_delegations"
android:resource="@array/supported_delegations" />
</activity>
<resource>
必须是从以下有效值中选择的字符串列表:
[ "payerName", "payerEmail", "payerPhone", "shippingAddress" ]
以下示例只能提供送货地址和付款人的电子邮件地址 地址。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="supported_delegations">
<item>payerEmail</item>
<item>shippingAddress</item>
</string-array>
</resources>
解析了 PAY
intent extra 以了解必需的付款方式
商家可以使用
paymentOptions
字典。Chrome 将提供一系列必需选项,
将以下参数作为 intent 传递给 PAY
activity 来提供
extra。
paymentOptions
paymentOptions
是部分商家指定的付款方式,
您的应用声明了委托支持功能。
val paymentOptions: Bundle? = extras.getBundle("paymentOptions")
val requestPayerName: Boolean? = paymentOptions?.getBoolean("requestPayerName")
val requestPayerPhone: Boolean? = paymentOptions?.getBoolean("requestPayerPhone")
val requestPayerEmail: Boolean? = paymentOptions?.getBoolean("requestPayerEmail")
val requestShipping: Boolean? = paymentOptions?.getBoolean("requestShipping")
val shippingType: String? = paymentOptions?.getString("shippingType")
它可以包含以下参数:
requestPayerName
- 指示付款人姓名的布尔值 为必填字段。requestPayerPhone
- 布尔值,指示付款人的手机是否 为必填字段。requestPayerEmail
- 布尔值,指示付款人的电子邮件是否 为必填字段。requestShipping
- 指示是否提供配送信息的布尔值 为必填字段。shippingType
- 显示运费类型的字符串。配送类型可以是"shipping"
、"delivery"
或"pickup"
。您的应用可以在其 询问用户的地址或配送选项时的界面。
shippingOptions
shippingOptions
是商家指定运费的 Parcelable 数组
选项。只有当 paymentOptions.requestShipping ==
true
时,此参数才存在。
val shippingOptions: List<ShippingOption>? =
extras.getParcelableArray("shippingOptions")?.mapNotNull {
p -> from(p as Bundle)
}
每个运费选项都是一个 Bundle
,其中包含以下键。
id
- 送货方式标识符。label
- 向用户显示的配送选项标签。amount
- 运费捆绑包包含currency
和value
键, 字符串值。currency
显示运费的币种,采用 ISO4217 格式正确 3 个字母的字母代码value
显示运费的值,以有效的小数货币表示 值
selected
- 选择运费选项时, 付款应用会显示运费选项。
除 selected
之外的所有键都具有字符串值。“selected
”包含一个布尔值
值。
val id: String = bundle.getString("id")
val label: String = bundle.getString("label")
val amount: Bundle = bundle.getBundle("amount")
val selected: Boolean = bundle.getBoolean("selected", false)
在付款响应中提供所需信息
您的应用应在对
PAY
activity。
为此,必须将以下参数指定为 intent extra:
payerName
- 付款人的全名。在下列情况下,它应该是非空字符串paymentOptions.requestPayerName
为 true。payerPhone
- 付款人的电话号码。在下列情况下,它应该是非空字符串paymentOptions.requestPayerPhone
为 true。payerEmail
- 付款人的电子邮件地址。它应该是非空字符串 当paymentOptions.requestPayerEmail
为 true 时。shippingAddress
- 用户提供的送货地址。它应该是 当paymentOptions.requestShipping
为 true 时,非空 bundle。套装 应包含以下键,这些键分别代表物理 地址。city
countryCode
dependentLocality
organization
phone
postalCode
recipient
region
sortingCode
addressLine
除addressLine
之外的所有键都具有字符串值。addressLine
是一个字符串数组。
shippingOptionId
- 用户选择的运费选项的标识符。这个 当paymentOptions.requestShipping
为 true 时,它应该是非空字符串。
验证付款响应
如果从调用的付款收到付款响应的活动结果
应用设置为 RESULT_OK
,则 Chrome 会检查是否有必需的额外
。如果验证失败,Chrome 会返回“已拒绝”
promise 中包含下列面向开发者的以下错误之一:request.show()
消息:
'Payment app returned invalid response. Missing field "payerEmail".'
'Payment app returned invalid response. Missing field "payerName".'
'Payment app returned invalid response. Missing field "payerPhone".'
'Payment app returned invalid shipping address in response.'
'... is not a valid CLDR country code, should be 2 upper case letters [A-Z]'
'Payment app returned invalid response. Missing field "shipping option".'
以下代码示例为有效响应的示例:
fun Intent.populateRequestedPaymentOptions() {
if (requestPayerName) {
putExtra("payerName", "John Smith")
}
if (requestPayerPhone) {
putExtra("payerPhone", "4169158200")
}
if (requestPayerEmail) {
putExtra("payerEmail", "john.smith@gmail.com")
}
if(requestShipping) {
val address: Bundle = Bundle()
address.putString("countryCode", "CA")
val addressLines: Array<String> =
arrayOf<String>("111 Richmond st. West")
address.putStringArray("addressLines", addressLines)
address.putString("region", "Ontario")
address.putString("city", "Toronto")
address.putString("postalCode", "M5H2G4")
address.putString("recipient", "John Smith")
address.putString("phone", "4169158200")
putExtra("shippingAddress", address)
putExtra("shippingOptionId", "standard")
}
}
可选:支持动态流程
有时交易的总费用会增加,比如当用户 选择“快递”选项 选项或其价格会随着用户选择跨国送货而发生变化 地址。当应用提供用户选择的送货地址或选项时, 应该能够通知商家有关任何送货地址或选项的信息 更改并向用户显示更新后的付款明细(由 商家)。
AIDL
如需通知商家有关新更改的信息,请使用PaymentDetailsUpdateService
Chrome 的 AndroidManifest.xml 中声明的服务。要使用此服务,请创建两个
包含以下内容的 AIDL 文件:
app/src/main/aidl/org/chromium/components/payments/IPaymentDetailsUpdateService
package org.chromium.components.payments;
import android.os.Bundle;
interface IPaymentDetailsUpdateServiceCallback {
oneway void updateWith(in Bundle updatedPaymentDetails);
oneway void paymentDetailsNotUpdated();
}
app/src/main/aidl/org/chromium/components/payments/IPaymentDetailsUpdateServiceCallback
package org.chromium.components.payments;
import android.os.Bundle;
import org.chromium.components.payments.IPaymentDetailsUpdateServiceCallback;
interface IPaymentDetailsUpdateService {
oneway void changePaymentMethod(in Bundle paymentHandlerMethodData,
IPaymentDetailsUpdateServiceCallback callback);
oneway void changeShippingOption(in String shippingOptionId,
IPaymentDetailsUpdateServiceCallback callback);
oneway void changeShippingAddress(in Bundle shippingAddress,
IPaymentDetailsUpdateServiceCallback callback);
}
通知商家用户所选付款方式、送货地址或运费选项的变化
private fun bind() {
// The action is introduced in Chrome version 92, which supports the service in Chrome
// and other browsers (e.g., WebLayer).
val newIntent = Intent("org.chromium.intent.action.UPDATE_PAYMENT_DETAILS")
.setPackage(callingBrowserPackage)
if (packageManager.resolveService(newIntent, PackageManager.GET_RESOLVED_FILTER) == null) {
// Fallback to Chrome-only approach.
newIntent.setClassName(
callingBrowserPackage,
"org.chromium.components.payments.PaymentDetailsUpdateService")
newIntent.action = IPaymentDetailsUpdateService::class.java.name
}
isBound = bindService(newIntent, connection, Context.BIND_AUTO_CREATE)
}
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val service = IPaymentDetailsUpdateService.Stub.asInterface(service)
try {
if (isOptionChange) {
service?.changeShippingOption(selectedOptionId, callback)
} else (isAddressChange) {
service?.changeShippingAddress(selectedAddress, callback)
} else {
service?.changePaymentMethod(methodData, callback)
}
} catch (e: RemoteException) {
// Handle the remote exception
}
}
}
用于服务启动 intent 的 callingPackageName
可以具有下列其中一项:
以下值,具体取决于发起付款的浏览器
请求。
Chrome 渠道 | 软件包名称 |
---|---|
稳定 |
"com.android.chrome"
|
测试版 |
"com.chrome.beta"
|
Dev |
"com.chrome.dev"
|
Canary 版 |
"com.chrome.canary"
|
Chromium |
"org.chromium.chrome"
|
Google 快速搜索框(一种 WebLayer 嵌入器) |
"com.google.android.googlequicksearchbox"
|
changePaymentMethod
在用户选择的付款方式发生变化时通知商家。通过
“paymentHandlerMethodData
”套装包含“methodName
”和可选的details
键和字符串值。Chrome 会检查是否有包含
非空 methodName
,并发送 updatePaymentDetails
,其中包含其中一个
通过 callback.updateWith
发送以下错误消息。
'Method data required.'
'Method name required.'
changeShippingOption
通知商家用户选择的配送选项的变化。
shippingOptionId
应该是某个商家指定的
运费选项。Chrome 将检查是否有非空 shippingOptionId
并发送
通过updatePaymentDetails
如果验证失败,则返回 callback.updateWith
。
'Shipping option identifier required.'
changeShippingAddress
通知商家用户提供的送货地址的变化。Chrome 浏览器
将检查是否有包含有效 countryCode
的非空 shippingAddress
bundle
并通过updatePaymentDetails
如果验证失败,则返回 callback.updateWith
。
'Payment app returned invalid shipping address in response.'
“状态无效”错误消息
Chrome 在收到任何更改请求时遇到无效状态
它将调用 callback.updateWith
,其中 updatePaymentDetails
已隐去
软件包。该 bundle 将仅包含具有 "Invalid state"
的 error
键。
无效状态的示例如下:
- Chrome 仍在等待商家对上一次更改做出的响应时 (例如进行中的更改事件)。
- 付款应用提供的配送选项标识符不属于以下任何一项: 商家指定的运费选项。
从商家接收更新后的付款信息
private fun unbind() {
if (isBound) {
unbindService(connection)
isBound = false
}
}
private val callback: IPaymentDetailsUpdateServiceCallback =
object : IPaymentDetailsUpdateServiceCallback.Stub() {
override fun paymentDetailsNotUpdated() {
// Payment request details have not changed.
unbind()
}
override fun updateWith(updatedPaymentDetails: Bundle) {
newPaymentDetails = updatedPaymentDetails
unbind()
}
}
updatePaymentDetails
是等效于
PaymentRequestDetailsUpdate
WebIDL 字典(隐去
modifiers
字段),并包含以下可选键:
total
- 包含currency
和value
键的 bundle,这两个键都具有 字符串值shippingOptions
- shipping [运费] 的 Parcelable 数组 选项error
- 包含一般错误消息的字符串(例如,changeShippingOption
未提供有效的送货方式标识符)stringifiedPaymentMethodErrors
- 表示验证的 JSON 字符串 付款方式错误addressErrors
- 包含与 shipping [运费] 属性相同的可选键的套装 地址和字符串 值。每个键都表示一个与其对应的 部分。
如果缺少键,则意味着该键的值未更改。