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

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

Sahel Şerif
Sahel Sharify

Web formu üzerinden gönderim adresi ve iletişim bilgileri girmek müşteriler için zahmetli bir deneyim olabilir. Bu durum hatalara ve dönüşüm oranının düşmesine neden olabilir.

Bu yüzden Payment Request API, gönderim adresi ve iletişim bilgilerini isteme özelliğini destekler. Bunun birden çok avantajı vardır:

  • Kullanıcılar birkaç dokunuşla doğru adresi seçebilir.
  • Adres her zaman standartlaştırılmış biçimde döndürülür.
  • Yanlış bir adres gönderme olasılığı daha düşüktü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.

Mümkün olduğunda Chrome, müşterilerin gönderim adresi ve iletişim bilgilerinin toplanması için yetkiyi, çağrılan Android ödeme uygulamasına verir. Bu yetki, ödeme sırasında daha az sorun yaşanmasını önler.

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.

Gönderim seçeneği ve gönderim adresi değişikliği uygulanır. Bu özelliğin, kargo seçeneklerini ve toplam fiyatı dinamik olarak nasıl etkilediğini 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. Gerekli ödeme seçenekleri için PAY amaç 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 gönderim seçeneğindeki değişiklikler hakkında satıcıyı bilgilendirin.
    2. Satıcıdan güncellenmiş ödeme ayrıntılarını (ör. seçilen gönderim seçeneğinin maliyetine göre düzenlenmiş toplam tutar) alın.

Desteklenen yetkileri bildirme

Ödeme uygulamasının sağlayabileceği ek bilgilerin listesi, tarayıcının bu bilgilerin toplanması konusunda uygulamanıza yetki verebilmesi için gereklidir. Desteklenen yetkileri uygulamanızın AndroidManifest.xml dosyasında <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çilmiş bir dize listesi olmalıdır:

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

Aşağıdaki örnekte yalnızca gönderim adresi ve ödeme yapan kişinin e-posta adresi belirtilebilir.

<?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 amaç eklerini ayrıştırma

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

paymentOptions

paymentOptions, satıcı tarafından belirtilen ödeme seçeneklerinin, uygulamanızda yetki desteği beyan ettiği 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 - Ödemeyi yapanın adının gerekli olup olmadığını belirten boole değeri.
  • requestPayerPhone - Ödemeyi yapan kişinin telefonunun gerekli olup olmadığını gösteren boole.
  • requestPayerEmail - Ödemeyi yapan kişinin e-postasının gerekli olup olmadığını gösteren boole.
  • requestShipping - Gönderim bilgilerinin gerekli olup olmadığını belirten boole değeridir.
  • shippingType - Gönderim 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çeneği 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 olacaktır.

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

Her bir kargo seçeneğinde aşağıdaki anahtarları içeren bir Bundle bulunur.

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

selected dışındaki tüm anahtarlar dize değerlerine sahiptir. 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 - Ödeyenin tam adı. paymentOptions.requestPayerName doğru olduğunda bu, boş olmayan bir dize olmalıdır.
  • payerPhone - Ödemeyi yapan kişinin telefon numarası. paymentOptions.requestPayerPhone doğru olduğunda bu, boş olmayan bir dize olmalıdır.
  • payerEmail: Ödemeyi yapan kişinin 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. Pakette fiziksel bir adreste farklı parçaları temsil eden aşağıdaki anahtarlar bulunmalıdır.
    • city
    • countryCode
    • dependentLocality
    • organization
    • phone
    • postalCode
    • recipient
    • region
    • sortingCode
    • addressLine addressLine dışındaki tüm anahtarlar dize değerlerine sahiptir. addressLine bir dize dizisidir.
  • shippingOptionId - Kullanıcı tarafından seçilen kargo 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ğrulayın

