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

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

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

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

  • Chrome: 60.
  • Edge: 15.
  • Firefox: फ़्लैग के पीछे.
  • Safari: 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 सेवा के लिए एपीआई, एआईडीएल में तय किया गया है. इस कॉन्टेंट वाली दो एआईडीएल फ़ाइलें बनाएं:

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> टैग होना चाहिए. यह टैग, ऐप्लिकेशन के लिए पैसे चुकाने के डिफ़ॉल्ट तरीके के आइडेंटिफ़ायर की पहचान करता है.

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

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