הזנת פרטי משלוח ופרטים ליצירת קשר מאפליקציית תשלום ל-Android

איך מעדכנים את אפליקציית התשלום ל-Android כדי לספק כתובת למשלוח ופרטים ליצירת קשר עם משלם באמצעות ממשקי API של תשלומים באינטרנט.

Sahel Sharify
Sahel Sharify

תאריך פרסום: 17 ביולי 2020, עדכון אחרון: 27 במאי 2025

לקוחות עלולים להתקשות למלא טופס אינטרנטי כדי להזין כתובת למשלוח ופרטים ליצירת קשר. השימוש בשיטה הזו עלול לגרום לשגיאות ולהפחית את שיעור ההמרה.

לכן Payment Request API תומך בתכונה שמאפשרת לבקש כתובת למשלוח ופרטים ליצירת קשר. היתרונות של השיטה הזו:

  • המשתמשים יכולים לבחור את הכתובת הנכונה בכמה הקשות.
  • הכתובת תמיד מוחזרת בפורמט סטנדרטי.
  • הסיכוי לשלוח כתובת שגויה נמוך יותר.

דפדפנים יכולים לדחות את האיסוף של כתובת למשלוח ופרטים ליצירת קשר לאפליקציית תשלום, כדי לספק חוויית תשלום אחידה. הפונקציונליות הזו נקראת הענקת הרשאה.

בכל הזדמנות אפשרית, Chrome מעביר את איסוף כתובת המשלוח ופרטי הקשר של הלקוח לאפליקציית התשלום של Android שהופעלה. ההעברה הזו מצמצמת את החיכוך במהלך התשלום.

אתר המוכר יכול לעדכן באופן דינמי את אפשרויות המשלוח ואת המחיר הכולל בהתאם לבחירת הלקוח של כתובת המשלוח ואפשרות המשלוח.

שינוי אפשרות המשלוח והכתובת למשלוח בפועל. השינוי יתבצע באופן דינמי ותוכלו לראות איך הוא משפיע על אפשרויות המשלוח ועל המחיר הכולל.

כדי להוסיף תמיכה בהענקת הרשאה לאפליקציית תשלום קיימת ל-Android, צריך לבצע את השלבים הבאים:

  1. הצהרה על העברות הרשאות נתמכות
  2. ניתוח של תוספים של כוונת 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>

ניתוח של התוספים של הכוונה 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". האפליקציה יכולה להשתמש ברמז הזה בממשק המשתמש שלה כשהיא מבקשת את כתובת המשתמש או את אפשרויות המשלוח שהוא בוחר.

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 עם ערכי מחרוזת.
    • ‫currency מייצג את המטבע של עלות המשלוח, כקוד אלפביתי בן 3 אותיות בפורמט תקין של ISO4217
    • 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 הוא 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, ‏ Chrome יבדוק אם יש פרטים נוספים נדרשים בתוספים שלו. אם האימות נכשל, Chrome יחזיר הבטחה (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".'

דוגמת קוד לדוגמה של תגובה תקינה:

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, ויקרא ל-method‏ setPaymentDetailsUpdateService(service) כדי לספק לאפליקציית התשלום את נקודת הקצה IPaymentDetailsUpdateService לצורך קבלת הודעות על שינויים באמצעי התשלום, באפשרות המשלוח או בכתובת למשלוח של המשתמש.

משתמשים ב-packageManager.getPackagesForUid(Binder.getCallingUid()) כשמקבלים תקשורת בין תהליכים (IPC) כדי לוודא שלאפליקציה שהפעילה את הכוונות PAY יש אותו שם חבילה כמו לאפליקציה שהפעילה את השיטות IPaymentDetailsUpdateServiceCallback.

AIDL

יוצרים שני קובצי 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.

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 לא ריקה עם 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, לשני המפתחות יש ערכי מחרוזת
  • ‫shippingOptions – מערך הנתונים שניתן להעברה של shipping options
  • ‫error – מחרוזת שמכילה הודעת שגיאה כללית (למשל, אם הפונקציה changeShippingOption לא מספקת מזהה תקין של אפשרות משלוח)
  • ‫stringifiedPaymentMethodErrors - מחרוזת JSON שמייצגת שגיאות אימות של אמצעי התשלום
  • ‫addressErrors – חבילה עם מפתחות אופציונליים שזהים ל-shipping address ולערכי מחרוזת. כל מפתח מייצג שגיאת אימות שקשורה לחלק המתאים בכתובת למשלוח.
  • ‫modifiers – מערך של חבילות שאפשר להעביר, כל אחת עם השדות total ו-methodData, שהם גם חבילות.

מפתח שלא מופיע מציין שהערך שלו לא השתנה.