Çağrılan ödeme uygulamasından alınan ödeme yanıtının etkinlik sonucu RESULT_OK olarak ayarlanırsa Chrome, gerekli ek bilgileri ek özelliklerinde kontrol eder. Doğrulama başarısız olursa Chrome, request.show() tarafından gönderilen aşağıdaki hata mesajlarından biriyle birlikte reddedilen bir 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

Kullanıcı ekspres kargo seçeneğini tercih ettiğinde veya kullanıcı uluslararası bir kargo adresi seçtiğinde mevcut kargo seçeneklerinin listesinin ya da fiyatlarının değişmesi gibi durumlarda bir işlemin toplam maliyeti bazen artar. Uygulamanız kullanıcı tarafından seçilen gönderim adresini veya seçeneğini sunduğunda, tüm gönderim adresleri ya da seçenek değişiklikleri hakkında satıcıyı bilgilendirebilmeli ve kullanıcıya güncellenmiş ödeme ayrıntılarını (satıcı tarafından sağlanan) gösterebilmelidir.

AIDL

Satıcıyı yeni değişiklikler hakkında bilgilendirmek için Chrome'un AndroidManifest.xml dosyasında beyan edilen 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 belirlediği ödeme yöntemi, gönderim adresi veya gönderim seçeneğindeki değişiklikler hakkında satıcıyı bilgilendirme

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şlatma 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 Çabuk Arama Kutusu (bir Web Katmanı gömme aracı) "com.google.android.googlequicksearchbox"

changePaymentMethod

Kullanıcı tarafından seçilen ödeme yöntemindeki değişiklikler hakkında satıcıyı bilgilendirir. paymentHandlerMethodData paketi, her ikisi de dize değerlerine sahip methodName ve isteğe bağlı details anahtarları içerir. Chrome, boş olmayan bir methodName içeren boş olmayan paket olup olmadığını kontrol eder ve doğrulama başarısız olursa 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

Kullanıcı tarafından seçilen gönderim seçeneğindeki değişiklikler hakkında satıcıyı bilgilendirir. shippingOptionId, satıcı tarafından belirtilen gönderim seçeneklerinden birinin tanımlayıcısı olmalıdır. Chrome, boş olmayan bir shippingOptionId olup olmadığını 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.

'Shipping option identifier required.'

changeShippingAddress

Kullanıcı tarafından sağlanan gönderim adresindeki değişiklikler hakkında satıcıyı bilgilendirir. Chrome, geçerli bir countryCode içeren boş olmayan shippingAddress paketi olup olmadığını kontrol eder ve doğrulama başarısız olursa callback.updateWith aracılığıyla 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 çıkartılmış updatePaymentDetails paketiyle callback.updateWith çağırır. Paket, "Invalid state" içeren yalnızca error anahtarını içerir. Geçersiz duruma örnekler:

  • Chrome, satıcının önceki bir değişikliğe (ör. devam eden değişiklik etkinliği) yanıt vermesini beklerken.
  • Ödeme uygulaması tarafından sağlanan gönderim seçeneği tanımlayıcısı, satıcı tarafından belirtilen gönderim seçeneklerinden 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, PaymentRequestDetailsUpdate WebIDL sözlüğüne eş değer bir pakettir (modifiers alanı çıkartıldıktan sonra) ve aşağıdaki isteğe bağlı anahtarları içerir:

  • total - currency ve value anahtarları içeren bir paket; her iki anahtar da dize değerlerine sahiptir
  • shippingOptions: Parselable gönderim seçenekleri dizisi
  • error - Genel bir hata mesajı içeren dize (ör. changeShippingOption geçerli bir gönderim seçeneği tanımlayıcısı sunmadığında)
  • stringifiedPaymentMethodErrors - Ödeme yöntemiyle ilgili doğrulama hatalarını temsil eden bir JSON dizesi
  • addressErrors: Gönderim adresi ve dize değerleri ile aynı isteğe bağlı anahtarlara sahip bir pakettir. Her anahtar, gönderim adresinin karşılık gelen bölümüyle ilgili bir doğrulama hatasını temsil eder.

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