Android ödeme uygulaması geliştiricileri kılavuzu

Android ödeme uygulamanızı Web Ödemeleri ile çalışacak ve müşterilere daha iyi bir kullanıcı deneyimi sunacak şekilde nasıl uyarlayacağınızı öğrenin.

Ödeme İsteği API'si web'e, kullanıcıların gerekli ödeme bilgilerini hiç olmadığı kadar kolay bir şekilde girmelerini sağlayan, tarayıcı tabanlı yerleşik bir arayüz sunuyor. API, platforma özel ödeme uygulamalarını da çağırabilir.

Tarayıcı Desteği

  • 60
  • 15
  • 11.1

Kaynak

Web Payments'ı kullanan platforma özel Google Pay uygulamasıyla ödeme akışı.

Yalnızca Android Intents'i kullanmaya kıyasla, Web Ödemeleri tarayıcı, güvenlik ve kullanıcı deneyimi ile daha iyi entegrasyona olanak tanır:

  • Ödeme uygulaması, satıcı web sitesi bağlamında kalıcı bir öğe olarak kullanıma sunuldu.
  • Uygulanması, mevcut ödeme uygulamanıza ek olarak kullanıcı tabanınızdan yararlanmanıza olanak tanır.
  • Başka cihazdan yüklemeyi önlemek için, ödeme uygulamasının imzası kontrol edilir.
  • Ödeme uygulamaları birden fazla ödeme yöntemini destekleyebilir.
  • Kripto para birimleri ve banka havaleleri gibi tüm ödeme yöntemleri entegre edilebilir. Android cihazlardaki ödeme uygulamaları, cihazdaki donanım çipine erişimi gerektiren yöntemleri bile entegre edebilir.

Web Ödemeleri'nin bir Android ödeme uygulamasına uygulanması dört adımdan oluşur:

  1. Satıcıların ödeme uygulamanızı keşfetmesine izin verin.
  2. Müşterinin kayıtlı bir aracının (ör. kredi kartı) olup olmadığını satıcıya bildirin.
  3. Müşterinin ödeme yapmasına izin verin.
  4. Arayanın imzalama sertifikasını doğrulayın.

Web Ödemelerinin nasıl çalıştığını görmek için android-web-payment demosuna göz atın.

1. Adım: Satıcıların ödeme uygulamanızı keşfetmesine izin verin

Bir satıcının ödeme uygulamanızı kullanabilmesi için PaymentRequest API'sini kullanması ve ödeme yöntemi tanımlayıcısını kullanarak desteklediğiniz ödeme yöntemini belirtmesi gerekir.

Ödeme uygulamanıza özgü bir ödeme yöntemi tanımlayıcınız varsa tarayıcıların uygulamanızı keşfedebilmesi için kendi ödeme yöntemi manifestinizi oluşturabilirsiniz.

2. Adım: Müşterinin ödeme için hazır bir aracı olup olmadığını satıcıya bildirin

Satıcı, müşterinin ödeme yapıp yapamadığını sorgulamak için hasEnrolledInstrument() numaralı telefonu arayabilir. Bu sorguyu yanıtlamak için IS_READY_TO_PAY hizmetini bir Android hizmeti olarak uygulayabilirsiniz.

AndroidManifest.xml

org.chromium.intent.action.IS_READY_TO_PAY işlemini kullanarak hizmetinizi bir amaç filtresiyle tanımlayın.

<service
  android:name=".SampleIsReadyToPayService"
  android:exported="true">
  <intent-filter>
    <action android:name="org.chromium.intent.action.IS_READY_TO_PAY" />
  </intent-filter>
</service>

IS_READY_TO_PAY hizmeti isteğe bağlıdır. Ödeme uygulamasında böyle bir intent işleyici yoksa web tarayıcısı, uygulamanın her zaman ödeme yapabileceğini varsayar.

AIDL

IS_READY_TO_PAY hizmetinin API'si, AIDL'de tanımlanmıştır. Aşağıdaki içeriğe sahip iki AIDL dosyası oluşturun:

app/src/main/aidl/org/chromium/IsReadyToPayServiceCallback.aidl

package org.chromium;
interface IsReadyToPayServiceCallback {
    oneway void handleIsReadyToPay(boolean isReadyToPay);
}

app/src/main/aidl/org/chromium/IsReadyToPayService.aidl

package org.chromium;
import org.chromium.IsReadyToPayServiceCallback;

interface IsReadyToPayService {
    oneway void isReadyToPay(IsReadyToPayServiceCallback callback);
}

IsReadyToPayService kullanımı

IsReadyToPayService öğesinin en basit uygulaması aşağıdaki örnekte gösterilmiştir:

