Android ödeme uygulamasından gönderim ve iletişim bilgileri sağlama

Web Payments API'leriyle gönderim adresini ve ödeyen iletişim bilgilerini sağlamak için Android ödeme uygulamanızı güncelleme.

Sahel Sharify
Sahel Sharify

Bir web formu aracılığıyla gönderim adresi ve iletişim bilgilerini girmek müşteriler için zahmetli bir deneyim olabilir. Hatalara ve dönüşüm oranının düşmesine neden olabilir.

Bu nedenle Payment Request API, kargo adresi ve iletişim bilgilerini isteme özelliğini destekler. Bunun birden çok avantajı vardır:

  • Kullanıcılar yalnızca birkaç dokunuşla doğru adresi seçebilir.
  • Adres her zaman standartlaştırılmış biçimde döndürülür.
  • Yanlış adres gönderme olasılığınız azalır.

Tarayıcılar, birleşik bir ödeme deneyimi sunmak için gönderim adresi ve iletişim bilgilerinin toplanmasını bir ödeme uygulamasına erteleyebilir. Bu işleve yetki denir.

Chrome, mümkün olduğunda bir müşterinin kargo adresi ve iletişim bilgilerinin toplanması için çağrılan Android ödeme uygulamasına yetki verir. Bu yetki, ödeme sırasında karşılaşılan zorlukları azaltır.

Satıcı web sitesi, müşterinin gönderim adresi ve gönderim seçeneğine bağlı olarak gönderim seçeneklerini ve toplam fiyatı dinamik olarak güncelleyebilir.

Kargo seçeneği ve kargo adresi değişikliği yapılıyor. Bu durumun kargo seçeneklerini ve toplam fiyatı nasıl etkilediğini dinamik olarak görün.

Mevcut bir Android ödeme uygulamasına yetki desteği eklemek için aşağıdaki adımları uygulayın:

  1. Desteklenen yetkileri beyan edin.
  2. Zorunlu ödeme seçenekleri için PAY intent ekstralarını ayrıştırın.
  3. Ödeme yanıtında gerekli bilgileri sağlayın.
  4. [İsteğe bağlı] Dinamik akışı destekleyin:
    1. Kullanıcının seçtiği ödeme yöntemi, gönderim adresi veya kargo seçeneğindeki değişiklikler hakkında satıcıyı bilgilendirin.
    2. Satıcıdan güncel ödeme ayrıntılarını alın (örneğin, belirlenen kargo seçeneğinin maliyetine göre düzenlenmiş toplam tutar).

Desteklenen yetkileri bildirme

Tarayıcının, ödeme uygulamanızın sağlayabileceği ek bilgilerin listesini bilmesi gerekir. Böylece, bu bilgilerin toplanması için uygulamanıza yetki verilebilir. Uygulamanızın AndroidManifest.xml dosyasında, desteklenen yetkileri <meta-data> olarak beyan edin.

<activity
  android:name=".PaymentActivity"
  …
  <meta-data
    android:name="org.chromium.payment_supported_delegations"
    android:resource="@array/supported_delegations" />
</activity>

<resource>, aşağıdaki geçerli değerlerden seçilen dizelerden oluşan bir liste olmalıdır:

[ "payerName", "payerEmail", "payerPhone", "shippingAddress" ]

Aşağıdaki örnekte yalnızca bir gönderim adresi ve ödemeyi yapanın e-posta adresi sağlanabilir.

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string-array name="supported_delegations">
    <item>payerEmail</item>
    <item>shippingAddress</item>
  </string-array>
</resources>

Gerekli ödeme seçenekleri için PAY intent ekstralarını ayrıştır

Satıcı, paymentOptions sözlüğünü kullanarak gerekli ek bilgileri belirtebilir. Chrome, aşağıdaki parametreleri PAY etkinliğine Amaç ayrıntıları olarak ileterek uygulamanızın sağlayabileceği gerekli seçeneklerin listesini sağlar.

paymentOptions

paymentOptions, uygulamanızın yetki desteği beyan ettiği satıcı tarafından belirtilen ödeme seçeneklerinin alt kümesidir.

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")

