วิธีอัปเดตแอปการชำระเงินบน Android เพื่อระบุที่อยู่สำหรับจัดส่งและข้อมูลติดต่อของผู้ชำระเงินด้วย Web Payments API
เผยแพร่: 17 กรกฎาคม 2020, อัปเดตล่าสุด: 27 พฤษภาคม 2025
การป้อนที่อยู่สำหรับจัดส่งและข้อมูลติดต่อผ่านแบบฟอร์มบนเว็บอาจเป็นประสบการณ์ที่ยุ่งยากสำหรับลูกค้า ซึ่งอาจทำให้เกิดข้อผิดพลาดและอัตรา Conversion ลดลง
ด้วยเหตุนี้ Payment Request API จึงรองรับฟีเจอร์ในการขอที่อยู่จัดส่ง และข้อมูลติดต่อ ซึ่งมีประโยชน์หลายประการ ดังนี้
- ผู้ใช้สามารถเลือกที่อยู่ที่ถูกต้องได้ด้วยการแตะเพียงไม่กี่ครั้ง
- ระบบจะแสดงที่อยู่ในรูปแบบมาตรฐาน เสมอ
- โอกาสที่จะส่งที่อยู่ไม่ถูกต้องจะน้อยลง
เบราว์เซอร์สามารถเลื่อนการเก็บรวบรวมที่อยู่สำหรับจัดส่งและข้อมูลติดต่อไปยังแอปการชำระเงินเพื่อมอบประสบการณ์การชำระเงินแบบรวม ฟังก์ชันนี้เรียกว่าการมอบสิทธิ์
เมื่อใดก็ตามที่เป็นไปได้ Chrome จะมอบหมายการรวบรวมที่อยู่จัดส่งและข้อมูลติดต่อของลูกค้าให้กับแอปการชำระเงิน Android ที่เรียกใช้ การมอบหมายนี้จะช่วยลดอุปสรรคในระหว่างการชำระเงิน
เว็บไซต์ของผู้ขายสามารถอัปเดตตัวเลือกการจัดส่งและราคารวมแบบไดนามิก โดยขึ้นอยู่กับที่อยู่สำหรับจัดส่งและตัวเลือกการจัดส่งที่ลูกค้าเลือก
หากต้องการเพิ่มการรองรับการมอบสิทธิ์ให้กับแอปการชำระเงิน Android ที่มีอยู่แล้ว ให้ทำตามขั้นตอนต่อไปนี้
- ประกาศการมอบสิทธิ์ที่รองรับ
- แยกวิเคราะห์ส่วนเพิ่มเติมของ Intent
PAYสำหรับตัวเลือกการชำระเงินที่จำเป็น - ระบุข้อมูลที่จำเป็นในการตอบกลับการชำระเงิน
- ไม่บังคับ: รองรับโฟลว์แบบไดนามิก
ประกาศการมอบสิทธิ์ที่รองรับ
เบราว์เซอร์ต้องทราบรายการข้อมูลเพิ่มเติมที่แอปการชำระเงินของคุณระบุได้ เพื่อให้สามารถมอบสิทธิ์การเก็บรวบรวมข้อมูลดังกล่าวให้กับแอปของคุณ ประกาศการมอบสิทธิ์ที่รองรับเป็น <meta-data> ใน AndroidManifest.xml ของแอป
<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> ที่มีค่าทั้งหมดหรือค่าบางส่วนต่อไปนี้
payerNamepayerEmailpayerPhoneshippingAddress
ตัวอย่างต่อไปนี้ระบุได้เฉพาะที่อยู่จัดส่งและอีเมลของผู้ชำระเงิน
<?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
ไปยังกิจกรรม 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- ตัวระบุตัวเลือกการจัดส่งlabel- ป้ายกำกับตัวเลือกการจัดส่งที่แสดงต่อผู้ใช้amount- ชุดค่าจัดส่งที่มีคีย์currencyและvalueที่มีค่าเป็นสตริงcurrencyแสดงสกุลเงินของค่าจัดส่งเป็นรหัสตัวอักษร 3 ตัวที่ถูกต้องตามรูปแบบ ISO4217valueแสดงค่าของค่าจัดส่งเป็นค่าเงินทศนิยมที่ถูกต้อง
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เป็นจริงpayerPhone- หมายเลขโทรศัพท์ของผู้ชำระเงิน ควรเป็นสตริงที่ไม่ว่างเปล่าเมื่อpaymentOptions.requestPayerPhoneเป็นจริงpayerEmail- อีเมลของผู้ชำระเงิน ควรเป็นสตริงที่ไม่ว่างเปล่า เมื่อpaymentOptions.requestPayerEmailเป็นจริงshippingAddress- ที่อยู่สำหรับจัดส่งที่ผู้ใช้ระบุ ซึ่งควรเป็น แพ็กเกจที่ไม่ว่างเปล่าเมื่อpaymentOptions.requestShippingเป็นจริง โดยแพ็กเกจ ควรมีคีย์ต่อไปนี้ซึ่งแสดงถึงส่วนต่างๆ ในที่อยู่จริงcountryCodepostalCodesortingCoderegioncitydependentLocalityaddressLineorganizationrecipientphoneคีย์อื่นๆ ทั้งหมดนอกเหนือจากaddressLineมีค่าเป็นสตริงaddressLineเป็นอาร์เรย์ของสตริง
shippingOptionId- ตัวระบุของตัวเลือกการจัดส่งที่ผู้ใช้เลือก ค่านี้ ควรเป็นสตริงที่ไม่ว่างเปล่าเมื่อpaymentOptions.requestShippingเป็นจริง
ตรวจสอบการตอบกลับการชำระเงิน
หากตั้งค่าผลลัพธ์ของกิจกรรมการตอบกลับการชำระเงินที่ได้รับจากแอปการชำระเงินที่เรียกใช้เป็น 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".'
ตัวอย่างโค้ดต่อไปนี้เป็นตัวอย่างการตอบกลับที่ถูกต้อง
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ด้วยตัวกรอง Intent UPDATE_PAYMENT_DETAILS
หลังจากเรียกใช้ Intent PAY แล้ว Chrome จะเชื่อมต่อกับบริการ UPDATE_PAYMENT_DETAILS (หากมี) ในแพ็กเกจเดียวกันกับ Intent PAY และจะเรียกใช้ setPaymentDetailsUpdateService(service) เพื่อระบุปลายทาง IPaymentDetailsUpdateService ให้แอปการชำระเงินของคุณเพื่อแจ้งเตือนเกี่ยวกับการเปลี่ยนแปลงวิธีการชำระเงิน ตัวเลือกการจัดส่ง หรือที่อยู่สำหรับจัดส่งของผู้ใช้
ใช้ packageManager.getPackagesForUid(Binder.getCallingUid()) เมื่อได้รับ
การสื่อสารระหว่างกระบวนการ (IPC) เพื่อตรวจสอบว่าแอปที่เรียกใช้ Intent PAY มีชื่อแพ็กเกจเดียวกันกับแอปที่เรียกใช้เมธอด IPaymentDetailsUpdateServiceCallback
AIDL
สร้างไฟล์ AIDL 2 ไฟล์ที่มีเนื้อหาต่อไปนี้
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
เปิดเผยบริการสำหรับ IPaymentDetailsUpdateServiceCallback ใน
AndroidManifest.xml
<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 (ไม่บังคับ)
ทั้ง 2 คีย์มีค่าสตริง Chrome จะตรวจสอบบันเดิลที่ไม่ว่างซึ่งมี methodName ที่ไม่ว่าง และส่ง updatePaymentDetails พร้อมข้อความแสดงข้อผิดพลาดต่อไปนี้ข้อความใดข้อความหนึ่งโดยใช้ callback.updateWith หากการตรวจสอบไม่สำเร็จ
'Method data required.'
'Method name required.'
changeShippingOption
แจ้งให้ผู้ขายทราบเกี่ยวกับการเปลี่ยนแปลงตัวเลือกการจัดส่งที่ผู้ใช้เลือก
shippingOptionId ควรเป็นตัวระบุของตัวเลือกการจัดส่งที่ผู้ขายระบุ
ตัวเลือกใดตัวเลือกหนึ่ง Chrome จะตรวจสอบว่า shippingOptionId ไม่ว่างเปล่าและส่ง updatePaymentDetails พร้อมข้อความแสดงข้อผิดพลาดต่อไปนี้โดยใช้ callback.updateWith หากการตรวจสอบไม่สำเร็จ
'Shipping option identifier required.'
changeShippingAddress
แจ้งให้ผู้ขายทราบเกี่ยวกับการเปลี่ยนแปลงที่อยู่สำหรับจัดส่งที่ผู้ใช้ระบุ Chrome
จะตรวจสอบshippingAddressที่ไม่ว่างซึ่งมี countryCode ที่ถูกต้อง
และส่ง updatePaymentDetails พร้อมข้อความแสดงข้อผิดพลาดต่อไปนี้โดยใช้
callback.updateWith หากการตรวจสอบไม่สำเร็จ
'Payment app returned invalid shipping address in response.'
ข้อความแสดงข้อผิดพลาดเกี่ยวกับสถานะไม่ถูกต้อง
หาก Chrome พบสถานะที่ไม่ถูกต้องเมื่อได้รับคำขอเปลี่ยนแปลง
ระบบจะเรียกใช้ callback.updateWith พร้อมกับแพ็กเกจ updatePaymentDetails
ที่แก้ไขแล้ว โดยแพ็กเกจจะมีเฉพาะerrorคีย์ที่มี"Invalid state"
ตัวอย่างของสถานะที่ไม่ถูกต้องมีดังนี้
- เมื่อ Chrome ยังรอการตอบกลับของผู้ขายสำหรับการเปลี่ยนแปลงก่อนหน้า (เช่น เหตุการณ์การเปลี่ยนแปลงที่กำลังดำเนินการ)
- ตัวระบุตัวเลือกการจัดส่งที่แอปการชำระเงินระบุไม่ได้เป็นของตัวเลือกการจัดส่งที่ผู้ขายระบุ
รับรายละเอียดการชำระเงินที่อัปเดตแล้วจากผู้ขาย
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โดยทั้ง 2 คีย์มีค่าเป็นสตริงshippingOptions- อาร์เรย์ที่ส่งผ่านได้ของ shipping optionserror- สตริงที่มีข้อความแสดงข้อผิดพลาดทั่วไป (เช่น เมื่อchangeShippingOptionไม่ได้ระบุตัวระบุตัวเลือกการจัดส่งที่ถูกต้อง)stringifiedPaymentMethodErrors- สตริง JSON ที่แสดงข้อผิดพลาดในการตรวจสอบ สำหรับวิธีการชำระเงินaddressErrors- ชุดที่มีคีย์ที่ไม่บังคับซึ่งเหมือนกับ shipping address และค่าสตริง คีย์แต่ละรายการแสดงข้อผิดพลาดในการตรวจสอบที่เกี่ยวข้องกับส่วนที่สอดคล้องกันของที่อยู่สำหรับจัดส่งmodifiers- อาร์เรย์ที่ส่งผ่านได้ของ Bundle แต่ละรายการที่มีฟิลด์totalและmethodDataซึ่งเป็น Bundle ด้วย
คีย์ที่ไม่มีหมายความว่าค่าของคีย์นั้นไม่มีการเปลี่ยนแปลง