Android पेमेंट ऐप्लिकेशन डेवलपर गाइड

Android पेमेंट ऐप्लिकेशन को, वेब पेमेंट के साथ काम करने के लिए इस्तेमाल करने और ग्राहकों को बेहतर उपयोगकर्ता अनुभव देने का तरीका जानें.

युइची अराकी
युइची अराकी

पेमेंट अनुरोध एपीआई, वेब पर पहले से मौजूद ब्राउज़र पर आधारित इंटरफ़ेस होता है. इसकी मदद से, लोग पैसे चुकाने के बारे में ज़रूरी जानकारी पहले से ज़्यादा आसानी से डाल सकते हैं. एपीआई, प्लैटफ़ॉर्म के हिसाब से बने पेमेंट ऐप्लिकेशन भी शुरू कर सकता है.

ब्राउज़र सहायता

  • 60
  • 15
  • 11.1

सोर्स

अलग-अलग प्लैटफ़ॉर्म के हिसाब से, Google Pay ऐप्लिकेशन में चेकआउट करने की प्रोसेस, जिसमें वेब पेमेंट का इस्तेमाल होता है.

सिर्फ़ Android इंटेंट के इस्तेमाल की तुलना में, वेब पेमेंट से ब्राउज़र, सुरक्षा, और उपयोगकर्ता अनुभव के साथ बेहतर इंटिग्रेशन मिलता है:

  • पेमेंट ऐप्लिकेशन को, कारोबारी या कंपनी की वेबसाइट के लिए, एक मॉडल के तौर पर लॉन्च किया गया है.
  • इसे लागू करना, आपके मौजूदा पेमेंट ऐप्लिकेशन की एक और सुविधा है. इससे आपको अपने उपयोगकर्ता आधार का फ़ायदा मिलता है.
  • साइडलोडिंग से बचने के लिए, पेमेंट ऐप्लिकेशन के हस्ताक्षर की जांच की जाती है.
  • पेमेंट ऐप्लिकेशन में, पेमेंट के एक से ज़्यादा तरीकों का इस्तेमाल किया जा सकता है.
  • क्रिप्टो करंसी, बैंक ट्रांसफ़र जैसे पेमेंट के किसी भी तरीके को इंटिग्रेट किया जा सकता है. Android डिवाइसों पर मौजूद पेमेंट ऐप्लिकेशन, ऐसे तरीकों को भी इंटिग्रेट कर सकते हैं जिनके लिए डिवाइस में मौजूद हार्डवेयर चिप का ऐक्सेस ज़रूरी होता है.

किसी Android पेमेंट ऐप्लिकेशन में वेब पेमेंट की सुविधा लागू करने के लिए, चार चरणों की ज़रूरत होती है:

  1. कारोबारी या कंपनी को अपना पेमेंट ऐप्लिकेशन खोजने दें.
  2. कारोबारी को बताएं कि ग्राहक के पास रजिस्टर किया गया कोई तरीका (जैसे कि क्रेडिट कार्ड) है या नहीं, जो पैसे चुकाने के लिए तैयार है.
  3. ग्राहक को पेमेंट करने की अनुमति दें.
  4. कॉलर के साइनिंग सर्टिफ़िकेट की पुष्टि करें.

वेब भुगतान का तरीका देखने के लिए, android-web-payment डेमो देखें.

पहला चरण: कारोबारियों को अपना पेमेंट ऐप्लिकेशन खोजने देना

कारोबारी या कंपनी आपके पेमेंट ऐप्लिकेशन का इस्तेमाल कर सके, इसके लिए उसे Payment Request API का इस्तेमाल करना होगा. साथ ही, पेमेंट के तरीके के आइडेंटिफ़ायर का इस्तेमाल करके, पेमेंट का आपका तरीका बताना होगा.

अगर आपके पेमेंट ऐप्लिकेशन के लिए, पेमेंट के तरीके का आइडेंटिफ़ायर यूनीक है, तो पैसे चुकाने के तरीके की जानकारी सेट अप की जा सकती है, ताकि ब्राउज़र आपके ऐप्लिकेशन को खोज सकें.

दूसरा चरण: व्यापारी/कंपनी को यह बताना कि ग्राहक के पास कोई ऐसा तरीका है या नहीं जो पैसे चुकाने के लिए तैयार है

व्यापारी/कंपनी, hasEnrolledInstrument() को कॉल करके यह पूछ सकती है कि ग्राहक पेमेंट कर सकता है या नहीं. इस क्वेरी का जवाब देने के लिए, IS_READY_TO_PAY को Android सेवा के तौर पर लागू किया जा सकता है.

AndroidManifest.xml

org.chromium.intent.action.IS_READY_TO_PAY कार्रवाई के साथ इंटेंट फ़िल्टर की मदद से अपनी सेवा का एलान करें.

<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 सेवा ज़रूरी नहीं है. अगर पेमेंट ऐप्लिकेशन में ऐसा कोई इंटेंट हैंडलर नहीं है, तो वेब ब्राउज़र यह मानता है कि ऐप्लिकेशन हमेशा पेमेंट कर सकता है.