Aşağıdaki parametreleri içerebilir:

  • requestPayerName: Ödeyen adının gerekli olup olmadığını gösteren boole değeri.
  • requestPayerPhone: Ödeyen telefonunun gerekli olup olmadığını gösteren boole değeri.
  • requestPayerEmail: Ödeyenin e-posta adresinin gerekli olup olmadığını gösteren boole değeri.
  • requestShipping: Kargo bilgilerinin gerekli olup olmadığını gösteren boole değeri.
  • shippingType: Kargo türünü gösteren dize. Kargo türü "shipping", "delivery" veya "pickup" olabilir. Uygulamanız, kullanıcının adresini veya gönderim seçeneklerini isterken kullanıcı arayüzünde bu ipucunu kullanabilir.

shippingOptions

shippingOptions, satıcı tarafından belirtilen kargo seçeneklerinin ayrıştırılabilir dizisidir. Bu parametre yalnızca paymentOptions.requestShipping == true olduğunda mevcut olur.

val shippingOptions: List<ShippingOption>? =
    extras.getParcelableArray("shippingOptions")?.mapNotNull {
        p -> from(p as Bundle)
    }

Her gönderim seçeneği, aşağıdaki anahtarlara sahip bir Bundle şeklindedir.

  • id: Gönderim seçeneği tanımlayıcısı.
  • label: Kullanıcıya gösterilen gönderim seçeneği etiketi.
  • amount - Dize değerlerine sahip currency ve value anahtarlarını içeren kargo maliyeti paketi.
  • selected - Ödeme uygulamasında kargo seçenekleri gösterildiğinde kargo seçeneğinin belirlenmesi gerekip gerekmediği.

selected dışındaki tüm anahtarların dize değerleri var. selected, bir boole değerine sahip.

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)

Ödeme yanıtında gerekli bilgileri sağlama

Uygulamanız, PAY etkinliğine verdiği yanıtta gerekli ek bilgileri içermelidir.

Bunun için aşağıdaki parametreler Intent ekstraları olarak belirtilmelidir:

  • payerName - Ödemeyi yapan kişinin tam adı. paymentOptions.requestPayerName doğru olduğunda bu, boş olmayan bir dize olmalıdır.
  • payerPhone - Ödemeyi yapan kullanıcının telefon numarası. paymentOptions.requestPayerPhone doğru olduğunda bu, boş olmayan bir dize olmalıdır.
  • payerEmail - Ödeyenin e-posta adresi. paymentOptions.requestPayerEmail doğru olduğunda bu, boş olmayan bir dize olmalıdır.
  • shippingAddress: Kullanıcı tarafından sağlanan gönderim adresi. paymentOptions.requestShipping doğru olduğunda bu, boş olmayan bir paket olmalıdır. Paket, fiziksel bir adresin farklı bölümlerini temsil eden aşağıdaki anahtarları içermelidir.
    • city
    • countryCode
    • dependentLocality
    • organization
    • phone
    • postalCode
    • recipient
    • region
    • sortingCode
    • addressLine addressLine dışındaki tüm anahtarlar dize değerlerine sahip. addressLine, bir dize dizisidir.
  • shippingOptionId - Kullanıcı tarafından seçilen gönderim seçeneğinin tanımlayıcısı. paymentOptions.requestShipping doğru olduğunda bu, boş olmayan bir dize olmalıdır.

Ödeme yanıtını doğrula

Çağrılan ödeme uygulamasından alınan ödeme yanıtının etkinlik sonucu RESULT_OK olarak ayarlanırsa Chrome, ekstra bilgilerinde gerekli ek bilgileri kontrol eder. Doğrulama başarısız olursa Chrome, geliştiriciye yönelik aşağıdaki hata mesajlarından biriyle request.show() tarafından gönderilen reddedilen sözü döndürür:

'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".'

Aşağıdaki kod örneği geçerli bir yanıt örneğidir:

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")
    }
}

İsteğe bağlı: Dinamik akışı destekleme

Bazen bir işlemin toplam maliyeti artar. Örneğin, kullanıcı ekspres kargo seçeneğini belirlediğinde veya kullanıcı uluslararası bir kargo adresi seçtiğinde mevcut kargo seçeneklerinin listesi ya da fiyatları değişirse. Uygulamanız, kullanıcı tarafından seçilen gönderim adresini veya seçeneğini sağladığında, gönderim adresi ya da seçenek değişiklikleri hakkında satıcıya bilgi verebilmeli ve kullanıcıya güncel ödeme ayrıntılarını (satıcı tarafından sağlanır) gösterebilmelidir.

AIDL

