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

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

Sahel Sharify
Sahel Sharify

เผยแพร่: 17 กรกฎาคม 2020 อัปเดตล่าสุด: 27 พฤษภาคม 2025

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

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

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

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

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/chromium_payment_supported_delegations" />
</activity>

android:resource ต้องชี้ไปยัง <string-array> ที่มีค่าต่อไปนี้ทั้งหมดหรือบางส่วน

  • payerName
  • payerEmail
  • payerPhone
  • shippingAddress

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

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string-array name="chromium_payment_supported_delegations">
    <item>payerEmail</item>
    <item>shippingAddress</item>
  </string-array>
</resources>

แยกวิเคราะห์ข้อมูลเพิ่มเติมของ Intent PAY สำหรับตัวเลือกการชำระเงินที่จำเป็น

ผู้ขายสามารถระบุข้อมูลเพิ่มเติมที่จำเป็นได้โดยใช้พจนานุกรม paymentOptions Chrome จะแสดงรายการตัวเลือกที่จำเป็นที่แอปของคุณระบุได้โดยการส่ง paymentOptions Intent extras ไปยังกิจกรรม 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 ที่มีค่าสตริง
  • 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 เป็นจริง พุลลิงค์ควรมีคีย์ต่อไปนี้ซึ่งแสดงถึงส่วนต่างๆ ในที่อยู่จริง
    • countryCode
    • postalCode
    • sortingCode
    • region
    • city
    • dependentLocality
    • addressLine
    • organization
    • recipient
    • phone คีย์ทั้งหมดที่ไม่ใช่ 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".'

ตัวอย่างโค้ดต่อไปนี้เป็นตัวอย่างของการตอบกลับที่ถูกต้อง

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 Bundle ที่ไม่ใช่ค่าว่างซึ่งมี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 options ที่แบ่งออกเป็นส่วนๆ ได้
  • error - สตริงที่มีข้อความแสดงข้อผิดพลาดทั่วไป (เช่น เมื่อ changeShippingOption ไม่ได้ระบุตัวระบุตัวเลือกการจัดส่งที่ถูกต้อง)
  • stringifiedPaymentMethodErrors - สตริง JSON ที่แสดงข้อผิดพลาดในการตรวจสอบสำหรับวิธีการชำระเงิน
  • addressErrors - กลุ่มที่มีคีย์ที่ไม่บังคับซึ่งเหมือนกับที่อยู่สำหรับจัดส่งและค่าสตริง คีย์แต่ละรายการแสดงข้อผิดพลาดในการตรวจสอบที่เกี่ยวข้องกับส่วนที่เกี่ยวข้องของที่อยู่สำหรับจัดส่ง
  • modifiers - อาร์เรย์ Bundle ที่แบ่งพาร์ติชันได้ โดยแต่ละรายการมีช่อง total และ methodData ซึ่งเป็น Bundle เช่นกัน

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