كيفية تحديث تطبيق الدفع على Android لتوفير عنوان الشحن ومعلومات الاتصال الخاصة بالجهة المسدِّدة باستخدام واجهات برمجة التطبيقات Web Payments API
يمكن أن يكون إدخال عنوان الشحن ومعلومات الاتصال من خلال نموذج ويب تجربة مرهقة للعملاء. يمكن أن تتسبب في حدوث أخطاء وانخفاض الإحالات الناجحة المعدل.
هذا هو السبب في أن واجهة برمجة التطبيقات Payment Request API تتيح ميزة طلب الشحن وعنوانك ومعلومات الاتصال الخاصة بك. يوفر ذلك مزايا متعددة:
- ويمكن للمستخدمين اختيار العنوان الصحيح ببضع نقرات فقط.
- ويتم إرجاع العنوان دائمًا بالعنوان القياسي .
- ومن غير المرجح أن يتم إرسال عنوان غير صحيح.
يمكن للمتصفحات تأجيل جمع عنوان الشحن ومعلومات الاتصال إلى تطبيق للدفع لتقديم تجربة دفع موحّدة. هذه الوظيفة تسمى التفويض.
يفوض Chrome، كلما أمكن ذلك، بجمع معلومات الشحن الخاصة بالعميل العنوان ومعلومات الاتصال إلى تطبيق الدفع على Android الذي تم استدعاؤه. تشير رسالة الأشكال البيانية أن التفويض يقلل من المعوقات أثناء الدفع.
يمكن أن يعدّل الموقع الإلكتروني للتاجر بشكل ديناميكي خيارات الشحن والسعر الإجمالي. اعتمادًا على اختيار العميل لعنوان الشحن والشحن الخيار.
لإضافة إتاحة التفويض إلى تطبيق حالي للدفع على Android، يُرجى اتّباع الخطوات التالية: نفِّذ الخطوات التالية:
- توضيح التفويضات المتوافقة
- تحليل
PAY
إضافات intent للدفعة المطلوبة الخيارات. - تقديم المعلومات المطلوبة عند الدفع الرد.
- [اختياري] إتاحة المسار الديناميكي:
تعريف التفويضات المتوافقة
يحتاج المتصفّح إلى معرفة قائمة المعلومات الإضافية التي يمكن أن تكون دفعتك
تطبيقك حتى يتمكن من تفويض جمع هذه المعلومات إلى
التطبيق. يُرجى تعريف التفويضات المتوافقة على أنّها <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
مع قيم السلسلة.- تعرض
currency
عملة تكلفة الشحن، تم صياغة ISO4217 بشكل جيد رمز أبجدي من 3 أحرف - تعرض
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
- حزمة تحتوي على مفاتيح اختيارية مماثلة لسمة الشحن العنوان وسلسلة القيم. يمثِّل كل مفتاح خطأ في عملية التحقّق من الصحة المرتبط على جزء من عنوان الشحن.
ويعني عدم توفّر المفتاح أنّ قيمته لم تتغيّر.