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

چگونه برنامه پرداخت اندروید خود را به‌روزرسانی کنید تا آدرس ارسال و اطلاعات تماس پرداخت‌کننده را با APIهای پرداخت وب ارائه دهد.

ساحل شریفی
Sahel Sharify

منتشر شده: ۱۷ ژوئیه ۲۰۲۰، آخرین به‌روزرسانی: ۲۷ مه ۲۰۲۵

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

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

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

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

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

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

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

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

  1. هیئت‌های نمایندگی مورد حمایت خود را اعلام کنید .
  2. موارد اضافی مربوط به قصد PAY intent) را برای گزینه‌های پرداخت مورد نیاز تجزیه و تحلیل کنید .
  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>

موارد اضافی PAY intent را برای گزینه‌های پرداخت مورد نیاز تجزیه کنید

فروشنده می‌تواند اطلاعات مورد نیاز اضافی را با استفاده از دیکشنری paymentOptions مشخص کند. کروم فهرست گزینه‌های مورد نیازی را که برنامه شما می‌تواند ارائه دهد، با ارسال موارد اضافی paymentOptions Intent به فعالیت PAY ارائه می‌دهد.

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

جاوا

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

shippingOptions

shippingOptions آرایه‌ای از گزینه‌های حمل و نقل مشخص شده توسط فروشنده است که قابل بسته‌بندی است. این پارامتر فقط زمانی وجود خواهد داشت که paymentOptions.requestShipping == true .

کاتلین

val shippingOptions: List<ShippingOption>? =
    extras.getParcelableArray("shippingOptions")?.mapNotNull {
        p -> from(p as Bundle)
    }

جاوا

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 واحد پول هزینه حمل و نقل را به صورت یک کد سه حرفی خوش‌فرم 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)

جاوا

String id = bundle.getString("id");
String label = bundle.getString("label");
Bundle amount = bundle.getBundle("amount");
Boolean selected = bundle.getBoolean("selected", false);

اطلاعات لازم را در پاسخ پرداخت ارائه دهید

برنامه شما باید اطلاعات اضافی مورد نیاز را در پاسخ به فعالیت PAY درج کند.

برای انجام این کار، پارامترهای زیر باید به عنوان Intent extras مشخص شوند:

  • payerName - نام کامل پرداخت‌کننده. این باید یک رشته غیر خالی باشد وقتی paymentOptions.requestPayerName برابر با true باشد.
  • payerPhone - شماره تلفن پرداخت‌کننده. این شماره باید یک رشته غیر خالی باشد وقتی paymentOptions.requestPayerPhone برابر با true باشد.
  • payerEmail - آدرس ایمیل پرداخت‌کننده. این باید یک رشته غیر خالی باشد وقتی paymentOptions.requestPayerEmail برابر با true باشد.
  • shippingAddress - آدرس ارسال ارائه شده توسط کاربر. این باید یک بسته غیر خالی باشد وقتی paymentOptions.requestShipping برابر با true باشد. بسته باید دارای کلیدهای زیر باشد که نشان دهنده بخش‌های مختلف در یک آدرس فیزیکی هستند.
    • countryCode
    • postalCode
    • sortingCode
    • region
    • city
    • dependentLocality
    • addressLine
    • organization
    • recipient
    • phone همه کلیدها به غیر از addressLine دارای مقادیر رشته‌ای هستند. addressLine آرایه‌ای از رشته‌ها است.
  • shippingOptionId - شناسه‌ی گزینه‌ی حمل و نقل انتخاب شده توسط کاربر. این باید یک رشته‌ی غیر خالی باشد وقتی paymentOptions.requestShipping برابر با true باشد.

اعتبارسنجی پاسخ پرداخت

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

نمونه کد زیر نمونه‌ای از یک پاسخ معتبر است:

کاتلین

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")
    }
}

جاوا

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 خود با فیلتر UPDATE_PAYMENT_DETAILS اعلان کنید.