एआईडीएल

IS_READY_TO_PAY सेवा के लिए एपीआई की जानकारी, AIDL में दी गई है. इस कॉन्टेंट वाली दो AIDL बनाएं:

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 लागू करना

यहां दिए गए उदाहरण में, IsReadyToPayService को सबसे आसानी से लागू किया जा सकता है:

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

जवाब

सेवा handleIsReadyToPay(Boolean) तरीके से अपना जवाब भेज सकती है.

callback?.handleIsReadyToPay(true)

अनुमति

Binder.getCallingUid() का इस्तेमाल करके पता लगाया जा सकता है कि कॉलर कौन है. ध्यान दें कि ऐसा आपको isReadyToPay तरीके का इस्तेमाल करके करना है, न कि onBind तरीके में.

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

यह पुष्टि करने का तरीका जानने के लिए कि कॉल करने वाले पैकेज पर सही हस्ताक्षर है या नहीं, कॉलर के साइनिंग सर्टिफ़िकेट की पुष्टि करें देखें.

तीसरा चरण: ग्राहक को पेमेंट करने की अनुमति देना

व्यापारी/कंपनी/कारोबारी, show() को कॉल करके पेमेंट ऐप्लिकेशन लॉन्च करें, ताकि ग्राहक पेमेंट कर सके. पेमेंट ऐप्लिकेशन, Android इंटेंट PAY से शुरू किया जाता है. इसमें इंटेंट पैरामीटर में लेन-देन की जानकारी शामिल होती है.

पेमेंट ऐप्लिकेशन, methodName और details के साथ रिस्पॉन्स करता है. ये पेमेंट ऐप्लिकेशन से जुड़े होते हैं और ब्राउज़र पर काम नहीं करते. ब्राउज़र, JSON डीज़रियलाइज़ेशन की मदद से, details स्ट्रिंग को कारोबारी के लिए JavaScript ऑब्जेक्ट में बदल देता है. हालांकि, इसके बाद किसी मान्य वैल्यू को लागू नहीं करता. ब्राउज़र, details में बदलाव नहीं करता है. इस पैरामीटर की वैल्यू सीधे व्यापारी या कंपनी को भेज दी जाती है.

AndroidManifest.xml

PAY इंटेंट फ़िल्टर वाली गतिविधि में <meta-data> टैग होना चाहिए, जो ऐप्लिकेशन के लिए पेमेंट के डिफ़ॉल्ट तरीके के आइडेंटिफ़ायर की पहचान करता हो.

पेमेंट के एक से ज़्यादा तरीकों का इस्तेमाल करने के लिए, <string-array> संसाधन के साथ <meta-data> टैग जोड़ें.

<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, स्ट्रिंग की एक सूची होनी चाहिए. हर स्ट्रिंग, एचटीटीपीएस स्कीम वाला मान्य और पूरा यूआरएल होना चाहिए, जैसा कि यहां दिखाया गया है.

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

पैरामीटर

नीचे दिए गए पैरामीटर, गतिविधि को इंटेंट के अतिरिक्त एलिमेंट के तौर पर पास किए जाते हैं:

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

methodNames

इस्तेमाल किए जा रहे तरीकों के नाम. एलिमेंट, methodData शब्दकोश में मौजूद कुंजियां हैं. पेमेंट ऐप्लिकेशन में, ये तरीके इस्तेमाल किए जा सकते हैं.

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

methodData

हर methodNames से methodData के लिए मैपिंग.

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

merchantName

कारोबारी के चेकआउट पेज के <title> एचटीएमएल टैग का कॉन्टेंट (ब्राउज़र का टॉप लेवल ब्राउज़िंग कॉन्टेक्स्ट).

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

topLevelOrigin

स्कीम के बिना कारोबारी या कंपनी का ऑरिजिन (टॉप लेवल ब्राउज़िंग कॉन्टेक्स्ट का स्कीम-लेस ऑरिजिन). उदाहरण के लिए, https://mystore.com/checkout को mystore.com के तौर पर पास किया गया है.

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

topLevelCertificateChain

कारोबारी की सर्टिफ़िकेट चेन (टॉप-लेवल ब्राउज़िंग कॉन्टेक्स्ट की सर्टिफ़िकेट चेन). localhost और डिस्क पर फ़ाइल के लिए शून्य, जो दोनों ही एसएसएल सर्टिफ़िकेट के बिना सुरक्षित कॉन्टेक्स्ट हैं. हर Parcelable एक बंडल है, जिसमें certificate कुंजी और बाइट कलेक्शन की वैल्यू होती है.

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

paymentRequestOrigin

iframe ब्राउज़िंग कॉन्टेक्स्ट का स्कीम-लेस ऑरिजिन, जिसने JavaScript में new PaymentRequest(methodData, details, options) कंस्ट्रक्टर को शुरू किया. अगर कंस्ट्रक्टर को टॉप-लेवल कॉन्टेक्स्ट से शुरू किया गया था, तो इस पैरामीटर की वैल्यू topLevelOrigin पैरामीटर की वैल्यू के बराबर होगी.

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