class SampleIsReadyToPayService : Service() {
  private val binder = object : IsReadyToPayService.Stub() {
    override fun isReadyToPay(callback: IsReadyToPayServiceCallback?) {
      callback?.handleIsReadyToPay(true)
    }
  }

  override fun onBind(intent: Intent?): IBinder? {
    return binder
  }
}

Yanıt

Hizmet, yanıtını handleIsReadyToPay(Boolean) yöntemiyle gönderebilir.

callback?.handleIsReadyToPay(true)

İzin

Arayanın kim olduğunu kontrol etmek için Binder.getCallingUid() öğesini kullanabilirsiniz. Bunu onBind yönteminde değil, isReadyToPay yönteminde yapmanız gerektiğini unutmayın.

override fun isReadyToPay(callback: IsReadyToPayServiceCallback?) {
  try {
    val callingPackage = packageManager.getNameForUid(Binder.getCallingUid())
    // …

Çağrı paketinin doğru imzaya sahip olduğunu doğrulama hakkında bilgi edinmek için Arayanın imzalama sertifikasını doğrulama bölümüne bakın.

3. Adım: Müşterinin ödeme yapmasına izin verin

Satıcı, müşterinin ödeme yapabilmesi için show() numaralı telefonu arayarak ödeme uygulamasını başlatır. Ödeme uygulaması, amaç parametrelerinde işlem bilgileri olan bir Android amacı PAY aracılığıyla çağrılır.

Ödeme uygulaması, ödeme uygulamasına özel olan ve tarayıcı için şeffaf olmayan methodName ve details ile yanıt verir. Tarayıcı, JSON serileştirmesini devre dışı bırakarak details dizesini satıcı için bir JavaScript nesnesine dönüştürür ancak bunun dışındaki herhangi bir geçerliliği zorunlu kılmaz. Tarayıcı details özelliğini değiştirmez. Bu parametrenin değeri doğrudan satıcıya iletilir.

AndroidManifest.xml

PAY intent filtresine sahip etkinlikler, uygulama için varsayılan ödeme yöntemi tanımlayıcısını tanımlayan bir <meta-data> etiketine sahip olmalıdır.

Birden fazla ödeme yöntemini desteklemek için <string-array> kaynağı olan bir <meta-data> etiketi ekleyin.

<activity
  android:name=".PaymentActivity"
  android:theme="@style/Theme.SamplePay.Dialog">
  <intent-filter>
    <action android:name="org.chromium.intent.action.PAY" />
  </intent-filter>

  <meta-data
    android:name="org.chromium.default_payment_method_name"
    android:value="https://bobbucks.dev/pay" />
  <meta-data
    android:name="org.chromium.payment_method_names"
    android:resource="@array/method_names" />
</activity>

resource, burada gösterildiği gibi her biri HTTPS şemasına sahip geçerli ve mutlak bir URL olmalıdır.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="method_names">
        <item>https://alicepay.com/put/optional/path/here</item>
        <item>https://charliepay.com/put/optional/path/here</item>
    </string-array>
</resources>

Parametreler

Aşağıdaki parametreler etkinliğe Intent ekstraları olarak aktarılır:

  • methodNames
  • methodData
  • topLevelOrigin
  • topLevelCertificateChain
  • paymentRequestOrigin
  • total
  • modifiers
  • paymentRequestId
val extras: Bundle? = intent?.extras

methodNames

Kullanılan yöntemlerin adları. Öğeler, methodData sözlüğündeki anahtarlardır. Bunlar, ödeme uygulamasının desteklediği yöntemlerdir.

val methodNames: List<String>? = extras.getStringArrayList("methodNames")

methodData

Her bir methodNames öğesinden methodData öğesine bir eşleme.

val methodData: Bundle? = extras.getBundle("methodData")

merchantName

Satıcının ödeme sayfasındaki <title> HTML etiketinin içeriği (tarayıcının üst düzey göz atma bağlamı).

val merchantName: String? = extras.getString("merchantName")

topLevelOrigin

Satıcının şema olmadan kaynağı (Üst düzey göz atma bağlamının şemasız kaynağı). Örneğin, https://mystore.com/checkout, mystore.com olarak geçirilir.

val topLevelOrigin: String? = extras.getString("topLevelOrigin")

topLevelCertificateChain

Satıcının sertifika zinciri (Üst düzey göz atma bağlamının sertifika zinciri). Yerel ana makine ve diskteki dosya için null (her ikisi de SSL sertifikaları olmayan güvenli bağlamlar) Her Parcelable, certificate anahtarı ve bayt dizisi değerine sahip bir Pakettir.

val topLevelCertificateChain: Array<Parcelable>? =
    extras.getParcelableArray("topLevelCertificateChain")
val list: List<ByteArray>? = topLevelCertificateChain?.mapNotNull { p ->
  (p as Bundle).getByteArray("certificate")
}

paymentRequestOrigin

JavaScript'te new PaymentRequest(methodData, details, options) oluşturucuyu çağıran iframe tarama bağlamının şemasız kaynağı. Oluşturucu üst düzey bağlamdan çağrıldıysa bu parametrenin değeri, topLevelOrigin parametresinin değerine eşit olur.

val paymentRequestOrigin: String? = extras.getString("paymentRequestOrigin")

total

İşlemin toplam tutarını temsil eden JSON dizesi.

val total: String? = extras.getString("total")

Dizeyle ilgili örnek bir içerik şöyledir:

{"currency":"USD","value":"25.00"}

modifiers

details.modifiers değerinin yalnızca supportedMethods ve total içerdiği JSON.stringify(details.modifiers) çıkışı.

paymentRequestId

"Push-ödeme" uygulamalarının işlem durumuyla ilişkilendirmesi gereken PaymentRequest.id alanı. Satıcı web siteleri, bant dışı işlem durumu için "push-ödeme" uygulamalarını sorgulamak amacıyla bu alanı kullanır.

val paymentRequestId: String? = extras.getString("paymentRequestId")

Yanıt

Etkinlik, yanıtını setResult üzerinden RESULT_OK aracılığıyla geri gönderebilir.

setResult(Activity.RESULT_OK, Intent().apply {
  putExtra("methodName", "https://bobbucks.dev/pay")
  putExtra("details", "{\"token\": \"put-some-data-here\"}")
})
finish()

Intent ekstraları olarak iki parametre belirtmelisiniz:

  • methodName: Kullanılan yöntemin adı.
  • details: Satıcının işlemi tamamlaması için gerekli bilgileri içeren JSON dizesi. Başarı true ise details, JSON.parse(details) öğesinin başarılı olacağı şekilde yapılandırılmalıdır.

İşlem, ödeme uygulamasında tamamlanmamışsa (örneğin, kullanıcı ödeme uygulamasında hesabı için doğru PIN kodunu giremediyse) RESULT_CANCELED numaralı telefonu iletebilirsiniz. Tarayıcı, kullanıcının farklı bir ödeme uygulaması seçmesine izin verebilir.

setResult(RESULT_CANCELED)
finish()

Çağrılan ödeme uygulamasından alınan ödeme yanıtının etkinlik sonucu RESULT_OK olarak ayarlanırsa Chrome, ekstralarında boş olmayan methodName ve details olup olmadığını 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 "details".'
'Payment app returned invalid response. Missing field "methodName".'

İzin

Etkinlik, arayanı getCallingPackage() yöntemiyle kontrol edebilir.

val caller: String? = callingPackage

Son adım, çağrı yapan paketin doğru imzaya sahip olduğunu onaylamak için çağrıyı yapanın imzalama sertifikasını doğrulamaktır.

4. adım: Arayanın imzalama sertifikasını doğrulayın

Arayanın paket adını IS_READY_TO_PAY içinde Binder.getCallingUid() ve PAY içinde Activity.getCallingPackage() ile kontrol edebilirsiniz. Arayanın aklınızdaki tarayıcı olduğunu gerçekten doğrulamak için imzalama sertifikasını kontrol etmeli ve doğru değerle eşleştiğinden emin olmalısınız.

API düzeyi 28 ve üstünü hedefliyorsanız ve tek bir imzalama sertifikasına sahip bir tarayıcıyla entegrasyon yapıyorsanız PackageManager.hasSigningCertificate() kullanabilirsiniz.

val packageName: String = … // The caller's package name
val certificate: ByteArray = … // The correct signing certificate.
val verified = packageManager.hasSigningCertificate(
  callingPackage,
  certificate,
  PackageManager.CERT_INPUT_SHA256
)

Sertifika rotasyonunu doğru bir şekilde işlediğinden PackageManager.hasSigningCertificate(), tek sertifikalı tarayıcılar için tercih edilir. (Chrome'un tek bir imzalama sertifikası vardır.) Birden çok imzalama sertifikası olan uygulamalar bu sertifikaları döndüremez.

27 ve daha eski API düzeylerini desteklemeniz veya birden fazla imzalama sertifikasına sahip tarayıcıları kullanmanız gerekiyorsa PackageManager.GET_SIGNATURES'yi kullanabilirsiniz.

val packageName: String = … // The caller's package name
val certificates: Set<ByteArray> = … // The correct set of signing certificates

val packageInfo = getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
val sha256 = MessageDigest.getInstance("SHA-256")
val signatures = packageInfo.signatures.map { sha256.digest(it.toByteArray()) }
val verified = signatures.size == certificates.size &&
    signatures.all { s -> certificates.any { it.contentEquals(s) } }