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

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

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

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

  • 60
  • 15
  • 11.1

सोर्स

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

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

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

किसी Android भुगतान ऐप्लिकेशन में वेब भुगतान लागू करने के लिए चार चरणों की आवश्यकता है:

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

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

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

किसी कारोबारी या कंपनी को आपके पेमेंट ऐप्लिकेशन का इस्तेमाल करने के लिए, पेमेंट का अनुरोध करने के लिए एपीआई का इस्तेमाल करना होगा. साथ ही, पेमेंट के तरीके के आइडेंटिफ़ायर का इस्तेमाल करके, पेमेंट का आपका तरीका बताना होगा.

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

दूसरा चरण: कारोबारी या कंपनी को यह बताना कि क्या खरीदार के पास रजिस्टर किया गया वह इंस्ट्रुमेंट है जिससे पेमेंट किया जा सकता है

कारोबारी, 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 सेवा के लिए एपीआई की जानकारी एआईडीएल में दी गई है. इस कॉन्टेंट वाली दो एआईडीएल फ़ाइलें बनाएं:

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

जवाब

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

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