वेब पेमेंट के साथ काम करने और ग्राहकों के लिए बेहतर उपयोगकर्ता अनुभव देने के लिए, अपने Android पेमेंट ऐप्लिकेशन को इसके हिसाब से ढालने का तरीका जानें.
पेमेंट रिक्वेस्ट एपीआई, वेब पर ब्राउज़र पर आधारित इंटरफ़ेस उपलब्ध कराता है. इससे लोग, क्रेडिट/डेबिट कार्ड की ज़रूरी जानकारी आसानी से डाल सकते हैं. यह एपीआई, प्लैटफ़ॉर्म के हिसाब से बने पेमेंट ऐप्लिकेशन भी शुरू कर सकता है.
सिर्फ़ Android इंटेंट के मुकाबले वेब पेमेंट, ब्राउज़र, सुरक्षा, और उपयोगकर्ता अनुभव के साथ बेहतर इंटिग्रेशन की सुविधा देता है:
- कारोबारी या कंपनी की वेबसाइट के हिसाब से, पेमेंट ऐप्लिकेशन को मॉडल के तौर पर लॉन्च किया गया हो.
- पेमेंट के तरीके को लागू करना, आपके मौजूदा पेमेंट ऐप्लिकेशन के अलावा, अन्य काम भी करता है. इससे आपको अपने उपयोगकर्ता आधार का फ़ायदा लेने में मदद मिलती है.
- साइडलोडिंग को रोकने के लिए, पेमेंट ऐप्लिकेशन के हस्ताक्षर की जांच की जाती है.
- पेमेंट ऐप्लिकेशन में, पेमेंट के एक से ज़्यादा तरीके काम कर सकते हैं.
- क्रिप्टो करंसी, बैंक ट्रांसफ़र जैसे पेमेंट के किसी भी तरीके को इंटिग्रेट किया जा सकता है. Android डिवाइसों पर मौजूद पेमेंट ऐप्लिकेशन, उन तरीकों को भी इंटिग्रेट कर सकते हैं जिनके लिए डिवाइस के हार्डवेयर चिप के ऐक्सेस की ज़रूरत होती है.
किसी Android भुगतान ऐप्लिकेशन में वेब भुगतान लागू करने के लिए चार चरणों की आवश्यकता है:
- कारोबारियों या कंपनियों को अपना पेमेंट ऐप्लिकेशन खोजने दें.
- कारोबारी या कंपनी को बताएं कि खरीदार के पास रजिस्टर किया गया कोई इंस्ट्रुमेंट (जैसे, क्रेडिट कार्ड) है या नहीं, जो पैसे चुकाने के लिए तैयार है.
- ग्राहक को पेमेंट करने दें.
- कॉल करने वाले (कॉलर) के साइनिंग सर्टिफ़िकेट की पुष्टि करें.
वेब पेमेंट को काम करते हुए देखने के लिए, 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) } }