আপনার অ্যান্ড্রয়েড পেমেন্ট অ্যাপকে ওয়েব পেমেন্টের সাথে কাজ করার জন্য কীভাবে মানিয়ে নেবেন এবং গ্রাহকদের আরও ভালো ব্যবহারকারীর অভিজ্ঞতা দেবেন, তা শিখুন।
প্রকাশিত: ৫ মে, ২০২০, সর্বশেষ হালনাগাদ: ২৭ মে, ২০২৫
পেমেন্ট রিকোয়েস্ট এপিআই ওয়েবে একটি বিল্ট-ইন ব্রাউজার-ভিত্তিক ইন্টারফেস নিয়ে এসেছে, যা ব্যবহারকারীদের আগের চেয়ে অনেক সহজে প্রয়োজনীয় পেমেন্টের তথ্য প্রবেশ করাতে সাহায্য করে। এই এপিআই প্ল্যাটফর্ম-নির্দিষ্ট পেমেন্ট অ্যাপগুলোকেও চালু করতে পারে।
শুধুমাত্র অ্যান্ড্রয়েড ইন্টেন্ট ব্যবহারের তুলনায়, ওয়েব পেমেন্ট ব্রাউজারের সাথে আরও ভালো ইন্টিগ্রেশন, নিরাপত্তা এবং ব্যবহারকারীর অভিজ্ঞতা প্রদান করে:
- পেমেন্ট অ্যাপটি মার্চেন্ট ওয়েবসাইটের প্রেক্ষাপটে একটি মডেল হিসেবে চালু করা হয়।
- এর বাস্তবায়ন আপনার বিদ্যমান পেমেন্ট অ্যাপের পরিপূরক, যা আপনাকে আপনার ব্যবহারকারী গোষ্ঠীর সুবিধা নিতে সক্ষম করে।
- সাইডলোডিং প্রতিরোধ করার জন্য পেমেন্ট অ্যাপের সিগনেচার যাচাই করা হয়।
- পেমেন্ট অ্যাপগুলো একাধিক পেমেন্ট পদ্ধতি সমর্থন করতে পারে।
- ক্রিপ্টোকারেন্সি, ব্যাংক ট্রান্সফার এবং আরও অনেক কিছুর মতো যেকোনো পেমেন্ট পদ্ধতি ইন্টিগ্রেট করা যেতে পারে। অ্যান্ড্রয়েড ডিভাইসের পেমেন্ট অ্যাপগুলো এমন পদ্ধতিও ইন্টিগ্রেট করতে পারে, যেগুলোর জন্য ডিভাইসের হার্ডওয়্যার চিপে অ্যাক্সেসের প্রয়োজন হয়।
একটি অ্যান্ড্রয়েড পেমেন্ট অ্যাপে ওয়েব পেমেন্ট বাস্তবায়ন করতে চারটি ধাপ অনুসরণ করতে হয়:
- ব্যবসায়ীদের আপনার পেমেন্ট অ্যাপটি খুঁজে পেতে দিন।
- কোনো গ্রাহকের যদি অর্থ পরিশোধের জন্য প্রস্তুত কোনো নিবন্ধিত মাধ্যম (যেমন ক্রেডিট কার্ড) থাকে, তবে ব্যবসায়ীকে তা জানান।
- গ্রাহককে অর্থ পরিশোধ করতে দিন।
- কলারের সাইনিং সার্টিফিকেট যাচাই করুন।
ওয়েব পেমেন্ট বাস্তবে কেমন কাজ করে তা দেখতে, android-web-payment ডেমোটি দেখুন।
ধাপ ১: ব্যবসায়ীদের আপনার পেমেন্ট অ্যাপটি খুঁজে পেতে দিন
পেমেন্ট পদ্ধতি সেট আপ করার নির্দেশাবলী অনুসারে ওয়েব অ্যাপ ম্যানিফেস্টে related_applications প্রপার্টিটি সেট করুন।
কোনো মার্চেন্টকে আপনার পেমেন্ট অ্যাপ ব্যবহার করতে হলে, তাদের পেমেন্ট রিকোয়েস্ট এপিআই (Payment Request API) ব্যবহার করতে হবে এবং পেমেন্ট মেথড আইডেন্টিফায়ার (payment method identifier) ব্যবহার করে আপনার সমর্থিত পেমেন্ট পদ্ধতিটি নির্দিষ্ট করতে হবে।
আপনার পেমেন্ট অ্যাপের জন্য যদি একটি অনন্য পেমেন্ট মেথড আইডেন্টিফায়ার থাকে, তাহলে আপনি আপনার নিজস্ব পেমেন্ট মেথড ম্যানিফেস্ট সেট আপ করতে পারেন, যাতে ব্রাউজারগুলো আপনার অ্যাপটি খুঁজে পেতে পারে।
ধাপ ২: কোনো গ্রাহকের যদি অর্থ পরিশোধের জন্য প্রস্তুত কোনো নিবন্ধিত মাধ্যম থাকে, তবে ব্যবসায়ীকে তা জানান।
গ্রাহক পেমেন্ট করতে সক্ষম কিনা তা জানতে মার্চেন্ট hasEnrolledInstrument() কল করতে পারেন। এই জিজ্ঞাসার উত্তর দেওয়ার জন্য আপনি IS_READY_TO_PAY একটি অ্যান্ড্রয়েড সার্ভিস হিসেবে ইমপ্লিমেন্ট করতে পারেন।
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 সার্ভিসের API-টি AIDL-এ সংজ্ঞায়িত করা আছে। নিম্নলিখিত বিষয়বস্তু সহ দুটি AIDL ফাইল তৈরি করুন:
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 বাস্তবায়ন করা হচ্ছে
IsReadyToPayService এর সবচেয়ে সরল বাস্তবায়ন নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
কোটলিন
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
}
}
জাভা
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;
}
}
প্রতিক্রিয়া
সার্ভিসটি handleIsReadyToPay(Boolean) মেথড ব্যবহার করে তার প্রতিক্রিয়া পাঠাতে পারে।
কোটলিন
callback?.handleIsReadyToPay(true)
জাভা
if (callback != null) {
callback.handleIsReadyToPay(true);
}
অনুমতি
কলার কে তা যাচাই করতে আপনি Binder.getCallingUid() ব্যবহার করতে পারেন। মনে রাখবেন, আপনাকে এটি isReadyToPay মেথডে করতে হবে, onBind মেথডে নয়, কারণ অ্যান্ড্রয়েড ওএস সার্ভিস কানেকশনটি ক্যাশ করে পুনরায় ব্যবহার করতে পারে, যা onBind() মেথডটিকে ট্রিগার করে না।
কোটলিন
override fun isReadyToPay(callback: IsReadyToPayServiceCallback?, parameters: Bundle?) {
try {
val untrustedPackageName = parameters?.getString("packageName")
val actualPackageNames = packageManager.getPackagesForUid(Binder.getCallingUid())
// ...
জাভা
@Override
public void isReadyToPay(IsReadyToPayServiceCallback callback, Bundle parameters) {
try {
String untrustedPackageName = parameters != null
? parameters.getString("packageName")
: null;
String[] actualPackageNames = packageManager.getPackagesForUid(Binder.getCallingUid());
// ...
ইন্টার-প্রসেস কমিউনিকেশন (IPC) কল গ্রহণ করার সময় ইনপুট প্যারামিটারগুলো নাল ( null কিনা তা সর্বদা যাচাই করুন। এটি বিশেষভাবে গুরুত্বপূর্ণ, কারণ অ্যান্ড্রয়েড ওএস-এর বিভিন্ন সংস্করণ বা ফর্ক অপ্রত্যাশিতভাবে আচরণ করতে পারে এবং তা সঠিকভাবে পরিচালনা না করা হলে ত্রুটির কারণ হতে পারে।
যদিও packageManager.getPackagesForUid() সাধারণত একটিমাত্র এলিমেন্ট রিটার্ন করে, আপনার কোডকে অবশ্যই সেই বিরল পরিস্থিতিটি সামলাতে হবে যেখানে কোনো কলার একাধিক প্যাকেজের নাম ব্যবহার করে। এটি আপনার অ্যাপ্লিকেশনকে সুরক্ষিত রাখে।
কলিং প্যাকেজটিতে সঠিক সিগনেচার আছে কিনা, তা কীভাবে যাচাই করবেন সে সম্পর্কে জানতে “কলারের সাইনিং সার্টিফিকেট যাচাই করুন” অংশটি দেখুন।
প্যারামিটার
বান্ডেল (Bundle) parameters ক্রোম ১৩৯ সংস্করণে যোগ করা হয়েছে। এটিকে সবসময় null এর সাথে মিলিয়ে দেখা উচিত।
parameters বান্ডেলের মাধ্যমে সার্ভিসে নিম্নলিখিত প্যারামিটারগুলো পাঠানো হয়:
-
packageName -
methodNames -
methodData -
topLevelOrigin -
paymentRequestOrigin -
topLevelCertificateChain
packageName Chrome 138-এ যোগ করা হয়েছে। এর মান ব্যবহার করার আগে আপনাকে অবশ্যই Binder.getCallingUid() -এর সাথে এই প্যারামিটারটি যাচাই করে নিতে হবে। এই যাচাইকরণ অপরিহার্য, কারণ parameters বান্ডেলটি কলারের সম্পূর্ণ নিয়ন্ত্রণে থাকে, অপরদিকে Binder.getCallingUid() অ্যান্ড্রয়েড অপারেটিং সিস্টেম দ্বারা নিয়ন্ত্রিত হয়।
WebView-তে এবং http://localhost এর মতো নন-https ওয়েবসাইটগুলিতে, যেগুলো সাধারণত লোকাল টেস্টিংয়ের জন্য ব্যবহৃত হয়, topLevelCertificateChain null হয়।
ধাপ ৩: গ্রাহককে অর্থ পরিশোধ করতে দিন
মার্চেন্ট পেমেন্ট অ্যাপটি চালু করার জন্য show() কল করে, যাতে গ্রাহক পেমেন্ট করতে পারেন। পেমেন্ট অ্যাপটি PAY নামক একটি অ্যান্ড্রয়েড ইন্টেন্ট ব্যবহার করে চালু করা হয়, যার ইন্টেন্ট প্যারামিটারগুলিতে লেনদেনের তথ্য থাকে।
পেমেন্ট অ্যাপটি methodName এবং details দিয়ে সাড়া দেয়, যা পেমেন্ট অ্যাপ-নির্দিষ্ট এবং ব্রাউজারের কাছে অস্বচ্ছ। ব্রাউজারটি JSON স্ট্রিং ডিসিরিয়ালাইজেশন ব্যবহার করে ` details স্ট্রিংটিকে মার্চেন্টের জন্য একটি জাভাস্ক্রিপ্ট ডিকশনারিতে রূপান্তর করে, কিন্তু এর বাইরে কোনো বৈধতা বলবৎ করে না। ব্রাউজারটি ` 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/chromium_payment_method_names" />
</activity>
android:resource অবশ্যই স্ট্রিং-এর একটি তালিকা হতে হবে, যার প্রতিটি স্ট্রিং এখানে দেখানো অনুযায়ী HTTPS স্কিমসহ একটি বৈধ, অ্যাবসোলিউট URL হতে হবে।
<?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>
প্যারামিটার
নিম্নলিখিত প্যারামিটারগুলো Intent এক্সট্রা হিসেবে অ্যাক্টিভিটিতে পাঠানো হয়:
-
methodNames -
methodData -
merchantName -
topLevelOrigin -
topLevelCertificateChain -
paymentRequestOrigin -
total -
modifiers -
paymentRequestId -
paymentOptions shippingOptions
কোটলিন
val extras: Bundle? = getIntent()?.extras
জাভা
Bundle extras = getIntent() != null ? getIntent().getExtras() : null;
পদ্ধতির নাম
ব্যবহৃত মেথডগুলোর নাম। এলিমেন্টগুলো হলো methodData ডিকশনারির কী (key)। এগুলো হলো সেই মেথড যা পেমেন্ট অ্যাপটি সাপোর্ট করে।
কোটলিন
val methodNames: List<String>? = extras.getStringArrayList("methodNames")
জাভা
List<String> methodNames = extras.getStringArrayList("methodNames");
methodData
প্রতিটি methodNames থেকে methodData পর্যন্ত একটি ম্যাপিং।
কোটলিন
val methodData: Bundle? = extras.getBundle("methodData")
জাভা
Bundle methodData = extras.getBundle("methodData");
merchantName
মার্চেন্টের চেকআউট পেজের <title> HTML ট্যাগের বিষয়বস্তু (ব্রাউজারের শীর্ষ-স্তরের ব্রাউজিং কনটেক্সট)।
কোটলিন
val merchantName: String? = extras.getString("merchantName")
জাভা
String merchantName = extras.getString("merchantName");
topLevelOrigin
স্কিম ছাড়া মার্চেন্টের অরিজিন (টপ-লেভেল ব্রাউজিং কনটেক্সটের স্কিম-বিহীন অরিজিন)। উদাহরণস্বরূপ, https://mystore.com/checkout mystore.com হিসেবে পাস করা হয়।
কোটলিন
val topLevelOrigin: String? = extras.getString("topLevelOrigin")
জাভা
String topLevelOrigin = extras.getString("topLevelOrigin");
topLevelCertificateChain
মার্চেন্টের সার্টিফিকেট চেইন (শীর্ষ-স্তরের ব্রাউজিং কনটেক্সটের সার্টিফিকেট চেইন)। WebView, লোকালহোস্ট বা ডিস্কের কোনো ফাইলের জন্য এর মান null হয়। প্রতিটি Parcelable হলো একটি Bundle, যার মধ্যে একটি certificate কী এবং একটি বাইট অ্যারে ভ্যালু থাকে।
কোটলিন
val topLevelCertificateChain: Array<Parcelable>? =
extras.getParcelableArray("topLevelCertificateChain")
val list: List<ByteArray>? = topLevelCertificateChain?.mapNotNull { p ->
(p as Bundle).getByteArray("certificate")
}
জাভা
Parcelable[] topLevelCertificateChain =
extras.getParcelableArray("topLevelCertificateChain");
if (topLevelCertificateChain != null) {
for (Parcelable p : topLevelCertificateChain) {
if (p != null && p instanceof Bundle) {
((Bundle) p).getByteArray("certificate");
}
}
}
paymentRequestOrigin
জাভাস্ক্রিপ্টে new PaymentRequest(methodData, details, options) কনস্ট্রাক্টরটিকে কল করা iframe ব্রাউজিং কনটেক্সটের স্কিম-বিহীন অরিজিন। যদি কনস্ট্রাক্টরটি টপ-লেভেল কনটেক্সট থেকে কল করা হয়ে থাকে, তাহলে এই প্যারামিটারের মান topLevelOrigin প্যারামিটারের মানের সমান হয়।
কোটলিন
val paymentRequestOrigin: String? = extras.getString("paymentRequestOrigin")
জাভা
String paymentRequestOrigin = extras.getString("paymentRequestOrigin");
total
লেনদেনের মোট পরিমাণ নির্দেশকারী JSON স্ট্রিং।
কোটলিন
val total: String? = extras.getString("total")
জাভা
String total = extras.getString("total");
এখানে স্ট্রিংটির একটি উদাহরণ দেওয়া হলো:
{"currency":"USD","value":"25.00"}
modifiers
JSON.stringify(details.modifiers) এর আউটপুট, যেখানে details.modifiers শুধুমাত্র supportedMethods , data এবং total থাকে।
paymentRequestId
PaymentRequest.id ফিল্ডটি হলো এমন একটি ফিল্ড যা "পুশ-পেমেন্ট" অ্যাপগুলোকে ট্রানজ্যাকশনের অবস্থার সাথে যুক্ত করতে হয়। মার্চেন্ট ওয়েবসাইটগুলো এই ফিল্ডটি ব্যবহার করে আউট-অফ-ব্যান্ড পদ্ধতিতে "পুশ-পেমেন্ট" অ্যাপগুলোকে ট্রানজ্যাকশনের অবস্থা সম্পর্কে জিজ্ঞাসা করবে।
কোটলিন
val paymentRequestId: String? = extras.getString("paymentRequestId")
জাভা
String paymentRequestId = 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()
জাভা
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();
আপনাকে ইন্টেন্ট এক্সট্রা হিসেবে দুটি প্যারামিটার অবশ্যই নির্দিষ্ট করতে হবে:
-
methodName: যে মেথডটি ব্যবহার করা হচ্ছে তার নাম। -
details: লেনদেনটি সম্পন্ন করার জন্য মার্চেন্টের প্রয়োজনীয় তথ্য সম্বলিত একটি JSON স্ট্রিং। যদি success-এর মানtrueহয়, তাহলেdetailsএমনভাবে তৈরি করতে হবে যাতেJSON.parse(details)সফল হয়। যদি ফেরত দেওয়ার মতো কোনো ডেটা না থাকে, তাহলে এই স্ট্রিংটি"{}"হতে পারে, যা মার্চেন্টের ওয়েবসাইট একটি খালি জাভাস্ক্রিপ্ট ডিকশনারি হিসেবে গ্রহণ করবে।
যদি ব্যবহারকারী পেমেন্ট অ্যাপে লেনদেনটি বাতিল করেন, তাহলে আপনি RESULT_CANCELED পাস করতে পারেন। এর ফলে মার্চেন্ট ওয়েবসাইটে request.show() একটি AbortError সহ প্রত্যাখ্যাত হবে, যা ব্যবহারকারীর বাতিলকরণকে নির্দেশ করে।
কোটলিন
setResult(Activity.RESULT_CANCELED)
finish()
জাভা
setResult(Activity.RESULT_CANCELED);
finish();
ক্রোম ১৪৯ থেকে নিম্নলিখিত ফলাফল মানগুলো সমর্থিত:
কোটলিন
Activity.RESULT_CANCELED // 0 (0x00000000)
Activity.RESULT_OK // -1 (0xffffffff)
const val INTERNAL_PAYMENT_APP_ERROR = Activity.RESULT_FIRST_USER // 1 (0x00000001)
জাভা
Activity.RESULT_CANCELED // 0 (0x00000000)
Activity.RESULT_OK // -1 (0xffffffff)
static final int INTERNAL_PAYMENT_APP_ERROR = Activity.RESULT_FIRST_USER; // 1 (0x00000001)
যদি কোনো অভ্যন্তরীণ ত্রুটির কারণে পেমেন্ট অ্যাপটি ব্যর্থ হয়, তাহলে আপনি ফলাফল কোড হিসেবে Activity.RESULT_FIRST_USER পাস করে তা নির্দেশ করতে পারেন।
যদি INTERNAL_PAYMENT_APP_ERROR রিটার্ন করা হয়, তাহলে মার্চেন্ট ওয়েবসাইটে request.show() একটি OperationError দেখিয়ে প্রত্যাখ্যাত হবে, যা পেমেন্ট অ্যাপে একটি ত্রুটি নির্দেশ করে।
ব্যবহারকারীর বাতিলের জন্য RESULT_CANCELED (0), যা AbortError ঘটায়, এবং অ্যাপের অভ্যন্তরীণ ত্রুটির জন্য INTERNAL_PAYMENT_APP_ERROR (1), যা OperationError ঘটায়, এই দুইয়ের মধ্যে পার্থক্য ব্যবসায়ীদের আরও উন্নত ইউজার ফ্লো তৈরি করতে সাহায্য করে।
কোটলিন
setResult(Activity.RESULT_FIRST_USER)
finish()
জাভা
setResult(Activity.RESULT_FIRST_USER);
finish();
যদি ইনভোক করা পেমেন্ট অ্যাপ থেকে প্রাপ্ত পেমেন্ট রেসপন্সের অ্যাক্টিভিটি রেজাল্ট RESULT_OK সেট করা থাকে, তাহলে Chrome তার extras-এ 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
জাভা
String caller = getCallingPackage();
চূড়ান্ত ধাপ হলো কলারের সাইনিং সার্টিফিকেট যাচাই করে নিশ্চিত করা যে কলিং প্যাকেজটিতে সঠিক স্বাক্ষর রয়েছে।
ধাপ ৪: কলারের সাইনিং সার্টিফিকেট যাচাই করুন
আপনি IS_READY_TO_PAY পর্যায়ে Binder.getCallingUid() ব্যবহার করে এবং PAY পর্যায়ে Activity.getCallingPackage() ব্যবহার করে কলারের প্যাকেজ নেম যাচাই করতে পারেন। কলারটি যে আপনার কাঙ্ক্ষিত ব্রাউজারই, তা নিশ্চিতভাবে যাচাই করার জন্য, আপনার এর সাইনিং সার্টিফিকেটটি পরীক্ষা করে দেখা উচিত এবং নিশ্চিত করা উচিত যে এটি সঠিক মানের সাথে মিলে যাচ্ছে।
যদি আপনি এপিআই লেভেল ২৮ বা তার পরবর্তী সংস্করণকে টার্গেট করেন এবং এমন কোনো ব্রাউজারের সাথে ইন্টিগ্রেট করেন যেটিতে একটিমাত্র সাইনিং সার্টিফিকেট রয়েছে, তাহলে আপনি 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
)
জাভা
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() ব্যবহার করা শ্রেয়, কারণ এটি সার্টিফিকেট রোটেশন সঠিকভাবে পরিচালনা করে। (ক্রোমের একটিমাত্র সাইনিং সার্টিফিকেট রয়েছে।) যেসব অ্যাপের একাধিক সাইনিং সার্টিফিকেট থাকে, তারা সেগুলো রোটেশন করতে পারে না।
যদি আপনাকে এপিআই লেভেল ২৭ এবং তার পূর্ববর্তী সংস্করণগুলো সমর্থন করতে হয়, অথবা একাধিক সাইনিং সার্টিফিকেটযুক্ত ব্রাউজারগুলো পরিচালনা করতে হয়, তাহলে আপনি PackageManager.GET_SIGNATURES ব্যবহার করতে পারেন।
কোটলিন
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)
জাভা
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);
ডিবাগ
ত্রুটি বা তথ্যমূলক বার্তা পর্যবেক্ষণ করতে নিম্নলিখিত কমান্ডটি ব্যবহার করুন:
adb logcat | grep -i pay