איך לעדכן את אפליקציית התשלומים ב-Android כדי לספק כתובת למשלוח ופרטים ליצירת קשר עם המשלם באמצעות ממשקי Web Payments API.
הזנת כתובת למשלוח ופרטים ליצירת קשר בטופס אינטרנט יכולה להיות חוויה מסורבלת ללקוחות. הוא עלול לגרום לשגיאות ולשיעור המרות נמוך יותר.
לכן, ב-Payment Request API יש תמיכה בתכונה לבקשת כתובת למשלוח ופרטים ליצירת קשר. יש לכך כמה יתרונות:
- המשתמשים יכולים לבחור את הכתובת הנכונה בכמה הקשות פשוטות.
- הכתובת תמיד מוחזרת בפורמט סטנדרטי.
- אם שולחים כתובת לא נכונה, יש סיכוי נמוך יותר.
דפדפנים יכולים לדחות את איסוף הכתובת למשלוח והפרטים ליצירת קשר לאפליקציית תשלום כדי לספק חוויית תשלום אחידה. הפונקציונליות הזו נקראת הענקת גישה.
כשזה אפשרי, Chrome מעניק גישה לאיסוף הכתובת למשלוח והפרטים ליצירת קשר של הלקוחות לאפליקציית התשלומים שמופעלת ב-Android. כך תקל על תהליך התשלום.
באתר של המוכר אפשר לעדכן באופן דינמי את אפשרויות המשלוח ואת המחיר הכולל, בהתאם לבחירת הלקוח לכתובת למשלוח ולאפשרות המשלוח.
כדי להוסיף תמיכה בהענקת גישה לאפליקציית תשלומים קיימת ל-Android, צריך לבצע את השלבים הבאים:
- להצהיר על סמכויות גישה שנתמכות
- ניתוח תוספות של Intent
PAY
לאפשרויות התשלום הנדרשות. - לספק את המידע הנדרש בתגובה לתשלום.
- [אופציונלי] תמיכה בזרימה דינמית:
הצהרה על סמכויות גישה שנתמכות
הדפדפן צריך לדעת את רשימת הפרטים הנוספים שאפליקציית התשלומים יכולה לספק, כדי להעניק גישה לאיסוף המידע הזה לאפליקציה שלכם. צריך להצהיר על הענקת הגישה הנתמכות כ-<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>
ניתוח של תוספות Intent מסוג PAY
לאפשרויות התשלום הנדרשות
המוכר יכול לציין פרטים נדרשים נוספים באמצעות המילון paymentOptions
. Chrome יספק את רשימת האפשרויות הנדרשות שהאפליקציה שלכם יכולה לספק על ידי העברת הפרמטרים הבאים לפעילות PAY
כתוספות של Intent.
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
מציג את המטבע של עלות המשלוח, כקוד אלפביתי בן 3 אותיות בפורמט 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)
לספק את המידע הנדרש בתגובה לתשלום
האפליקציה צריכה לכלול את המידע הנוסף הנדרש בתגובה שלה לפעילות של PAY
.
כדי לעשות זאת, יש לציין את הפרמטרים הבאים כתוספות ל-Intent:
payerName
- השם המלא של המשלם. המחרוזת צריכה להיות לא ריקה אם הערך שלpaymentOptions.requestPayerName
הוא TRUE.payerPhone
- מספר הטלפון של המשלם. המחרוזת צריכה להיות לא ריקה אם הערך שלpaymentOptions.requestPayerPhone
הוא TRUE.payerEmail
- כתובת האימייל של המשלם. כשהערך שלpaymentOptions.requestPayerEmail
הוא TRUE, הוא צריך להיות מחרוזת לא ריקה.shippingAddress
– הכתובת למשלוח שסופקה על ידי המשתמש. כשהערך שלpaymentOptions.requestShipping
הוא TRUE, החבילה צריכה להיות לא ריקה. החבילה צריכה לכלול את המפתחות הבאים, שמייצגים חלקים שונים בכתובת פיזית.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")
}
}
אופציונלי: תמיכה בזרימה דינמית
לפעמים העלות הכוללת של העסקה עולה, למשל כשהמשתמשים בוחרים באפשרות של משלוח מהיר, או כשרשימת אפשרויות המשלוח הזמינות או המחירים שלהן משתנים כשהמשתמש בוחר כתובת למשלוח בינלאומי. כשבאפליקציה מוצגות הכתובת למשלוח או אפשרות המשלוח שנבחרו על ידי המשתמש, צריך ליידע את המוכר על כל שינוי בכתובת או באפשרות למשלוח ולהציג למשתמש את פרטי התשלום המעודכנים (שהמוכר סיפק).
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
שמשמש ל-Intent ההתחלה של השירות יכול לקבל אחד מהערכים הבאים, בהתאם לדפדפן שממנו נשלחה בקשת התשלום.
ערוץ 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
המוכר מודיע למוכר על שינויים בכתובת למשלוח שסופקה על ידי המשתמש. Chrome יחפש חבילת 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
– חבילה עם מפתחות אופציונליים שזהים לכתובת למשלוח ולערכי מחרוזות. כל מפתח מייצג שגיאת אימות שקשורה לחלק התואם שלו בכתובת למשלוח.
אם מפתח חסר, הערך שלו לא השתנה.