ارائه اطلاعات حمل و نقل و تماس از یک برنامه پرداخت Android

نحوه به‌روزرسانی برنامه پرداخت Android خود برای ارائه آدرس حمل و اطلاعات تماس پرداخت‌کننده با Web Payments.

ساحل شریفی
Sahel Sharify

وارد کردن آدرس حمل و نقل و اطلاعات تماس از طریق یک فرم وب می تواند یک تجربه دست و پا گیر برای مشتریان باشد. می تواند باعث خطا و کاهش نرخ تبدیل شود.

به همین دلیل است که API درخواست پرداخت از ویژگی درخواست آدرس ارسال و اطلاعات تماس پشتیبانی می کند. این مزایای متعددی را به همراه دارد:

  • کاربران می توانند آدرس مناسب را تنها با چند ضربه انتخاب کنند.
  • آدرس همیشه در قالب استاندارد بازگردانده می شود.
  • ارسال آدرس نادرست احتمال کمتری دارد.

مرورگرها می‌توانند جمع‌آوری آدرس ارسال و اطلاعات تماس را به یک برنامه پرداخت موکول کنند تا تجربه پرداخت یکپارچه را ارائه دهند. این قابلیت تفویض اختیار نامیده می شود.

هر زمان که ممکن باشد، Chrome جمع آوری آدرس ارسال و اطلاعات تماس مشتری را به برنامه پرداخت Android فراخوانی شده واگذار می کند. هیئت نمایندگی اصطکاک را در هنگام پرداخت کاهش می دهد.

وب سایت بازرگان می تواند بسته به انتخاب مشتری از آدرس حمل و نقل و گزینه حمل، گزینه های حمل و نقل و قیمت کل را به صورت پویا به روز کند.

گزینه حمل و نقل و آدرس حمل و نقل تغییر می کند. ببینید که چگونه به صورت پویا بر گزینه های حمل و نقل و قیمت کل تأثیر می گذارد.

برای افزودن پشتیبانی نمایندگی به یک برنامه پرداخت Android موجود، مراحل زیر را اجرا کنید:

  1. هیئت های حمایت شده را اعلام کنید .
  2. موارد اضافی قصد PAY را برای گزینه های پرداخت مورد نیاز تجزیه و تحلیل کنید .
  3. در پاسخ به پرداخت اطلاعات مورد نیاز را ارائه دهید .
  4. [اختیاری] پشتیبانی از جریان پویا :
    1. تاجر را از تغییرات در روش پرداخت انتخابی کاربر، آدرس ارسال یا گزینه ارسال مطلع کنید .
    2. جزئیات پرداخت به روز شده را از تاجر دریافت کنید (به عنوان مثال، مبلغ کل تنظیم شده بر اساس هزینه گزینه حمل و نقل انتخاب شده) .

هیئت های حمایت شده را اعلام کنید

مرورگر باید لیستی از اطلاعات اضافی را که برنامه پرداخت شما می تواند ارائه دهد بداند تا بتواند مجموعه آن اطلاعات را به برنامه شما واگذار کند. نمایندگی های پشتیبانی شده را در برنامه AndroidManifest.xml به عنوان <meta-data> اعلام کنید.

<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>

موارد اضافی قصد 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" باشد. برنامه شما می‌تواند از این راهنمایی در رابط کاربری خود هنگام درخواست آدرس کاربر یا انتخاب گزینه‌های ارسال استفاده کند.

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 حرفی ISO4217 نشان می دهد.
    • 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")
    }
}

اختیاری: پشتیبانی از جریان پویا

گاهی اوقات هزینه کل یک تراکنش افزایش می یابد، مانند زمانی که کاربر گزینه حمل و نقل سریع را انتخاب می کند، یا زمانی که کاربر یک آدرس حمل و نقل بین المللی را انتخاب می کند، لیست گزینه های حمل و نقل موجود یا قیمت آنها تغییر می کند. وقتی برنامه شما آدرس یا گزینه ارسال انتخابی توسط کاربر را ارائه می‌کند، باید بتواند تاجر را در مورد هر گونه آدرس حمل و نقل یا تغییر گزینه مطلع کند و جزئیات پرداخت به‌روز شده (ارائه شده توسط تاجر) را به کاربر نشان دهد.

ایدل

برای اطلاع دادن به تاجر در مورد تغییرات جدید، از سرویس 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 که برای هدف شروع سرویس استفاده می‌شود، بسته به مرورگری که درخواست پرداخت را آغاز کرده است، می‌تواند یکی از مقادیر زیر را داشته باشد.

کانال کروم نام بسته
پایدار "com.android.chrome"
بتا "com.chrome.beta"
توسعه دهنده "com.chrome.dev"
قناری "com.chrome.canary"
کروم "org.chromium.chrome"
جعبه جستجوی سریع Google (یک جاسازی لایه Web) "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 با دریافت هر یک از درخواست‌های تغییر با وضعیت نامعتبر مواجه شود، با یک بسته updatePaymentDetails ویرایش‌شده، callback.updateWith فراخوانی می‌کند. بسته فقط حاوی کلید 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 ، هر دو کلید دارای مقادیر رشته هستند
  • shippingOptions - آرایه قابل بسته بندی از گزینه های حمل و نقل
  • error - رشته ای حاوی یک پیام خطای عمومی (مثلاً وقتی changeShippingOption یک شناسه گزینه حمل و نقل معتبر ارائه نمی دهد)
  • stringifiedPaymentMethodErrors - یک رشته JSON که خطاهای اعتبارسنجی روش پرداخت را نشان می دهد
  • addressErrors - یک بسته با کلیدهای اختیاری مشابه آدرس ارسال و مقادیر رشته. هر کلید نشان دهنده یک خطای اعتبارسنجی مربوط به قسمت مربوطه آن از آدرس حمل و نقل است.

کلید غایب به این معنی است که مقدار آن تغییر نکرده است.