total

JSON स्ट्रिंग, ट्रांज़ैक्शन की कुल रकम दिखाती है.

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

स्ट्रिंग के कॉन्टेंट का एक उदाहरण यहां दिया गया है:

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

modifiers

JSON.stringify(details.modifiers) का आउटपुट, जहां details.modifiers में सिर्फ़ supportedMethods और total होते हैं.

paymentRequestId

"पुश-पेमेंट" ऐप्लिकेशन को PaymentRequest.id फ़ील्ड, लेन-देन की स्थिति से जुड़ा होना चाहिए. व्यापारी वेबसाइट इस फ़ील्ड का इस्तेमाल करके बैंड के बाहर लेन-देन की स्थिति के बारे में "पुश-पेमेंट" ऐप्लिकेशन से क्वेरी कर सकती हैं.

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

जवाब

गतिविधि, RESULT_OK की मदद से setResult के ज़रिए अपना जवाब वापस भेज सकती है.

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

इंटेंट अतिरिक्त के तौर पर आपको दो पैरामीटर तय करने होंगे:

  • methodName: इस्तेमाल किए जा रहे तरीके का नाम.
  • details: JSON स्ट्रिंग में वह जानकारी होती है जो व्यापारी/कंपनी/कारोबारी के लिए, लेन-देन पूरा करने के लिए ज़रूरी है. अगर सफलता true है, तो details को इस तरह से बनाया जाना चाहिए कि JSON.parse(details) काम कर सके.

अगर पेमेंट ऐप्लिकेशन में लेन-देन पूरा नहीं हुआ है, तो आपके पास RESULT_CANCELED को पास करने का विकल्प है. उदाहरण के लिए, अगर उपयोगकर्ता पेमेंट ऐप्लिकेशन में अपने खाते के लिए सही पिन कोड नहीं डाल पाए. ब्राउज़र, उपयोगकर्ता को कोई दूसरा पेमेंट ऐप्लिकेशन चुनने की अनुमति दे सकता है.

setResult(RESULT_CANCELED)
finish()

अगर शुरू किए गए पेमेंट ऐप्लिकेशन से मिले पेमेंट के जवाब की गतिविधि का नतीजा RESULT_OK पर सेट है, तो Chrome खाली नहीं methodName और details की जांच करेगा. अगर पुष्टि नहीं हो पाती है, तो Chrome request.show() का अस्वीकार किया गया वादा लौटाएगा. इसमें, डेवलपर को गड़बड़ी का इनमें से कोई एक मैसेज दिखेगा:

'Payment app returned invalid response. Missing field "details".'
'Payment app returned invalid response. Missing field "methodName".'

अनुमति

गतिविधि, getCallingPackage() तरीके की मदद से कॉलर की जांच कर सकती है.

val caller: String? = callingPackage

आखिरी चरण में, कॉलर के साइनिंग सर्टिफ़िकेट की पुष्टि की जाती है. ऐसा करके यह पक्का किया जाता है कि कॉल करने के पैकेज पर सही हस्ताक्षर है या नहीं.

चौथा चरण: कॉलर के साइनिंग सर्टिफ़िकेट की पुष्टि करना

कॉलर के पैकेज का नाम देखने के लिए, IS_READY_TO_PAY में Binder.getCallingUid() और PAY में Activity.getCallingPackage() डालें. आपके हिसाब से कॉल करने वाला ब्राउज़र ही है, इस बात की पुष्टि करने के लिए आपको इसके साइनिंग सर्टिफ़िकेट की जांच करनी चाहिए. साथ ही, यह पक्का करना चाहिए कि यह सही वैल्यू से मेल खाता हो.

अगर एपीआई लेवल 28 और इसके बाद के लेवल को टारगेट किया जा रहा है और आपको सिंगल साइनिंग सर्टिफ़िकेट वाले ब्राउज़र के साथ इंटिग्रेट करने की सुविधा चाहिए, तो PackageManager.hasSigningCertificate() का इस्तेमाल करें.

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
)

सिंगल सर्टिफ़िकेट वाले ब्राउज़र के लिए PackageManager.hasSigningCertificate() को प्राथमिकता दी जाती है, क्योंकि यह सर्टिफ़िकेट के रोटेशन को सही तरीके से मैनेज करता है. (Chrome में सिर्फ़ एक साइनिंग सर्टिफ़िकेट होता है.) जिन ऐप्लिकेशन के पास एक से ज़्यादा साइनिंग सर्टिफ़िकेट होते हैं, वे उन्हें रोटेट नहीं कर सकते.

अगर आपको एपीआई लेवल 27 और इससे पहले के वर्शन पर काम करना है या एक से ज़्यादा साइनिंग सर्टिफ़िकेट वाले ब्राउज़र का इस्तेमाल करना है, तो PackageManager.GET_SIGNATURES का इस्तेमाल करें.

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