تقديم معلومات الشحن والاتصال من تطبيق دفع على Android

كيفية تحديث تطبيق الدفع على Android لتوفير عنوان الشحن ومعلومات الاتصال الخاصة بالجهة المسدِّدة باستخدام واجهات برمجة التطبيقات Web Payments API

Sahel Sharify
Sahel Sharify

يمكن أن يكون إدخال عنوان الشحن ومعلومات الاتصال من خلال نموذج ويب تجربة مرهقة للعملاء. يمكن أن تتسبب في حدوث أخطاء وانخفاض الإحالات الناجحة المعدل.

هذا هو السبب في أن واجهة برمجة التطبيقات Payment Request API تتيح ميزة طلب الشحن وعنوانك ومعلومات الاتصال الخاصة بك. يوفر ذلك مزايا متعددة:

  • ويمكن للمستخدمين اختيار العنوان الصحيح ببضع نقرات فقط.
  • ويتم إرجاع العنوان دائمًا بالعنوان القياسي .
  • ومن غير المرجح أن يتم إرسال عنوان غير صحيح.

يمكن للمتصفحات تأجيل جمع عنوان الشحن ومعلومات الاتصال إلى تطبيق للدفع لتقديم تجربة دفع موحّدة. هذه الوظيفة تسمى التفويض.

يفوض Chrome، كلما أمكن ذلك، بجمع معلومات الشحن الخاصة بالعميل العنوان ومعلومات الاتصال إلى تطبيق الدفع على Android الذي تم استدعاؤه. تشير رسالة الأشكال البيانية أن التفويض يقلل من المعوقات أثناء الدفع.

يمكن أن يعدّل الموقع الإلكتروني للتاجر بشكل ديناميكي خيارات الشحن والسعر الإجمالي. اعتمادًا على اختيار العميل لعنوان الشحن والشحن الخيار.

يتم تغيير خيار الشحن وعنوان الشحن. ويمكنك الاطّلاع على كيفية تأثيره في خيارات الشحن والسعر الإجمالي ديناميكيًا.

لإضافة إتاحة التفويض إلى تطبيق حالي للدفع على Android، يُرجى اتّباع الخطوات التالية: نفِّذ الخطوات التالية:

  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/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 كهدف الإضافية.

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 مع قيم السلسلة.
  • 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 true.
  • shippingAddress: عنوان الشحن الذي قدّمه المستخدم يجب أن يكون هذا حزمة غير فارغة عندما يكون paymentOptions.requestShipping صحيحًا. الحزمة على المفاتيح التالية التي تمثل أجزاءً مختلفة في دالة عنوانك.
    • city
    • countryCode
    • dependentLocality
    • organization
    • phone
    • postalCode
    • recipient
    • region
    • sortingCode
    • addressLine تشتمل جميع المفاتيح غير addressLine على قيم سلسلة. addressLine عبارة عن صفيف من السلاسل.
  • shippingOptionId: معرّف خيار الشحن الذي اختاره المستخدم هذا النمط يجب أن تكون سلسلة غير فارغة عندما تكون القيمة paymentOptions.requestShipping true.

التحقّق من صحة الرد على طلب الدفع

إذا كان النشاط نتيجة لرد دفعة تم استلامه من الدفعة التي تم استدعاؤها تم ضبط التطبيق على 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")
    }
}

اختياري: إتاحة التدفق الديناميكي

في بعض الأحيان، تزداد التكلفة الإجمالية للمعاملة، كما هو الحال عندما ينفق المستخدم خيار الشحن السريع، أو عند إدراج قائمة الخيارات أو تتغير أسعارها عندما يختار المستخدم خدمة شحن دولي الخاص بك. عندما يقدّم تطبيقك عنوان الشحن أو خيار الشحن الذي اختاره المستخدم، يجب أن يكون قادرًا على إشعار التاجر بأي عنوان أو خيار شحن التغييرات وعرض تفاصيل الدفع المعدّلة للمستخدم (المقدمة من ).

لغة تعريف واجهة نظام Android ‏(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 المستخدَم في هدف بدء الخدمة على أحد القيم التالية اعتمادًا على المتصفّح الذي أجرى عملية الدفع طلبك.

قناة Chrome اسم الحزمة
إسطبل "com.android.chrome"
إصدار تجريبي "com.chrome.beta"
في وضع التطوير "com.chrome.dev"
الكاناري "com.chrome.canary"
Chromium "org.chromium.chrome"
مربّع البحث السريع من Google (أداة تضمين 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

يتم إشعار التاجر بالتغييرات في عنوان الشحن الذي قدّمه المستخدم. كروم سيتم البحث عن حزمة 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، ويحتوي كلا المفتاحين على قيم السلسلة
  • shippingOptions - مصفوفة الشحن الخيارات
  • error - سلسلة تحتوي على رسالة خطأ عامة (على سبيل المثال، عندما لا تقدّم changeShippingOption معرّف خيار شحن صالحًا)
  • stringifiedPaymentMethodErrors - سلسلة JSON تمثّل عملية التحقق من الصحة هناك أخطاء متعلّقة بطريقة الدفع
  • addressErrors - حزمة تحتوي على مفاتيح اختيارية مماثلة لسمة الشحن العنوان وسلسلة القيم. يمثِّل كل مفتاح خطأ في عملية التحقّق من الصحة المرتبط على جزء من عنوان الشحن.

ويعني عدم توفّر المفتاح أنّ قيمته لم تتغيّر.