瞭解如何更新 Android 付款應用程式,透過 Web Payments API 提供運送地址和付款人聯絡資訊。
發布日期:2020 年 7 月 17 日,上次更新時間:2025 年 5 月 27 日
透過網路表單輸入運送地址和聯絡資訊,對消費者來說可能相當麻煩。這可能會導致錯誤,並降低轉換率。
因此,Payment Request API 支援要求運送地址和聯絡資訊的功能。這項功能有許多優點:
- 使用者只要輕觸幾下,就能選取正確地址。
- 地址一律會以標準化格式傳回。
- 減少提交錯誤地址的機率。
瀏覽器可將運送地址和聯絡資訊的收集作業延後至付款應用程式,提供統一的付款體驗。這項功能稱為「委派」。
Chrome 會盡可能將收集顧客運送地址和聯絡資訊的作業,委派給叫用的 Android 付款應用程式。這項委派作業可減少結帳過程中的阻礙。
商家網站可根據顧客選擇的運送地址和運送選項,動態更新運送選項和總價。
如要為現有的 Android 付款應用程式新增委派支援,請按照下列步驟操作:
宣告支援的委派項目
瀏覽器需要知道付款應用程式可提供的額外資訊清單,才能將收集該資訊的作業委派給您的應用程式。請在應用程式的 AndroidManifest.xml 中,以 <meta-data>
形式宣告支援的委派作業。
<activity
android:name=".PaymentActivity"
…
<meta-data
android:name="org.chromium.payment_supported_delegations"
android:resource="@array/chromium_payment_supported_delegations" />
</activity>
android:resource
必須指向 <string-array>
,其中包含下列所有或部分值:
payerName
payerEmail
payerPhone
shippingAddress
以下範例只能提供運送地址和付款人的電子郵件地址。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="chromium_payment_supported_delegations">
<item>payerEmail</item>
<item>shippingAddress</item>
</string-array>
</resources>
剖析 PAY
意圖額外項目,取得必要付款方式
商家可以使用 paymentOptions
字典指定其他必要資訊。Chrome 會提供應用程式可透過將 paymentOptions
Intent extras
傳遞至 PAY
活動來提供的必要選項清單。
paymentOptions
paymentOptions
是商家指定的付款方式子集,您的應用程式已聲明支援委派。
Kotlin
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")
Java
Bundle paymentOptions = extras.getBundle("paymentOptions");
if (paymentOptions != null) {
Boolean requestPayerName = paymentOptions.getBoolean("requestPayerName");
Boolean requestPayerPhone = paymentOptions.getBoolean("requestPayerPhone");
Boolean requestPayerEmail = paymentOptions.getBoolean("requestPayerEmail");
Boolean requestShipping = paymentOptions.getBoolean("requestShipping");
String shippingType = paymentOptions.getString("shippingType");
}
可包含下列參數:
requestPayerName
- 布林值,指出是否需要付款人姓名。requestPayerPhone
- 布林值,指出是否需要付款人的電話號碼。requestPayerEmail
- 布林值,指出是否需要付款人的電子郵件地址。requestShipping
:布林值,指出是否需要運送資訊。shippingType
:顯示運送類型的字串。運送類型可以是"shipping"
、"delivery"
或"pickup"
。應用程式在要求使用者提供地址或選擇運送方式時,可以在 UI 中使用這項提示。
shippingOptions
shippingOptions
是商家指定運送選項的可封裝陣列。只有在 paymentOptions.requestShipping ==
true
時,這個參數才會存在。
Kotlin
val shippingOptions: List<ShippingOption>? =
extras.getParcelableArray("shippingOptions")?.mapNotNull {
p -> from(p as Bundle)
}
Java
Parcelable[] shippingOptions = extras.getParcelableArray("shippingOptions");
for (Parcelable it : shippingOptions) {
if (it != null && it instanceof Bundle) {
Bundle shippingOption = (Bundle) it;
}
}
每個運送選項都是 Bundle
,包含下列鍵。
id
- 運送選項 ID。label
- 向使用者顯示的運送選項標籤。amount
- 運費組合,包含currency
和value
鍵,以及字串值。selected
- 運送選項是否應在付款應用程式顯示運送選項時選取。
除了 selected
以外的所有鍵都有字串值。selected
具有布林值。
Kotlin
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)
Java
String id = bundle.getString("id");
String label = bundle.getString("label");
Bundle amount = bundle.getBundle("amount");
Boolean selected = bundle.getBoolean("selected", false);
在付款回覆中提供必要資訊
應用程式應在 PAY
活動的回應中加入必要額外資訊。
如要這麼做,必須將下列參數指定為 Intent 額外資訊:
payerName
- 付款人的全名。如果paymentOptions.requestPayerName
為 true,則此值不得為空字串。payerPhone
- 付款者的電話號碼。如果paymentOptions.requestPayerPhone
為 true,則此值不得為空字串。payerEmail
- 付款人的電子郵件地址。如果paymentOptions.requestPayerEmail
為 true,則此值不得為空字串。shippingAddress
- 使用者提供的運送地址。如果paymentOptions.requestShipping
為 true,則此值不得為空白套裝組合。這個組合應包含下列鍵,代表實體地址的不同部分。countryCode
postalCode
sortingCode
region
city
dependentLocality
addressLine
organization
recipient
phone
除了addressLine
以外,所有鍵都有字串值。addressLine
是字串陣列。
shippingOptionId
- 使用者所選運送選項的 ID。如果paymentOptions.requestShipping
為 true,這個值就不得為空字串。
驗證付款回應
如果從叫用的付款應用程式收到的付款回應活動結果設為 RESULT_OK
,Chrome 會檢查額外資訊中是否有必要資訊。如果驗證失敗,Chrome 會從 request.show()
傳回遭拒的 Promise,並顯示下列其中一個開發人員適用的錯誤訊息:
'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".'
以下是有效回應的程式碼範例:
Kotlin
fun Intent.populateRequestedPaymentOptions() {
if (requestPayerName) {
putExtra("payerName", "John Smith")
}
if (requestPayerPhone) {
putExtra("payerPhone", "5555555555")
}
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", "5555555555")
putExtra("shippingAddress", address)
putExtra("shippingOptionId", "standard")
}
}
Java
private Intent populateRequestedPaymentOptions() {
Intent result = new Intent();
if (requestPayerName) {
result.putExtra("payerName", "John Smith");
}
if (requestPayerPhone) {
presult.utExtra("payerPhone", "5555555555");
}
if (requestPayerEmail) {
result.putExtra("payerEmail", "john.smith@gmail.com");
}
if (requestShipping) {
Bundle address = new Bundle();
address.putExtra("countryCode", "CA");
address.putExtra("postalCode", "M5H2G4");
address.putExtra("region", "Ontario");
address.putExtra("city", "Toronto");
String[] addressLines = new String[] {"111 Richmond st. West"};
address.putExtra("addressLines", addressLines);
address.putExtra("recipient", "John Smith");
address.putExtra("phone", "5555555555");
result.putExtra("shippingAddress", address);
result.putExtra("shippingOptionId", "standard");
}
return result;
}
選用:支援動態流程
有時交易總費用會增加,例如使用者選擇快遞運送選項,或是使用者選擇國際運送地址時,可用的運送選項或價格清單有所變更。如果應用程式提供使用者選取的運送地址或選項,就應能通知商家運送地址或選項的任何變更,並向使用者顯示更新後的付款詳細資料 (由商家提供)。
如要通知商家新變更,請實作 IPaymentDetailsUpdateServiceCallback
介面,並在 AndroidManifest.xml
中使用 UPDATE_PAYMENT_DETAILS
意圖篩選器宣告。
叫用 PAY
意圖後,Chrome 會立即連線至與 PAY
意圖位於相同套件中的 UPDATE_PAYMENT_DETAILS
服務 (如有),並呼叫 setPaymentDetailsUpdateService(service)
,向付款應用程式提供 IPaymentDetailsUpdateService
端點,以便在使用者付款方式、運送選項或運送地址有異動時通知應用程式。
接收跨程序通訊 (IPC) 時,請使用 packageManager.getPackagesForUid(Binder.getCallingUid())
驗證叫用 PAY
意圖的應用程式,是否與叫用 IPaymentDetailsUpdateServiceCallback
方法的應用程式具有相同的套件名稱。
AIDL
建立兩個 AIDL 檔案,並加入以下內容:
org/chromium/components/payments/IPaymentDetailsUpdateServiceCallback.aidl
package org.chromium.components.payments;
import android.os.Bundle;
import org.chromium.components.payments.IPaymentDetailsUpdateService;
interface IPaymentDetailsUpdateServiceCallback {
oneway void updateWith(in Bundle updatedPaymentDetails);
oneway void paymentDetailsNotUpdated();
oneway void setPaymentDetailsUpdateService(IPaymentDetailsUpdateService service);
}
org/chromium/components/payments/IPaymentDetailsUpdateService.aidl
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);
}
服務
實作 IPaymentDetailsUpdateServiceCallback
服務。
Kotlin
class SampleUpdatePaymentDetailsCallbackService : Service() {
private val binder = object : IPaymentDetailsUpdateServiceCallback.Stub() {
override fun updateWith(updatedPaymentDetails: Bundle) {}
override fun paymentDetailsNotUpdated() {}
override fun setPaymentDetailsUpdateService(service: IPaymentDetailsUpdateService) {}
}
override fun onBind(intent: Intent?): IBinder? {
return binder
}
}
Java
import org.chromium.components.paymsnts.IPaymentDetailsUpdateServiceCallback;
public class SampleUpdatePaymentDetailsCallbackService extends Service {
private final IPaymentDetailsUpdateServiceCallback.Stub mBinder =
new IPaymentDetailsUpdateServiceCallback.Stub() {
@Override
public void updateWith(Bundle updatedPaymentDetails) {}
@Override
public void paymentDetailsNotUpdated() {}
@Override
public void setPaymentDetailsUpdateService(IPaymentDetailsUpdateService service) {}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
AndroidManifest.xml
在 AndroidManifest.xml
中公開 IPaymentDetailsUpdateServiceCallback
的服務。
<service
android:name=".SampleUpdatePaymentDetailsCallbackService"
android:exported="true">
<intent-filter>
<action android:name="org.chromium.intent.action.UPDATE_PAYMENT_DETAILS" />
</intent-filter>
</service>
通知商家使用者選取的付款方式、運送地址或運送選項有變更
Kotlin
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
}
Java
if (service == null) {
return;
}
try {
if (isOptionChange) {
service.changeShippingOption(selectedOptionId, callback);
} else (isAddressChange) {
service.changeShippingAddress(selectedAddress, callback);
} else {
service.changePaymentMethod(methodData, callback);
}
} catch (RemoteException e) {
// Handle the remote exception
}
changePaymentMethod
通知商家使用者所選付款方式的變更。paymentHandlerMethodData
組合包含 methodName
和選用的 details
鍵,兩者都具有字串值。Chrome 會檢查是否為非空白的套件,且包含非空白的 methodName
,如果驗證失敗,則會使用 callback.updateWith
傳送 updatePaymentDetails
,並附上下列其中一個錯誤訊息。
'Method data required.'
'Method name required.'
changeShippingOption
通知商家使用者選取的運送選項有異動。
shippingOptionId
應為商家指定運送選項的其中一個 ID。Chrome 會檢查 shippingOptionId
是否為空白,如果驗證失敗,則會使用 callback.updateWith
傳送 updatePaymentDetails
,並附上以下錯誤訊息。
'Shipping option identifier required.'
changeShippingAddress
通知商家使用者提供的運送地址有異動。Chrome 會檢查是否有包含有效 countryCode
的非空白 shippingAddress
套件,如果驗證失敗,則會使用 callback.updateWith
傳送 updatePaymentDetails
,並顯示下列錯誤訊息。
'Payment app returned invalid shipping address in response.'
無效的州/省錯誤訊息
如果 Chrome 在收到任何變更要求時遇到無效狀態,就會使用經過修訂的 updatePaymentDetails
套件呼叫 callback.updateWith
。組合只會包含索引為 "Invalid state"
的 error
鍵。無效狀態的例子包括:
- Chrome 仍在等待商家對先前的變更做出回應 (例如進行中的變更事件)。
- 付款應用程式提供的運送選項 ID 不屬於任何商家指定的運送選項。
接收商家更新的付款詳細資料
Kotlin
override fun updateWith(updatedPaymentDetails: Bundle) {}
override fun paymentDetailsNotUpdated() {}
Java
@Override
public void updateWith(Bundle updatedPaymentDetails) {}
@Override
public void paymentDetailsNotUpdated() {}
updatedPaymentDetails
是與 PaymentRequestDetailsUpdate
WebIDL 字典對應的組合,並包含下列選用鍵:
total
- 包含currency
和value
鍵的組合,兩個鍵都有字串值shippingOptions
- shipping options 的可封送陣列error
- 包含一般錯誤訊息的字串 (例如,當changeShippingOption
未提供有效的運送選項 ID 時)stringifiedPaymentMethodErrors
:代表付款方式驗證錯誤的 JSON 字串addressErrors
- 組合,內含與 shipping address 相同的選用鍵和字串值。每個鍵都代表與運送地址相應部分相關的驗證錯誤。modifiers
- 包含多個可封送處理的 Bundle 的陣列,每個 Bundle 都含有total
和methodData
欄位,這些欄位也是 Bundle。
如果缺少鍵,表示值未變更。