การให้ข้อมูลการจัดส่งและข้อมูลติดต่อจากแอปการชำระเงินของ Android

วิธีอัปเดตแอปการชำระเงินบน Android เพื่อระบุที่อยู่สำหรับจัดส่งและข้อมูลติดต่อของผู้ชำระเงินกับ Web Payments API

Sahel Sharify
Sahel Sharify

การป้อนที่อยู่สำหรับจัดส่งและข้อมูลติดต่อผ่านเว็บฟอร์มอาจเป็น ในการใช้งานที่ยุ่งยาก อาจทำให้เกิดข้อผิดพลาดและลด Conversion

API คำขอการชำระเงินจึงรองรับฟีเจอร์เพื่อขอการจัดส่ง ที่อยู่และข้อมูลติดต่อ ซึ่งมีประโยชน์หลายประการดังนี้

  • ผู้ใช้สามารถเลือกที่อยู่ที่ถูกต้องได้ด้วยการแตะเพียงไม่กี่ครั้ง
  • ที่อยู่จะแสดงในรูปแบบ มาตรฐานเสมอ format [รูปแบบ]
  • การส่งที่อยู่ที่ไม่ถูกต้องมีโอกาสน้อย

เบราว์เซอร์สามารถเลื่อนการเก็บข้อมูลที่อยู่สำหรับจัดส่งและข้อมูลติดต่อออกไปได้ แอปการชำระเงินเพื่อมอบประสบการณ์การชำระเงินที่เป็นหนึ่งเดียว ฟังก์ชันการทำงานนี้ ที่เรียกว่า delegation

Chrome จะมอบสิทธิ์การเก็บรวบรวมภาพการจัดส่งของลูกค้าเมื่อเป็นไปได้ ที่อยู่และข้อมูลติดต่อไปยังแอปการชำระเงิน Android ที่เรียกใช้ การมอบสิทธิ์จะช่วยลดอุปสรรคในระหว่างการชำระเงิน

เว็บไซต์ผู้ขายจะอัปเดตตัวเลือกการจัดส่งและราคารวมแบบไดนามิกได้ โดยขึ้นอยู่กับตัวเลือกของลูกค้าในที่อยู่สำหรับจัดส่งและการจัดส่ง ตัวเลือก

การเปลี่ยนแปลงตัวเลือกการจัดส่งและที่อยู่สำหรับจัดส่ง ดูว่าราคาส่งผลต่อตัวเลือกการจัดส่งและราคารวมแบบไดนามิกอย่างไร

หากต้องการเพิ่มการสนับสนุนการมอบสิทธิ์ในแอปการชำระเงินบน Android ที่มีอยู่แล้ว ให้ทำดังนี้ ทำตามขั้นตอนต่อไปนี้

  1. ประกาศการมอบสิทธิ์ที่รองรับ
  2. แยกวิเคราะห์ Intent เพิ่มเติม PAY รายการสำหรับการชำระเงินที่จำเป็น ตัวเลือกเพิ่มเติม
  3. ระบุข้อมูลที่จำเป็นในการชำระเงิน คำตอบ
  4. [ไม่บังคับ] รองรับขั้นตอนแบบไดนามิก
    1. แจ้งให้ผู้ขายทราบเกี่ยวกับการเปลี่ยนแปลงในวิธีการชำระเงินที่ผู้ใช้เลือก ที่อยู่สำหรับจัดส่ง หรือที่อยู่สำหรับจัดส่ง ตัวเลือก
    2. รับรายละเอียดการชำระเงินที่อัปเดตจากผู้ขาย (เช่น จำนวนเงินรวมที่ปรับแล้วตามตัวเลือกการจัดส่งที่เลือก ต้นทุน)

ประกาศการมอบสิทธิ์ที่รองรับ

เบราว์เซอร์จำเป็นต้องทราบรายการข้อมูลเพิ่มเติมที่การชำระเงินของคุณ สามารถมอบให้เพื่อมอบสิทธิ์การเก็บรวบรวมข้อมูลดังกล่าวให้กับ แอป ประกาศการมอบสิทธิ์ที่รองรับเป็น <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 พร้อมคีย์ ค่าสตริง
  • 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 ที่มีเนื้อหาต่อไปนี้

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 ทั้ง 2 คีย์ด้วยค่าสตริง Chrome จะตรวจหาแพ็กเกจที่ไม่ว่างเปล่า methodName ที่ไม่ว่างเปล่าและส่ง updatePaymentDetails ที่มี ข้อความแสดงข้อผิดพลาดต่อไปนี้ผ่านทาง callback.updateWith หากตรวจสอบไม่สำเร็จ

'Method data required.'
'Method name required.'

changeShippingOption

แจ้งผู้ขายเกี่ยวกับการเปลี่ยนแปลงในตัวเลือกการจัดส่งที่ผู้ใช้เลือก shippingOptionId ควรเป็นตัวระบุของหนึ่งในผู้ขายที่ระบุ ตัวเลือกการจัดส่ง Chrome จะตรวจหา shippingOptionId ที่ไม่ว่างเปล่าและส่ง updatePaymentDetails พร้อมข้อความแสดงข้อผิดพลาดต่อไปนี้ ผ่าน callback.updateWith หากตรวจสอบไม่สำเร็จ

'Shipping option identifier required.'

changeShippingAddress

แจ้งผู้ขายเกี่ยวกับการเปลี่ยนแปลงในที่อยู่สำหรับจัดส่งที่ได้จากผู้ใช้ โครเมียม จะตรวจสอบแพ็กเกจ 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 - แพ็กเกจที่มีคีย์ที่ไม่บังคับซึ่งเหมือนกับการจัดส่ง address และสตริง แต่ละคีย์แสดงถึงข้อผิดพลาดในการตรวจสอบความถูกต้องที่เกี่ยวข้องกับคีย์นั้นๆ ส่วนของที่อยู่สำหรับจัดส่ง

คีย์ที่ไม่มีการเปลี่ยนแปลงหมายความว่าค่าของคีย์ดังกล่าวไม่มีการเปลี่ยนแปลง