Satıcıyı yeni değişiklikler hakkında bilgilendirmek için Chrome'un AndroidManifest.xml dosyasında belirtilen PaymentDetailsUpdateService hizmetini kullanın. Bu hizmeti kullanmak için aşağıdaki içeriğe sahip iki AIDL dosyası oluşturun:

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);
}

Kullanıcının seçtiği ödeme yöntemi, gönderim adresi veya gönderim seçeneğinde yapılan değişiklikler hakkında satıcıya bilgi verme

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
        }
    }
}

Hizmetin başlangıç amacı için kullanılan callingPackageName, ödeme isteğini başlatan tarayıcıya bağlı olarak aşağıdaki değerlerden birine sahip olabilir.

Chrome Kanalı Paket Adı
Kararlı "com.android.chrome"
Beta "com.chrome.beta"
Dev "com.chrome.dev"
Canary "com.chrome.canary"
Chromium "org.chromium.chrome"
Google Hızlı Arama Kutusu (bir WebKatman yerleştirme aracı) "com.google.android.googlequicksearchbox"

changePaymentMethod

Satıcıyı, kullanıcı tarafından seçilen ödeme yöntemindeki değişiklikler hakkında bilgilendirir. paymentHandlerMethodData paketi, her ikisi de dize değerlerine sahip methodName ve isteğe bağlı details anahtarları içerir. Doğrulama başarısız olursa Chrome, boş olmayan bir methodName içeren paket olup olmadığını kontrol eder ve callback.updateWith aracılığıyla aşağıdaki hata mesajlarından birini içeren bir updatePaymentDetails gönderir.

'Method data required.'
'Method name required.'

changeShippingOption

Satıcıyı, kullanıcı tarafından belirlenen gönderim seçeneğindeki değişiklikler hakkında bilgilendirir. shippingOptionId, satıcı tarafından belirtilen kargo seçeneklerinden birinin tanımlayıcısı olmalıdır. Doğrulama başarısız olursa Chrome, boş olmayan bir shippingOptionId olup olmadığını kontrol edecek ve callback.updateWith aracılığıyla updatePaymentDetails aracılığıyla aşağıdaki hata mesajını gönderecektir.

'Shipping option identifier required.'

changeShippingAddress

Satıcıyı, kullanıcı tarafından sağlanan gönderim adresindeki değişiklikler hakkında bilgilendirir. Chrome, boş olmayan bir shippingAddress paketi olup olmadığını geçerli bir countryCode öğesi ile kontrol eder ve doğrulama başarısız olursa callback.updateWith üzerinden aşağıdaki hata mesajını içeren bir updatePaymentDetails gönderir.

'Payment app returned invalid shipping address in response.'

Geçersiz durum hata mesajı

Chrome, değişiklik isteklerinden herhangi birini aldıktan sonra geçersiz bir durumla karşılaşırsa callback.updateWith uygulamasını, çıkartılmış bir updatePaymentDetails paketiyle çağırır. Paket yalnızca "Invalid state" içeren error anahtarını içerecek. Geçersiz durum örnekleri şunlardır:

  • Chrome, satıcının önceki bir değişikliğe (ör. devam eden bir değişiklik etkinliği) karşı yanıtını beklerken hâlâ bekleme aşamasındadır.
  • Ödeme uygulaması tarafından sağlanan kargo seçeneği tanımlayıcısı, satıcı tarafından belirtilen kargo seçeneklerinin hiçbirine ait değil.

Satıcıdan güncel ödeme ayrıntılarını alma

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, (modifiers alanı çıkarıldıktan sonra) PaymentRequestDetailsUpdate WebIDL sözlüğüne eş değer olan pakettir ve aşağıdaki isteğe bağlı anahtarları içerir:

  • total - currency ve value anahtarlarını içeren bir paket (her iki anahtarın da dize değerleri var)
  • shippingOptions - Paketlenebilir gönderim seçenekleri dizisi
  • error - Genel bir hata mesajı içeren dize (ör. changeShippingOption geçerli bir kargo seçeneği tanımlayıcısı sağlamadığında)
  • stringifiedPaymentMethodErrors - Ödeme yöntemiyle ilgili doğrulama hatalarını temsil eden bir JSON dizesi
  • addressErrors - Gönderim adresi ve dize değerleriyle aynı olan isteğe bağlı anahtarlara sahip bir paket. Her anahtar, gönderim adresinin karşılık gelen kısmıyla ilgili bir doğrulama hatasını temsil eder.

Anahtarın eksik olması, değerinin değişmediği anlamına gelir.