วิธีอัปเดตแอปการชำระเงินบน Android เพื่อระบุที่อยู่สำหรับจัดส่งและข้อมูลติดต่อของผู้ชำระเงินกับ Web Payments API
การป้อนที่อยู่สำหรับจัดส่งและข้อมูลติดต่อผ่านเว็บฟอร์มอาจเป็นเรื่องยุ่งยากสำหรับลูกค้า อาจทำให้เกิดข้อผิดพลาดและ ลดอัตรา 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/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>
แยกวิเคราะห์ Intent เพิ่มเติมของ PAY
สำหรับตัวเลือกการชำระเงินที่จำเป็น
ผู้ขายสามารถระบุข้อมูลที่จำเป็นเพิ่มเติมโดยใช้พจนานุกรม paymentOptions
Chrome จะแสดงรายการตัวเลือกที่จำเป็นซึ่งแอปมีให้โดยการส่งพารามิเตอร์ต่อไปนี้ไปยังกิจกรรม PAY
เป็น Intent เพิ่มเติม
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"
แอปของคุณสามารถใช้คำแนะนำนี้ใน UI เมื่อขอที่อยู่ของผู้ใช้หรือตัวเลือกการจัดส่ง
shippingOptions
shippingOptions
คืออาร์เรย์แบบพัสดุที่ผู้ขายระบุ พารามิเตอร์นี้จะมีอยู่ก็ต่อเมื่อ paymentOptions.requestShipping ==
true
เท่านั้น
val shippingOptions: List<ShippingOption>? =
extras.getParcelableArray("shippingOptions")?.mapNotNull {
p -> from(p as Bundle)
}
ตัวเลือกการจัดส่งแต่ละรายการจะเป็น Bundle
ซึ่งมีคีย์ดังต่อไปนี้
id
- ตัวระบุตัวเลือกการจัดส่งlabel
- ป้ายกำกับตัวเลือกการจัดส่งที่แสดงต่อผู้ใช้amount
- กลุ่มค่าจัดส่งที่มีคีย์currency
และvalue
พร้อมค่าสตริงcurrency
แสดงสกุลเงินของค่าจัดส่ง เป็นรหัสตัวอักษร 3 ตัว ในรูปแบบ ISO4217value
แสดงค่าค่าจัดส่งเป็นค่าจำนวนเงินทศนิยมที่ถูกต้อง
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
ในการดำเนินการดังกล่าว คุณต้องระบุพารามิเตอร์ต่อไปนี้เป็นส่วนเสริมของ Intent
payerName
- ชื่อและนามสกุลของผู้ชำระเงิน สตริงนี้ควรเป็นสตริงที่ไม่ว่างเมื่อpaymentOptions.requestPayerName
เป็นจริงpayerPhone
- หมายเลขโทรศัพท์ของผู้ชำระเงิน สตริงนี้ควรเป็นสตริงที่ไม่ว่างเมื่อpaymentOptions.requestPayerPhone
เป็นจริงpayerEmail
- อีเมลของผู้ชำระเงิน ควรเป็นสตริงที่ไม่ว่างเมื่อpaymentOptions.requestPayerEmail
เป็นจริงshippingAddress
- ที่อยู่สำหรับจัดส่งที่ได้จากผู้ใช้ ซึ่งควรเป็นแพ็กเกจที่ไม่ว่างเปล่าเมื่อpaymentOptions.requestShipping
เป็นจริง แพ็กเกจควรมีคีย์ต่อไปนี้ซึ่งแสดงถึงส่วนต่างๆ ในที่อยู่จริงcity
countryCode
dependentLocality
organization
phone
postalCode
recipient
region
sortingCode
addressLine
คีย์ทั้งหมดที่ไม่ใช่addressLine
มีค่าสตริงaddressLine
คืออาร์เรย์ของสตริง
shippingOptionId
- ตัวระบุของตัวเลือกการจัดส่งที่ผู้ใช้เลือก ซึ่งควรเป็นสตริงที่ไม่ว่างเมื่อpaymentOptions.requestShipping
เป็นจริง
ตรวจสอบการตอบกลับการชำระเงิน
หากผลของกิจกรรมการตอบสนองการชำระเงินที่ได้รับจากแอปการชำระเงินที่เรียกใช้มีการตั้งค่าเป็น RESULT_OK
Chrome จะตรวจสอบข้อมูลเพิ่มเติมที่จำเป็นในส่วนเพิ่มเติม หากตรวจสอบไม่สำเร็จ Chrome จะส่งคืนคำสัญญาที่ถูกปฏิเสธจาก 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
ที่ประกาศใน AndroidManifest.xml ของ Chrome หากต้องการใช้บริการนี้ ให้สร้างไฟล์ AIDL 2 ไฟล์ที่มีเนื้อหาต่อไปนี้
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
}
}
}
callingPackageName
ที่ใช้สำหรับ Intent เริ่มต้นของบริการอาจมีค่าใดค่าหนึ่งต่อไปนี้ ทั้งนี้ขึ้นอยู่กับเบราว์เซอร์ที่ส่งคำขอการชำระเงิน
ช่องของ Chrome | ชื่อแพ็กเกจ |
---|---|
คงที่ |
"com.android.chrome"
|
เบต้า |
"com.chrome.beta"
|
กำลังพัฒนา |
"com.chrome.dev"
|
คะแนรี |
"com.chrome.canary"
|
Chromium |
"org.chromium.chrome"
|
ช่อง Google Quick Search (การฝัง 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 จะตรวจหาแพ็กเกจ shippingAddress
ที่ไม่ว่างเปล่าซึ่งมี countryCode
ที่ถูกต้อง และส่ง updatePaymentDetails
ที่มีข้อความแสดงข้อผิดพลาดต่อไปนี้ผ่าน callback.updateWith
หากตรวจสอบไม่สำเร็จ
'Payment app returned invalid shipping address in response.'
ข้อความแสดงข้อผิดพลาดเกี่ยวกับสถานะไม่ถูกต้อง
หาก Chrome พบสถานะที่ไม่ถูกต้องเมื่อได้รับคำขอเปลี่ยนแปลงใดๆ ระบบจะเรียกใช้ callback.updateWith
พร้อมแพ็กเกจ updatePaymentDetails
ที่ปกปิด แพ็กเกจจะมีเฉพาะคีย์ error
ที่มี "Invalid state"
เท่านั้น
ตัวอย่างของสถานะที่ไม่ถูกต้องมีดังนี้
- ในกรณีที่ 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
โดยทั้ง 2 คีย์มีค่าสตริงshippingOptions
- อาร์เรย์แบบพาร์เซลของตัวเลือกการจัดส่งerror
- สตริงที่มีข้อความแสดงข้อผิดพลาดทั่วไป (เช่น เมื่อchangeShippingOption
ไม่มีตัวระบุตัวเลือกการจัดส่งที่ถูกต้อง)stringifiedPaymentMethodErrors
- สตริง JSON ที่แสดง ข้อผิดพลาดในการตรวจสอบความถูกต้องสำหรับวิธีการชำระเงินaddressErrors
- แพ็กเกจที่มีคีย์ที่ไม่บังคับซึ่งเหมือนกับที่อยู่การจัดส่งและค่าของสตริง แต่ละคีย์แสดงถึงข้อผิดพลาดในการตรวจสอบความถูกต้องในส่วนที่เกี่ยวข้องของที่อยู่สำหรับจัดส่ง
คีย์ที่ไม่มีการเปลี่ยนแปลงหมายความว่าค่าของคีย์ดังกล่าวไม่มีการเปลี่ยนแปลง