วิธีอัปเดตแอปการชำระเงิน Android เพื่อระบุที่อยู่จัดส่งและข้อมูลติดต่อของผู้ชำระเงินด้วย Web Payments API
เผยแพร่: 17 กรกฎาคม 2020, อัปเดตล่าสุด: 27 พฤษภาคม 2025
การป้อนที่อยู่จัดส่งและข้อมูลติดต่อผ่านแบบฟอร์มบนเว็บอาจเป็นประสบการณ์ที่ยุ่งยากสำหรับลูกค้า ซึ่งอาจทำให้เกิดข้อผิดพลาดและอัตรา Conversion ลดลง
ด้วยเหตุนี้ Payment Request API จึงรองรับฟีเจอร์ในการขอที่อยู่จัดส่ง และข้อมูลติดต่อ ซึ่งมีประโยชน์หลายประการ ดังนี้
- ผู้ใช้เลือกที่อยู่ที่ถูกต้องได้ด้วยการแตะเพียงไม่กี่ครั้ง
- ระบบจะแสดงผลที่อยู่ในรูปแบบมาตรฐาน เสมอ
- โอกาสที่จะส่งที่อยู่ไม่ถูกต้องจะน้อยลง
เบราว์เซอร์สามารถเลื่อนการเก็บรวบรวมที่อยู่จัดส่งและข้อมูลติดต่อไปยัง แอปการชำระเงินเพื่อมอบประสบการณ์การชำระเงินแบบรวม ฟังก์ชันนี้เรียกว่าการมอบสิทธิ์
Chrome จะมอบสิทธิ์ให้แอปการชำระเงิน Android ที่เรียกใช้รวบรวมที่อยู่จัดส่งและข้อมูลติดต่อของลูกค้าทุกครั้งที่ทำได้ การมอบสิทธิ์จะช่วยลดอุปสรรคในระหว่างการชำระเงิน
เว็บไซต์ของผู้ขายสามารถอัปเดตตัวเลือกการจัดส่งและราคารวมแบบไดนามิก โดยขึ้นอยู่กับตัวเลือกที่อยู่จัดส่งและตัวเลือกการจัดส่งที่ลูกค้าเลือก
หากต้องการเพิ่มการรองรับการมอบสิทธิ์ให้กับแอปการชำระเงิน Android ที่มีอยู่แล้ว ให้ทำตามขั้นตอนต่อไปนี้
- ประกาศการมอบสิทธิ์ที่รองรับ
- แยกวิเคราะห์
PAYส่วนเพิ่มเติมของ Intent สำหรับตัวเลือกการชำระเงินที่จำเป็น - ระบุข้อมูลที่จำเป็นในการตอบกลับการชำระเงิน
- ไม่บังคับ: รองรับโฟลว์แบบไดนามิก
ประกาศการมอบสิทธิ์ที่รองรับ
เบราว์เซอร์ต้องทราบรายการข้อมูลเพิ่มเติมที่แอปการชำระเงินของคุณระบุได้ เพื่อให้สามารถมอบสิทธิ์ในการเก็บรวบรวมข้อมูลดังกล่าวให้กับแอปของคุณ ประกาศการมอบสิทธิ์ที่รองรับเป็น <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
Extras ของ 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 จะตรวจสอบข้อมูลเพิ่มเติมที่จำเป็นในส่วน "Extras" หากการตรวจสอบไม่สำเร็จ 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 (ไม่บังคับ)
ซึ่งมีค่าสตริงทั้งคู่ 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 พบสถานะที่ไม่ถูกต้องเมื่อได้รับคำขอเปลี่ยนแปลง
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 ด้วย
คีย์ที่ไม่มีหมายความว่าค่าของคีย์นั้นไม่มีการเปลี่ยนแปลง