Android ödeme uygulamanızı Web Payments ile çalışacak şekilde nasıl uyarlayacağınızı ve müşterilere daha iyi bir kullanıcı deneyimi sunacağınızı öğrenin.
Yayınlanma tarihi: 5 Mayıs 2020, Son güncelleme tarihi: 27 Mayıs 2025
Payment Request API, web'e kullanıcıların gerekli ödeme bilgilerini her zamankinden daha kolay girmelerine olanak tanıyan yerleşik bir tarayıcı tabanlı arayüz getirir. 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.
- Uygulama, mevcut ödeme uygulamanıza ek olarak 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şimi 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ı doğrulama 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
Web uygulaması manifest dosyasında related_applications
mülkünü Ödeme yöntemi oluşturma bölümündeki talimatlara göre ayarlayın.
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: Bir müşterinin ödeme yapmaya hazır kayıtlı bir aracısı olup olmadığını satıcıya bildirin
Satıcı, müşterinin ödeme yapıp yapamayacağını sorgulamak için hasEnrolledInstrument()
'ü arayabilir. Bu sorguyu yanıtlamak için IS_READY_TO_PAY
'ü 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ımlanır. Aşağıdaki içeriğe sahip iki AIDL dosyası oluşturun:
org/chromium/IsReadyToPayServiceCallback.aidl
package org.chromium;
interface IsReadyToPayServiceCallback {
oneway void handleIsReadyToPay(boolean isReadyToPay);
}
org/chromium/IsReadyToPayService.aidl
package org.chromium;
import org.chromium.IsReadyToPayServiceCallback;
interface IsReadyToPayService {
oneway void isReadyToPay(IsReadyToPayServiceCallback callback, in Bundle parameters);
}
IsReadyToPayService
kullanımı
IsReadyToPayService
işlevinin en basit uygulaması aşağıdaki örnekte gösterilmektedir:
Kotlin
class SampleIsReadyToPayService : Service() {
private val binder = object : IsReadyToPayService.Stub() {
override fun isReadyToPay(callback: IsReadyToPayServiceCallback?, parameters: Bundle?) {
callback?.handleIsReadyToPay(true)
}
}
override fun onBind(intent: Intent?): IBinder? {
return binder
}
}
Java
import org.chromium.IsReadyToPayService;
public class SampleIsReadyToPayService extends Service {
private final IsReadyToPayService.Stub mBinder =
new IsReadyToPayService.Stub() {
@Override
public void isReadyToPay(IsReadyToPayServiceCallback callback, Bundle parameters) {
if (callback != null) {
callback.handleIsReadyToPay(true);
}
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
Yanıt
Hizmet, yanıtını handleIsReadyToPay(Boolean)
yöntemini kullanarak gönderebilir.
Kotlin
callback?.handleIsReadyToPay(true)
Java
if (callback != null) {
callback.handleIsReadyToPay(true);
}
İzin
Arayanın kim olduğunu kontrol etmek için Binder.getCallingUid()
kullanabilirsiniz. Android OS, hizmet bağlantısını önbelleğe alıp yeniden kullanabildiğinden ve bu da onBind()
yöntemini tetiklemediğinden, bunu onBind
yönteminde değil, isReadyToPay
yönteminde yapmanız gerektiğini unutmayın.
Kotlin
override fun isReadyToPay(callback: IsReadyToPayServiceCallback?, parameters: Bundle?) {
try {
val untrustedPackageName = parameters?.getString("packageName")
val actualPackageNames = packageManager.getPackagesForUid(Binder.getCallingUid())
// ...
Java
@Override
public void isReadyToPay(IsReadyToPayServiceCallback callback, Bundle parameters) {
try {
String untrustedPackageName = parameters != null
? parameters.getString("packageName")
: null;
String[] actualPackageNames = packageManager.getPackagesForUid(Binder.getCallingUid());
// ...
İşlemler Arası İletişim (IPC) çağrıları alırken her zaman null
için giriş parametrelerini kontrol edin. Android OS'in farklı sürümleri veya çatalları beklenmedik şekilde davranabileceği ve uygun şekilde ele alınmadığı takdirde hatalara yol açabileceği için bu özellikle önemlidir.
packageManager.getPackagesForUid()
genellikle tek bir öğe döndürür ancak kodunuz, bir araya çağıranın birden fazla paket adı kullandığı yaygın olmayan senaryoyu ele almalıdır. Bu sayede uygulamanızın sağlam kalmasını sağlayabilirsiniz.
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.
Parametreler
parameters
paketi Chrome 139'a eklendi. Her zaman null
ile karşılaştırılmalıdır.
Aşağıdaki parametreler parameters
paketinde hizmete iletilir:
packageName
methodNames
methodData
topLevelOrigin
paymentRequestOrigin
topLevelCertificateChain
packageName
, Chrome 138'e eklendi. Değerini kullanmadan önce bu parametreyi Binder.getCallingUid()
ile doğrulamanız gerekir. parameters
paketi arayan kullanıcının tam kontrolü altındayken Binder.getCallingUid()
Android OS tarafından kontrol edildiği için bu doğrulama işlemi gereklidir.
topLevelCertificateChain
, WebView'de ve genellikle yerel test için kullanılan https olmayan web sitelerinde (ör. http://localhost
) null
olur.
3. Adım: Müşterinin ödeme yapmasına izin verin
Satıcı, müşterinin ödeme yapabilmesi için show()
'i arayarak ödeme uygulamasını başlatır. Ödeme uygulaması, intent parametrelerinde işlem bilgileri bulunan bir Android intent'i PAY
kullanılarak ç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ı, JSON dizesi serileştirmesini kullanarak details
dizesini satıcı için bir JavaScript sözlüğüne 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/chromium_payment_method_names" />
</activity>
android:resource
, her biri burada gösterildiği gibi HTTPS şemasına sahip geçerli ve mutlak bir URL olması gereken bir dize listesi olmalıdır.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="chromium_payment_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 iletilir:
methodNames
methodData
merchantName
topLevelOrigin
topLevelCertificateChain
paymentRequestOrigin
total
modifiers
paymentRequestId
paymentOptions
shippingOptions
Kotlin
val extras: Bundle? = getIntent()?.extras
Java
Bundle extras = getIntent() != null ? getIntent().getExtras() : null;
methodNames
Kullanılan yöntemlerin adları. Öğeler, methodData
sözlüğündeki anahtarlardır. Bunlar, ödeme uygulamasının desteklediği yöntemlerdir.
Kotlin
val methodNames: List<String>? = extras.getStringArrayList("methodNames")
Java
List<String> methodNames = extras.getStringArrayList("methodNames");
methodData
methodNames
öğelerinin her biri ile methodData
arasında bir eşleme.
Kotlin
val methodData: Bundle? = extras.getBundle("methodData")
Java
Bundle methodData = 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ı).
Kotlin
val merchantName: String? = extras.getString("merchantName")
Java
String merchantName = 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.
Kotlin
val topLevelOrigin: String? = extras.getString("topLevelOrigin")
Java
String topLevelOrigin = extras.getString("topLevelOrigin");
topLevelCertificateChain
Satıcının sertifika zinciri (üst düzey tarama bağlamının sertifika zinciri). Değer, WebView, localhost veya diskteki bir dosya için null
olur.
Her Parcelable
, certificate
anahtarı ve bayt dizisi değeri içeren bir pakettir.
Kotlin
val topLevelCertificateChain: Array<Parcelable>? =
extras.getParcelableArray("topLevelCertificateChain")
val list: List<ByteArray>? = topLevelCertificateChain?.mapNotNull { p ->
(p as Bundle).getByteArray("certificate")
}
Java
Parcelable[] topLevelCertificateChain =
extras.getParcelableArray("topLevelCertificateChain");
if (topLevelCertificateChain != null) {
for (Parcelable p : topLevelCertificateChain) {
if (p != null && p instanceof Bundle) {
((Bundle) p).getByteArray("certificate");
}
}
}
paymentRequestOrigin
JavaScript'te new
PaymentRequest(methodData, details, options)
kurucusunu çağıran iframe tarama bağlamının şemasız kaynağı. Oluşturucu üst düzey bağlamda çağrıldıysa bu parametrenin değeri topLevelOrigin
parametresinin değerine eşittir.
Kotlin
val paymentRequestOrigin: String? = extras.getString("paymentRequestOrigin")
Java
String paymentRequestOrigin = extras.getString("paymentRequestOrigin");
total
İşlemin toplam tutarını temsil eden JSON dizesi.
Kotlin
val total: String? = extras.getString("total")
Java
String total = extras.getString("total");
Aşağıda dizenin örnek içeriği verilmiştir:
{"currency":"USD","value":"25.00"}
modifiers
details.modifiers
yalnızca supportedMethods
, data
ve total
içeriyorsa JSON.stringify(details.modifiers)
çıkışı.
paymentRequestId
"Ödeme gönderme" uygulamalarının işlem durumuyla ilişkilendirmesi gereken PaymentRequest.id
alanı. Satıcı web siteleri, "push-payment" uygulamalarını bant dışı işlem durumu için sorgulamak üzere bu alanı kullanır.
Kotlin
val paymentRequestId: String? = extras.getString("paymentRequestId")
Java
String paymentRequestId = extras.getString("paymentRequestId");
Yanıt
Etkinlik, yanıtını setResult
üzerinden RESULT_OK
ile geri gönderebilir.
Kotlin
setResult(Activity.RESULT_OK, Intent().apply {
putExtra("methodName", "https://bobbucks.dev/pay")
putExtra("details", "{\"token\": \"put-some-data-here\"}")
})
finish()
Java
Intent result = new Intent();
Bundle extras = new Bundle();
extras.putString("methodName", "https://bobbucks.dev/pay");
extras.putString("details", "{\"token\": \"put-some-data-here\"}");
result.putExtras(extras);
setResult(Activity.RESULT_OK, result);
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)
'nin başarılı olacağı şekilde oluşturulmalıdır. Döndürülmesi gereken veri yoksa bu dize"{}"
olabilir. Satıcı web sitesi, bu dizeyi boş bir JavaScript sözlüğü olarak alı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.
Kotlin
setResult(Activity.RESULT_CANCELED)
finish()
Java
setResult(Activity.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 reddedilen bir söz döndürür ve geliştiriciye 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 kişiyi kontrol edebilir.
Kotlin
val caller: String? = callingPackage
Java
String caller = getCallingPackage();
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()
, PAY
içinde ise Activity.getCallingPackage()
ile kontrol edebilirsiniz. Arayanın aklınızdaki tarayıcı olduğunu doğrulamak için imza sertifikasını kontrol etmeniz ve doğru değerle eşleştiğinden emin olmanız gerekir.
API düzeyi 28 ve sonraki sürümleri hedefliyorsanız ve tek bir imzalama sertifikasına sahip bir tarayıcı ile entegrasyon yapıyorsanız PackageManager.hasSigningCertificate()
kullanabilirsiniz.
Kotlin
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
)
Java
String packageName = … // The caller's package name
byte[] certificate = … // The correct signing certificate
boolean verified = packageManager.hasSigningCertificate(
callingPackage,
certificate,
PackageManager.CERT_INPUT_SHA256);
PackageManager.hasSigningCertificate()
, sertifika rotasyonunu doğru şekilde yönettiğinden tek sertifika tarayıcıları için tercih edilir. (Chrome'un tek bir imzalama sertifikası vardır.) Birden fazla imzalama sertifikası olan uygulamalar bu sertifikaları döndüremese de
API 27 ve önceki sürümleri desteklemeniz veya birden fazla imzalama sertifikası olan tarayıcıları yönetmeniz gerekiyorsa PackageManager.GET_SIGNATURES
kullanabilirsiniz.
Kotlin
val packageName: String = … // The caller's package name
val expected: Set<String> = … // The correct set of signing certificates
val packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
val sha256 = MessageDigest.getInstance("SHA-256")
val actual = packageInfo.signatures.map {
SerializeByteArrayToString(sha256.digest(it.toByteArray()))
}
val verified = actual.equals(expected)
Java
String packageName = … // The caller's package name
Set<String> expected = … // The correct set of signing certificates
PackageInfo packageInfo =
packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
Set<String> actual = new HashSet<>();
for (Signature it : packageInfo.signatures) {
actual.add(SerializeByteArrayToString(sha256.digest(it.toByteArray())));
}
boolean verified = actual.equals(expected);
Hata Ayıklama
Hataları veya bilgilendirme mesajlarını gözlemlemek için aşağıdaki komutu kullanın:
adb logcat | grep -i pay