Android ödeme uygulamanızı Web Ödemeleri ile çalışacak şekilde nasıl uyarlayacağınızı ve müşterilere daha iyi bir kullanıcı deneyimi nasıl sunacağınızı öğrenin.
Payment Request API, web'e kullanıcıların gerekli ödeme bilgilerini her zamankinden daha kolay girmesini sağlayan tarayıcı tabanlı yerleşik bir arayüz sunar. API, platforma özel ödeme uygulamalarını da çağırabilir.
Yalnızca Android Intent'leri kullanmaya kıyasla Web Payments, tarayıcı, güvenlik ve kullanıcı deneyimiyle daha iyi entegrasyon sağlar:
- Ödeme uygulaması, satıcı web sitesi bağlamında modal olarak başlatılır.
- Mevcut ödeme uygulamanıza ek olarak uygulanan bu çözüm, kullanıcı tabanınızdan yararlanmanızı sağlar.
- Bilinmeyen kaynaklardan yükleme işlemini önlemek için ödeme uygulamasının imzası kontrol edilir.
- Ödeme uygulamaları birden fazla ödeme yöntemini destekleyebilir.
- Kripto para birimi, banka havaleleri ve daha fazlası gibi tüm ödeme yöntemleri entegre edilebilir. Android cihazlardaki ödeme uygulamaları, cihazdaki donanım çipine erişmeyi gerektiren yöntemleri bile entegre edebilir.
Web ödemelerini bir Android ödeme uygulamasına uygulamak için dört adım gerekir:
- Satıcıların ödeme uygulamanızı keşfetmesine izin verin.
- Bir müşterinin ödeme yapmaya hazır kayıtlı bir aracısı (ör. kredi kartı) olup olmadığını satıcıya bildirin.
- Müşterinin ödeme yapmasına izin verin.
- Arayanı imzalama sertifikasını doğrulayın.
Web ödemelerinin nasıl kullanıldığı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
Satıcıların ödeme uygulamanızı kullanabilmesi için PaymentRequest API'yi kullanmaları ve ödeme yöntemi tanımlayıcısını kullanarak desteklediğiniz ödeme yöntemini belirtmeleri 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 yapmaya hazır bir kayıtlı aracının olup olmadığını satıcıya bildirin
Satıcı, hasEnrolledInstrument()
'ü arayarak müşterinin ödeme yapıp yapamayacağını sorgulayabilir. Bu sorguyu yanıtlamak için IS_READY_TO_PAY
uygulamasını bir Android hizmeti olarak uygulayabilirsiniz.
AndroidManifest.xml
Hizmetinizi, org.chromium.intent.action.IS_READY_TO_PAY
işlemini içeren bir intent filtresiyle beyan edin.
<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
işlevinin en basit uygulaması aşağıdaki örnekte gösterilmektedir:
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())
// …
Arayan paketinin doğru imzaya sahip olduğunu doğrulama hakkında bilgi edinmek için Arayanın imzalama sertifikasını doğrulama başlıklı makaleyi inceleyin.
3. Adım: Müşterinin ödeme yapmasına izin verin
Satıcı, müşterinin ödeme yapabilmesi amacıyla ödeme uygulamasını başlatmak için show()
numaralı telefonu arar. Ödeme uygulaması, intent parametrelerinde işlem bilgileri bulunan bir Android intent'i PAY
aracılığıyla çağrılır.
Ödeme uygulaması, ödeme uygulamasına özgü olan ve tarayıcı tarafından görülemeyen methodName
ve details
ile yanıt verir. Tarayıcı, details
dizesini JSON'dan serileştirme yoluyla satıcı için JavaScript nesnesine dönüştürür ancak bunun dışında herhangi bir geçerlilik koşulu uygulamaz. Tarayıcı, details
parametresini değiştirmez; bu parametrenin değeri doğrudan satıcıya iletilir.
AndroidManifest.xml
PAY
intent filtresine sahip etkinlikte, uygulamanın varsayılan ödeme yöntemi tanımlayıcısını tanımlayan bir <meta-data>
etiketi olmalıdır.
Birden fazla ödeme yöntemini desteklemek için <string-array>
kaynağı içeren 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
, her biri burada gösterildiği gibi HTTPS şemasına sahip geçerli ve mutlak bir URL olan dizelerin listesi 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, Intent ekstraları olarak etkinliğe iletilir:
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
ile methodData
arasındaki eşleme.
val methodData: Bundle? = extras.getBundle("methodData")
merchantName
Satıcının ödeme sayfasının <title>
HTML etiketinin içeriği (tarayıcının üst düzey tarama bağlamı).
val merchantName: String? = extras.getString("merchantName")
topLevelOrigin
Satıcının şeması olmayan kaynağı (üst düzey tarama bağlamının şeması olmayan kaynağı). Örneğin, https://mystore.com/checkout
mystore.com
olarak iletilir.
val topLevelOrigin: String? = extras.getString("topLevelOrigin")
topLevelCertificateChain
Satıcının sertifika zinciri (Üst düzey tarama bağlamının sertifika zinciri). Hem SSL sertifikası olmayan güvenli bağlamlar olan localhost hem de diskteki dosya için null. Her Parcelable
, certificate
anahtarı ve bayt dizisi değeri içeren 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 göz atma 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")
Aşağıda dizenin örnek içeriği verilmiştir:
{"currency":"USD","value":"25.00"}
modifiers
details.modifiers
yalnızca supportedMethods
ve total
içeriyorsa JSON.stringify(details.modifiers)
işlevinin çıkışı.
paymentRequestId
"Ödeme gönderme" uygulamalarının işlem durumuyla ilişkilendirmesi gereken PaymentRequest.id
alanı. Satıcı web siteleri, işlemin bant dışı durumu için "push" 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
ile 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 belirtmeniz gerekir:
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
isedetails
,JSON.parse(details)
başarılı olacak şekilde yapılandırılmalıdır.
İşlem ödeme uygulamasında tamamlanmadıysa (ör. kullanıcı ödeme uygulamasında hesabının doğru PIN kodunu yazamadıysa) RESULT_CANCELED
değerini 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 bir ö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 reddedilen sözü döndürür ve aşağıdaki hata mesajlarından birini gösterir:
'Payment app returned invalid response. Missing field "details".'
'Payment app returned invalid response. Missing field "methodName".'
İzin
Etkinlik, getCallingPackage()
yöntemiyle arayanı kontrol edebilir.
val caller: String? = callingPackage
Son adımda, arayan paketinin doğru imzaya sahip olduğunu onaylamak için arayanın imzalama sertifikasını doğrulayın.
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 üzerini hedefliyorsanız ve tek bir imzalama sertifikasına sahip bir tarayıcı ile 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 şekilde işlediğinden tek sertifika tarayıcıları için PackageManager.hasSigningCertificate()
tercih edilir. (Chrome'un tek bir imzalama sertifikası vardır.) Birden fazla imzalama sertifikası olan uygulamalar bu sertifikaları döndüremese de
27 ve önceki API düzeylerini desteklemeniz veya birden fazla imzalama sertifikası olan tarayıcıları yönetmeniz gerekiyorsa PackageManager.GET_SIGNATURES
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) } }