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

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

Sahel Sharify
Sahel Sharify

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

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

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

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

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

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

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

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

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

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

ניתוח של רכיבי ה-intent הנוספים מסוג 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.

כדי לעשות זאת, צריך לציין את הפרמטרים הבאים כפרמטרים נוספים של כוונת החיפוש:

  • payerName – השם המלא של המשלם. המחרוזת הזו צריכה להיות לא ריקה כשהערך של paymentOptions.requestPayerName הוא TRUE.
  • payerPhone – מספר הטלפון של המשלם. המחרוזת הזו צריכה להיות לא ריקה כשהערך של paymentOptions.requestPayerPhone הוא TRUE.
  • payerEmail – כתובת האימייל של המשלם. המחרוזת הזו צריכה להיות לא ריקה כש-paymentOptions.requestPayerEmail נכון.
  • shippingAddress – כתובת המשלוח שסיפק המשתמש. הערך הזה צריך להיות חבילה לא ריקה כשהערך של paymentOptions.requestShipping הוא true. החבילה צריכה לכלול את המפתחות הבאים, שמייצגים חלקים שונים בכתובת פיזית.
    • countryCode
    • postalCode
    • sortingCode
    • region
    • city
    • dependentLocality
    • addressLine
    • organization
    • recipient
    • phone לכל המפתחות מלבד 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".'

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

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 באמצעות מסנן הכוונה UPDATE_PAYMENT_DETAILS.

מיד אחרי ההפעלה של הכוונה PAY, Chrome יתחבר לשירות UPDATE_PAYMENT_DETAILS (אם הוא קיים) באותה החבילה שבה נמצאת הכוונה PAY, ויבצע קריאה ל-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 הוא החבילה המקבילה למילון WebIDL של PaymentRequestDetailsUpdate, והיא מכילה את המפתחות האופציונליים הבאים:

  • total – חבילה שמכילה את המפתחות currency ו-value, וששני המפתחות מכילים ערכים של מחרוזות
  • shippingOptions – מערך של אפשרויות משלוח שאפשר לשלוח בדואר
  • error – מחרוזת שמכילה הודעת שגיאה גנרית (למשל, כשהערך של changeShippingOption לא מכיל מזהה תקין של אפשרות משלוח)
  • stringifiedPaymentMethodErrors – מחרוזת JSON שמייצגת שגיאות אימות של אמצעי התשלום
  • addressErrors – חבילה עם מפתחות אופציונליים זהים ל-shipping address וערכים של מחרוזות. כל מפתח מייצג שגיאת אימות שקשורה לחלק המתאים של הכתובת למשלוח.
  • modifiers – מערך של חבילות שניתן לחלוקה, שכל אחת מהן מכילה שדה total ושדה methodData, שהם גם חבילות.

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