Cách cập nhật ứng dụng thanh toán Android để cung cấp địa chỉ giao hàng và thông tin liên hệ của người thanh toán bằng API Thanh toán trên web.
Ngày xuất bản: 17 tháng 7 năm 2020, Ngày cập nhật gần đây nhất: 27 tháng 5 năm 2025
Việc nhập địa chỉ giao hàng và thông tin liên hệ thông qua biểu mẫu trên web có thể gây phiền hà cho khách hàng. Điều này có thể gây ra lỗi và làm giảm tỷ lệ chuyển đổi.
Đó là lý do Payment Request API hỗ trợ tính năng yêu cầu địa chỉ giao hàng và thông tin liên hệ. Điều này mang lại nhiều lợi ích:
- Người dùng có thể chọn địa chỉ phù hợp chỉ bằng vài lần nhấn.
- Địa chỉ luôn được trả về ở định dạng chuẩn hoá.
- Bạn ít có khả năng gửi nhầm địa chỉ.
Trình duyệt có thể trì hoãn việc thu thập địa chỉ giao hàng và thông tin liên hệ cho một ứng dụng thanh toán để mang lại trải nghiệm thanh toán hợp nhất. Chức năng này được gọi là uỷ quyền.
Bất cứ khi nào có thể, Chrome sẽ uỷ quyền việc thu thập địa chỉ giao hàng và thông tin liên hệ của khách hàng cho ứng dụng thanh toán Android được gọi. Việc uỷ quyền này giúp giảm sự phiền hà trong quá trình thanh toán.
Trang web của người bán có thể tự động cập nhật các lựa chọn vận chuyển và tổng giá tuỳ thuộc vào địa chỉ giao hàng và lựa chọn giao hàng mà khách hàng chọn.
Để thêm tính năng hỗ trợ uỷ quyền vào một ứng dụng thanh toán Android hiện có, hãy triển khai các bước sau:
- Khai báo các hoạt động uỷ quyền được hỗ trợ.
- Phân tích cú pháp các tuỳ chọn bổ sung về ý định
PAY
cho các tuỳ chọn thanh toán bắt buộc. - Cung cấp thông tin bắt buộc trong phản hồi thanh toán.
- [Không bắt buộc] Hỗ trợ luồng động:
Khai báo các hoạt động uỷ quyền được hỗ trợ
Trình duyệt cần biết danh sách thông tin bổ sung mà ứng dụng thanh toán của bạn có thể cung cấp để có thể uỷ quyền thu thập thông tin đó cho ứng dụng. Khai báo các uỷ quyền được hỗ trợ dưới dạng <meta-data>
trong AndroidManifest.xml của ứng dụng.
<activity
android:name=".PaymentActivity"
…
<meta-data
android:name="org.chromium.payment_supported_delegations"
android:resource="@array/chromium_payment_supported_delegations" />
</activity>
android:resource
phải trỏ đến một <string-array>
chứa tất cả hoặc một tập hợp con các giá trị sau:
payerName
payerEmail
payerPhone
shippingAddress
Ví dụ sau đây chỉ có thể cung cấp địa chỉ giao hàng và địa chỉ email của người thanh toán.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="chromium_payment_supported_delegations">
<item>payerEmail</item>
<item>shippingAddress</item>
</string-array>
</resources>
Phân tích cú pháp các ý định bổ sung PAY
cho các phương thức thanh toán bắt buộc
Người bán có thể chỉ định thêm thông tin bắt buộc bằng cách sử dụng từ điển paymentOptions
. Chrome sẽ cung cấp danh sách các tuỳ chọn bắt buộc mà ứng dụng của bạn có thể cung cấp bằng cách truyền paymentOptions
Thông tin bổ sung về ý định đến hoạt động PAY
.
paymentOptions
paymentOptions
là tập hợp con của các phương thức thanh toán do người bán chỉ định mà ứng dụng của bạn đã khai báo hỗ trợ uỷ quyền.
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");
}
Tệp này có thể bao gồm các tham số sau:
requestPayerName
– Giá trị boolean cho biết tên của người thanh toán có bắt buộc hay không.requestPayerPhone
– Giá trị boolean cho biết liệu có bắt buộc phải có điện thoại của người thanh toán hay không.requestPayerEmail
– Giá trị boolean cho biết email của người thanh toán có bắt buộc hay không.requestShipping
– Giá trị boolean cho biết liệu có bắt buộc phải cung cấp thông tin vận chuyển hay không.shippingType
– Chuỗi cho biết loại hình vận chuyển. Loại hình vận chuyển có thể là"shipping"
,"delivery"
hoặc"pickup"
. Ứng dụng của bạn có thể sử dụng gợi ý này trong giao diện người dùng khi yêu cầu địa chỉ của người dùng hoặc lựa chọn phương thức vận chuyển.
shippingOptions
shippingOptions
là mảng có thể phân phối các lựa chọn vận chuyển do người bán chỉ định. Tham số này sẽ chỉ tồn tại khi 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;
}
}
Mỗi phương thức vận chuyển là một Bundle
có các khoá sau.
id
– Giá trị nhận dạng phương thức vận chuyển.label
– Nhãn lựa chọn vận chuyển hiển thị cho người dùng.amount
– Gói chi phí vận chuyển chứa các khoácurrency
vàvalue
có giá trị chuỗi.currency
cho biết đơn vị tiền tệ của phí vận chuyển, dưới dạng mã bảng chữ cái ISO4217 gồm 3 chữ cái được định dạng đúng cáchvalue
cho biết giá trị của phí vận chuyển, dưới dạng giá trị tiền tệ thập phân hợp lệ
selected
– Liệu có nên chọn phương thức vận chuyển khi ứng dụng thanh toán hiển thị các phương thức vận chuyển hay không.
Tất cả các khoá khác ngoài selected
đều có giá trị chuỗi. selected
có giá trị boolean.
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);
Cung cấp thông tin bắt buộc trong phản hồi thanh toán
Ứng dụng của bạn phải đưa thông tin bổ sung bắt buộc vào phản hồi của ứng dụng đối với hoạt động PAY
.
Để làm như vậy, bạn phải chỉ định các tham số sau dưới dạng thông tin bổ sung về Ý định:
payerName
– Họ và tên của người thanh toán. Đây phải là một chuỗi không trống khipaymentOptions.requestPayerName
là true.payerPhone
– Số điện thoại của người thanh toán. Đây phải là một chuỗi không trống khipaymentOptions.requestPayerPhone
là true.payerEmail
– Địa chỉ email của người thanh toán. Đây phải là một chuỗi không trống khipaymentOptions.requestPayerEmail
là true.shippingAddress
– Địa chỉ giao hàng do người dùng cung cấp. Đây phải là một gói không trống khipaymentOptions.requestShipping
là true. Gói này phải có các khoá sau đây đại diện cho các phần khác nhau trong một địa chỉ thực.countryCode
postalCode
sortingCode
region
city
dependentLocality
addressLine
organization
recipient
phone
Tất cả các khoá khác ngoàiaddressLine
đều có giá trị chuỗi.addressLine
là một mảng chuỗi.
shippingOptionId
– Giá trị nhận dạng của phương thức vận chuyển do người dùng chọn. Đây phải là một chuỗi không trống khipaymentOptions.requestShipping
là true.
Xác thực phản hồi thanh toán
Nếu kết quả hoạt động của phản hồi thanh toán nhận được từ ứng dụng thanh toán được gọi là RESULT_OK
, thì Chrome sẽ kiểm tra thông tin bổ sung bắt buộc trong các phần bổ sung của ứng dụng đó. Nếu không xác thực được, Chrome sẽ trả về một lời hứa bị từ chối từ request.show()
kèm theo một trong các thông báo lỗi sau đây dành cho nhà phát triển:
'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".'
Mã mẫu sau đây là ví dụ về một phản hồi hợp lệ:
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;
}
Không bắt buộc: Hỗ trợ luồng động
Đôi khi, tổng chi phí của một giao dịch sẽ tăng lên, chẳng hạn như khi người dùng chọn phương thức giao hàng nhanh hoặc khi danh sách các phương thức giao hàng hiện có hoặc giá của các phương thức đó thay đổi khi người dùng chọn địa chỉ giao hàng quốc tế. Khi cung cấp địa chỉ hoặc phương thức giao hàng do người dùng chọn, ứng dụng của bạn phải có thể thông báo cho người bán về mọi thay đổi đối với địa chỉ hoặc phương thức giao hàng và hiển thị cho người dùng thông tin thanh toán mới nhất (do người bán cung cấp).
Để thông báo cho người bán về các thay đổi mới, hãy triển khai giao diện IPaymentDetailsUpdateServiceCallback
và khai báo giao diện đó trong AndroidManifest.xml
bằng bộ lọc ý định UPDATE_PAYMENT_DETAILS
.
Ngay sau khi gọi ý định PAY
, Chrome sẽ kết nối với dịch vụ UPDATE_PAYMENT_DETAILS
(nếu có) trong cùng một gói với ý định PAY
và sẽ gọi setPaymentDetailsUpdateService(service)
để cung cấp điểm cuối IPaymentDetailsUpdateService
cho ứng dụng thanh toán của bạn nhằm thông báo về các thay đổi đối với phương thức thanh toán, phương thức giao hàng hoặc địa chỉ giao hàng của người dùng.
Sử dụng packageManager.getPackagesForUid(Binder.getCallingUid())
khi nhận được Thông tin liên lạc giữa các quy trình (IPC) để xác thực rằng ứng dụng đã gọi ý định PAY
có cùng tên gói với ứng dụng đã gọi các phương thức IPaymentDetailsUpdateServiceCallback
.
AIDL
Tạo hai tệp AIDL có nội dung sau:
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);
}
Dịch vụ
Triển khai dịch vụ 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
Hiển thị dịch vụ cho IPaymentDetailsUpdateServiceCallback
trong AndroidManifest.xml
.
<service
android:name=".SampleUpdatePaymentDetailsCallbackService"
android:exported="true">
<intent-filter>
<action android:name="org.chromium.intent.action.UPDATE_PAYMENT_DETAILS" />
</intent-filter>
</service>
Thông báo cho người bán về những thay đổi đối với phương thức thanh toán, địa chỉ giao hàng hoặc phương thức giao hàng mà người dùng đã chọn
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
Thông báo cho người bán về những thay đổi đối với phương thức thanh toán do người dùng chọn. Gói paymentHandlerMethodData
chứa khoá methodName
và khoá details
tuỳ chọn, cả hai đều có giá trị chuỗi. Chrome sẽ kiểm tra một gói không trống có methodName
không trống và gửi updatePaymentDetails
kèm theo một trong các thông báo lỗi sau qua callback.updateWith
nếu không xác thực được.
'Method data required.'
'Method name required.'
changeShippingOption
Thông báo cho người bán về những thay đổi đối với phương thức giao hàng mà người dùng đã chọn.
shippingOptionId
phải là giá trị nhận dạng của một trong các tuỳ chọn vận chuyển do người bán chỉ định. Chrome sẽ kiểm tra shippingOptionId
không trống và gửi updatePaymentDetails
kèm theo thông báo lỗi sau đây qua callback.updateWith
nếu không xác thực được.
'Shipping option identifier required.'
changeShippingAddress
Thông báo cho người bán về những thay đổi trong địa chỉ giao hàng do người dùng cung cấp. Chrome sẽ kiểm tra một gói shippingAddress
không trống có countryCode
hợp lệ và gửi updatePaymentDetails
kèm theo thông báo lỗi sau đây qua callback.updateWith
nếu không xác thực được.
'Payment app returned invalid shipping address in response.'
Thông báo lỗi trạng thái không hợp lệ
Nếu gặp trạng thái không hợp lệ khi nhận được bất kỳ yêu cầu thay đổi nào, Chrome sẽ gọi callback.updateWith
bằng gói updatePaymentDetails
đã bị loại bỏ. Gói này sẽ chỉ chứa khoá error
với "Invalid state"
.
Sau đây là ví dụ về trạng thái không hợp lệ:
- Khi Chrome vẫn đang chờ phản hồi của người bán về một thay đổi trước đó (chẳng hạn như một sự kiện thay đổi đang diễn ra).
- Giá trị nhận dạng phương thức giao hàng do ứng dụng thanh toán cung cấp không thuộc về bất kỳ phương thức giao hàng nào do người bán chỉ định.
Nhận thông tin thanh toán mới cập nhật từ người bán
Kotlin
override fun updateWith(updatedPaymentDetails: Bundle) {}
override fun paymentDetailsNotUpdated() {}
Java
@Override
public void updateWith(Bundle updatedPaymentDetails) {}
@Override
public void paymentDetailsNotUpdated() {}
updatedPaymentDetails
là gói tương đương với từ điển
PaymentRequestDetailsUpdate
WebIDL và chứa các khoá
không bắt buộc sau:
total
– Một gói chứa các khoácurrency
vàvalue
, cả hai khoá đều có giá trị chuỗishippingOptions
– Mảng có thể phân phối của các tuỳ chọn vận chuyểnerror
– Một chuỗi chứa thông báo lỗi chung (ví dụ: khichangeShippingOption
không cung cấp mã nhận dạng phương thức giao hàng hợp lệ)stringifiedPaymentMethodErrors
– Chuỗi JSON đại diện cho lỗi xác thực phương thức thanh toánaddressErrors
– Một gói có các khoá không bắt buộc giống với địa chỉ giao hàng và giá trị chuỗi. Mỗi khoá đại diện cho một lỗi xác thực liên quan đến phần tương ứng của địa chỉ giao hàng.modifiers
– Một mảng có thể phân phối của các Gói, mỗi gói có một trườngtotal
vàmethodData
, cũng là các Gói.
Khoá không có nghĩa là giá trị của khoá đó không thay đổi.