بلافاصله پس از فراخوانی هدف PAY ، کروم به سرویس UPDATE_PAYMENT_DETAILS (در صورت وجود) در همان بسته هدف PAY متصل می‌شود و setPaymentDetailsUpdateService(service) را فراخوانی می‌کند تا نقطه پایانی IPaymentDetailsUpdateService را برای برنامه پرداخت شما فراهم کند تا در مورد تغییرات در روش پرداخت کاربر، گزینه ارسال یا آدرس ارسال اطلاع‌رسانی کند.

هنگام دریافت ارتباط بین فرآیندی (IPC) از packageManager.getPackagesForUid(Binder.getCallingUid()) استفاده کنید تا تأیید کنید که برنامه‌ای که قصد PAY را فراخوانی کرده است، نام بسته یکسانی با برنامه‌ای دارد که متدهای IPaymentDetailsUpdateServiceCallback فراخوانی کرده است.

آیدل

دو فایل AIDL با محتوای زیر ایجاد کنید:

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 را پیاده‌سازی کنید.

کاتلین

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

جاوا

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>

در مورد تغییرات در روش پرداخت، آدرس ارسال یا گزینه ارسال انتخابی کاربر، به فروشنده اطلاع دهید

کاتلین

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
}

جاوا

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

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

changeShippingOption

به فروشنده در مورد تغییرات در گزینه حمل و نقل انتخاب شده توسط کاربر اطلاع می‌دهد. shippingOptionId باید شناسه یکی از گزینه‌های حمل و نقل مشخص شده توسط فروشنده باشد. کروم shippingOptionId غیر خالی را بررسی می‌کند و در صورت عدم موفقیت اعتبارسنجی، با استفاده از callback.updateWith ، یک updatePaymentDetails با پیام خطای زیر ارسال می‌کند.

'Shipping option identifier required.'

changeShippingAddress

به فروشنده در مورد تغییرات در آدرس ارسال ارائه شده توسط کاربر اطلاع می‌دهد. کروم بسته shippingAddress غیر خالی با countryCode معتبر را بررسی می‌کند و در صورت عدم موفقیت اعتبارسنجی، با استفاده از callback.updateWith ، یک updatePaymentDetails با پیام خطای زیر ارسال می‌کند.

'Payment app returned invalid shipping address in response.'

پیام خطای وضعیت نامعتبر

اگر کروم هنگام دریافت هر یک از درخواست‌های تغییر با وضعیت نامعتبر مواجه شود، تابع callback.updateWith را با یک بسته‌ی ویرایش‌شده‌ی updatePaymentDetails فراخوانی می‌کند. این بسته فقط شامل کلید error با "Invalid state" خواهد بود. نمونه‌هایی از وضعیت نامعتبر عبارتند از:

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

جزئیات پرداخت به‌روز شده را از فروشنده دریافت کنید

کاتلین

override fun updateWith(updatedPaymentDetails: Bundle) {}

override fun paymentDetailsNotUpdated() {}

جاوا

@Override
public void updateWith(Bundle updatedPaymentDetails) {}

@Override
public void paymentDetailsNotUpdated() {}

updatedPaymentDetails معادل بسته‌ی دیکشنری PaymentRequestDetailsUpdate WebIDL است و شامل کلیدهای اختیاری زیر است:

  • total - یک بسته شامل کلیدهای currency و value ، هر دو کلید دارای مقادیر رشته‌ای هستند.
  • shippingOptions - آرایه‌ای از گزینه‌های ارسال قابل بسته‌بندی
  • error - رشته‌ای حاوی یک پیام خطای عمومی (مثلاً وقتی changeShippingOption شناسه گزینه حمل و نقل معتبری ارائه نمی‌دهد)
  • stringifiedPaymentMethodErrors - یک رشته JSON که خطاهای اعتبارسنجی برای روش پرداخت را نشان می‌دهد.
  • addressErrors - یک بسته با کلیدهای اختیاری مشابه آدرس ارسال و مقادیر رشته‌ای. هر کلید نشان‌دهنده یک خطای اعتبارسنجی مربوط به بخش مربوطه از آدرس ارسال است.
  • modifiers - آرایه‌ای قابل تقسیم از Bundleها، که هر کدام دارای یک total و یک فیلد methodData هستند که آنها نیز Bundle هستند.

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