1. ভূমিকা
শেষ আপডেট: 2023-07-11
একটি Flutter অ্যাপে অ্যাপ-মধ্যস্থ কেনাকাটা যোগ করার জন্য সঠিকভাবে অ্যাপ এবং প্লে স্টোর সেট আপ করা, ক্রয় যাচাই করা এবং সাবস্ক্রিপশন সুবিধার মতো প্রয়োজনীয় অনুমতি প্রদান করা প্রয়োজন।
এই কোডল্যাবে আপনি একটি অ্যাপে (আপনার জন্য দেওয়া) তিন ধরনের অ্যাপ-মধ্যস্থ কেনাকাটা যোগ করবেন এবং Firebase-এর সাথে একটি ডার্ট ব্যাকএন্ড ব্যবহার করে এই কেনাকাটাগুলি যাচাই করবেন। প্রদত্ত অ্যাপ, ড্যাশ ক্লিকার, একটি গেম রয়েছে যা মুদ্রা হিসাবে ড্যাশ মাসকট ব্যবহার করে। আপনি নিম্নলিখিত ক্রয় বিকল্প যোগ করবেন:
- একবারে 2000 ড্যাশের জন্য একটি পুনরাবৃত্তিযোগ্য ক্রয়ের বিকল্প।
- পুরানো শৈলী ড্যাশকে আধুনিক শৈলীর ড্যাশে পরিণত করার জন্য একটি এককালীন আপগ্রেড ক্রয়৷
- একটি সদস্যতা যা স্বয়ংক্রিয়ভাবে উৎপন্ন ক্লিক দ্বিগুণ করে।
প্রথম ক্রয়ের বিকল্পটি ব্যবহারকারীকে 2000 ড্যাশের সরাসরি সুবিধা দেয়। এগুলি সরাসরি ব্যবহারকারীর কাছে উপলব্ধ এবং অনেকবার কেনা যায়৷ এটিকে একটি ভোগ্য বলা হয় কারণ এটি সরাসরি খাওয়া হয় এবং একাধিকবার খাওয়া যায়।
দ্বিতীয় বিকল্পটি ড্যাশকে আরও সুন্দর ড্যাশে আপগ্রেড করে। এটি শুধুমাত্র একবার কিনতে হবে এবং চিরকালের জন্য উপলব্ধ। এই ধরনের ক্রয়কে অ-ভোগযোগ্য বলা হয় কারণ এটি অ্যাপ দ্বারা ব্যবহার করা যায় না তবে এটি চিরতরে বৈধ।
তৃতীয় এবং শেষ ক্রয় বিকল্পটি একটি সাবস্ক্রিপশন। সাবস্ক্রিপশন সক্রিয় থাকাকালীন ব্যবহারকারী আরও দ্রুত ড্যাশ পাবেন, কিন্তু যখন তিনি সাবস্ক্রিপশনের জন্য অর্থ প্রদান বন্ধ করেন তখন সুবিধাগুলিও চলে যায়।
ব্যাকএন্ড পরিষেবা (আপনার জন্যও সরবরাহ করা হয়েছে) একটি ডার্ট অ্যাপ হিসাবে চলে, কেনাকাটা করা হয়েছে কিনা তা যাচাই করে এবং Firestore ব্যবহার করে সেগুলি সঞ্চয় করে। Firestore প্রক্রিয়াটিকে সহজ করার জন্য ব্যবহার করা হয়, কিন্তু আপনার প্রোডাকশন অ্যাপে, আপনি যেকোনো ধরনের ব্যাকএন্ড পরিষেবা ব্যবহার করতে পারেন।
আপনি কি নির্মাণ করবেন
- আপনি উপভোগযোগ্য ক্রয় এবং সদস্যতা সমর্থন করার জন্য একটি অ্যাপ প্রসারিত করবেন।
- ক্রয়কৃত আইটেমগুলি যাচাই এবং সংরক্ষণ করতে আপনি একটি ডার্ট ব্যাকএন্ড অ্যাপও প্রসারিত করবেন।
আপনি কি শিখবেন
- ক্রয়যোগ্য পণ্যগুলির সাথে অ্যাপ স্টোর এবং প্লে স্টোর কীভাবে কনফিগার করবেন।
- কেনাকাটা যাচাই করতে এবং সেগুলি Firestore-এ সঞ্চয় করতে কীভাবে স্টোরগুলির সাথে যোগাযোগ করবেন।
- কীভাবে আপনার অ্যাপে কেনাকাটা পরিচালনা করবেন।
আপনি কি প্রয়োজন হবে
- অ্যান্ড্রয়েড স্টুডিও 4.1 বা তার পরে
- Xcode 12 বা তার পরে (iOS বিকাশের জন্য)
- ফ্লটার SDK
2. উন্নয়ন পরিবেশ সেট আপ করুন
এই কোডল্যাবটি শুরু করতে, কোডটি ডাউনলোড করুন এবং iOS-এর জন্য বান্ডেল শনাক্তকারী এবং অ্যান্ড্রয়েডের প্যাকেজের নাম পরিবর্তন করুন।
কোডটি ডাউনলোড করুন
কমান্ড লাইন থেকে GitHub সংগ্রহস্থল ক্লোন করতে, নিম্নলিখিত কমান্ডটি ব্যবহার করুন:
git clone https://github.com/flutter/codelabs.git flutter-codelabs
অথবা, যদি আপনার GitHub এর cli টুল ইনস্টল করা থাকে তবে নিম্নলিখিত কমান্ডটি ব্যবহার করুন:
gh repo clone flutter/codelabs flutter-codelabs
নমুনা কোডটি একটি flutter-codelabs
ডিরেক্টরিতে ক্লোন করা হয় যাতে কোডল্যাবগুলির একটি সংগ্রহের জন্য কোড থাকে। এই কোডল্যাবের কোডটি flutter-codelabs/in_app_purchases
এ রয়েছে।
flutter-codelabs/in_app_purchases
অধীনে থাকা ডিরেক্টরি কাঠামোতে প্রতিটি নামের ধাপের শেষে আপনার কোথায় থাকা উচিত তার একটি সিরিজ স্ন্যাপশট রয়েছে। স্টার্টার কোডটি ধাপ 0-এ রয়েছে, তাই মিলে যাওয়া ফাইলগুলি সনাক্ত করা যতটা সহজ:
cd flutter-codelabs/in_app_purchases/step_00
আপনি যদি এড়িয়ে যেতে চান বা একটি ধাপের পরে কিছু দেখতে কেমন হওয়া উচিত তা দেখতে চাইলে, আপনি যে ধাপে আগ্রহী সেই ধাপের নাম অনুসারে নির্দেশিকাটি দেখুন৷ শেষ ধাপের কোডটি complete
ফোল্ডারের নীচে রয়েছে৷
স্টার্টার প্রকল্প সেট আপ করুন
আপনার প্রিয় IDE-তে step_00
থেকে স্টার্টার প্রকল্পটি খুলুন। আমরা স্ক্রিনশটগুলির জন্য অ্যান্ড্রয়েড স্টুডিও ব্যবহার করেছি, তবে ভিজ্যুয়াল স্টুডিও কোডও একটি দুর্দান্ত বিকল্প। যেকোনো একটি এডিটরের সাথে, নিশ্চিত করুন যে লেটেস্ট ডার্ট এবং ফ্লাটার প্লাগইন ইনস্টল করা আছে।
আপনি যে অ্যাপগুলি তৈরি করতে যাচ্ছেন সেগুলিকে অ্যাপ স্টোর এবং প্লে স্টোরের সাথে যোগাযোগ করতে হবে কোন পণ্যগুলি উপলব্ধ এবং কী দামে তা জানার জন্য৷ প্রতিটি অ্যাপ একটি অনন্য আইডি দ্বারা চিহ্নিত করা হয়। iOS অ্যাপ স্টোরের জন্য এটিকে বান্ডেল শনাক্তকারী বলা হয় এবং অ্যান্ড্রয়েড প্লে স্টোরের জন্য এটি অ্যাপ্লিকেশন আইডি। এই শনাক্তকারীগুলি সাধারণত একটি বিপরীত ডোমেন নামের স্বরলিপি ব্যবহার করে তৈরি করা হয়। উদাহরণস্বরূপ flutter.dev-এর জন্য একটি ইন অ্যাপ ক্রয় অ্যাপ তৈরি করার সময় আমরা dev.flutter.inapppurchase
ব্যবহার করব। আপনার অ্যাপের জন্য একটি শনাক্তকারীর কথা চিন্তা করুন, আপনি এখন প্রকল্প সেটিংসে সেটি সেট করতে যাচ্ছেন।
প্রথমে, iOS এর জন্য বান্ডেল শনাক্তকারী সেট আপ করুন।
অ্যান্ড্রয়েড স্টুডিওতে প্রজেক্ট খোলার সাথে, iOS ফোল্ডারে ডান-ক্লিক করুন, Flutter এ ক্লিক করুন এবং Xcode অ্যাপে মডিউলটি খুলুন।
Xcode-এর ফোল্ডার স্ট্রাকচারে, রানার প্রোজেক্টটি শীর্ষে, এবং Flutter , Runner , এবং Products টার্গেট রানার প্রোজেক্টের নীচে। আপনার প্রকল্প সেটিংস সম্পাদনা করতে রানারে ডাবল-ক্লিক করুন, এবং সাইনিং এবং সক্ষমতা ক্লিক করুন। আপনার দল সেট করতে টিম ফিল্ডের অধীনে আপনি যে বান্ডিল শনাক্তকারীটি বেছে নিয়েছেন তা লিখুন।
আপনি এখন এক্সকোড বন্ধ করতে পারেন এবং অ্যান্ড্রয়েডের জন্য কনফিগারেশন শেষ করতে অ্যান্ড্রয়েড স্টুডিওতে ফিরে যেতে পারেন। এটি করতে android/app,
অধীনে build.gradle
ফাইলটি খুলুন এবং আপনার applicationId
(নীচের স্ক্রিনশটে 37 লাইনে) অ্যাপ্লিকেশন আইডিতে পরিবর্তন করুন, iOS বান্ডেল শনাক্তকারীর মতো। মনে রাখবেন যে আইওএস এবং অ্যান্ড্রয়েড স্টোরগুলির জন্য আইডিগুলি অভিন্ন হতে হবে না, তবে তাদের অভিন্ন রাখা কম ত্রুটি প্রবণ এবং তাই এই কোডল্যাবে আমরা অভিন্ন শনাক্তকারীগুলিও ব্যবহার করব৷
3. প্লাগইন ইনস্টল করুন
কোডল্যাবের এই অংশে আপনি in_app_purchase প্লাগইনটি ইনস্টল করবেন।
pubspec এ নির্ভরতা যোগ করুন
আপনার পাবস্পেকের নির্ভরতাগুলিতে in_app_purchase
যোগ করে pubspec-এ in_app_purchase
যোগ করুন:
$ cd app $ flutter pub add in_app_purchase
pubspec.yaml
dependencies:
..
cloud_firestore: ^4.0.3
firebase_auth: ^4.2.2
firebase_core: ^2.5.0
google_sign_in: ^6.0.1
http: ^0.13.4
in_app_purchase: ^3.0.1
intl: ^0.18.0
provider: ^6.0.2
..
প্যাকেজ ডাউনলোড করতে pub get এ ক্লিক করুন বা কমান্ড লাইনে flutter pub get
চালান।
4. অ্যাপ স্টোর সেট আপ করুন
অ্যাপ-মধ্যস্থ কেনাকাটা সেট আপ করতে এবং সেগুলি iOS-এ পরীক্ষা করতে, আপনাকে অ্যাপ স্টোরে একটি নতুন অ্যাপ তৈরি করতে হবে এবং সেখানে ক্রয়যোগ্য পণ্য তৈরি করতে হবে। আপনাকে কিছু প্রকাশ করতে হবে না বা অ্যাপটিকে পর্যালোচনার জন্য অ্যাপলে পাঠাতে হবে না। এটি করার জন্য আপনার একটি বিকাশকারী অ্যাকাউন্ট প্রয়োজন। আপনার যদি এটি না থাকে তবে Apple বিকাশকারী প্রোগ্রামে নথিভুক্ত করুন ৷
প্রদত্ত অ্যাপস চুক্তি
অ্যাপ-মধ্যস্থ কেনাকাটা ব্যবহার করতে, অ্যাপ স্টোর কানেক্টে অর্থপ্রদানকারী অ্যাপগুলির জন্য আপনার একটি সক্রিয় চুক্তিও থাকতে হবে। https://appstoreconnect.apple.com/- এ যান এবং Agreements, Tax, and Banking-এ ক্লিক করুন।
আপনি এখানে বিনামূল্যে এবং অর্থপ্রদানের অ্যাপের জন্য চুক্তি দেখতে পাবেন। বিনামূল্যের অ্যাপগুলির স্থিতি সক্রিয় হওয়া উচিত এবং অর্থপ্রদানের অ্যাপগুলির স্থিতি নতুন। নিশ্চিত করুন যে আপনি শর্তাবলী দেখেছেন, তাদের গ্রহণ করেছেন এবং সমস্ত প্রয়োজনীয় তথ্য প্রবেশ করান।
যখন সবকিছু সঠিকভাবে সেট করা হয়, তখন অর্থপ্রদানের অ্যাপগুলির স্থিতি সক্রিয় হবে। এটি খুবই গুরুত্বপূর্ণ কারণ আপনি একটি সক্রিয় চুক্তি ছাড়া অ্যাপ-মধ্যস্থ কেনাকাটার চেষ্টা করতে পারবেন না।
অ্যাপ আইডি নিবন্ধন করুন
অ্যাপল ডেভেলপার পোর্টালে একটি নতুন শনাক্তকারী তৈরি করুন।
অ্যাপ আইডি বেছে নিন
অ্যাপ নির্বাচন করুন
কিছু বিবরণ প্রদান করুন এবং বান্ডেল আইডি সেট করুন যাতে পূর্বে XCode-এ সেট করা মানের সাথে বান্ডেল আইডির সাথে মিল থাকে।
কীভাবে একটি নতুন অ্যাপ আইডি তৈরি করতে হয় সে সম্পর্কে আরও নির্দেশনার জন্য, বিকাশকারী অ্যাকাউন্ট সহায়তা দেখুন।
একটি নতুন অ্যাপ তৈরি করা হচ্ছে
আপনার অনন্য বান্ডেল শনাক্তকারীর সাথে অ্যাপ স্টোর সংযোগে একটি নতুন অ্যাপ তৈরি করুন।
কীভাবে একটি নতুন অ্যাপ তৈরি করবেন এবং চুক্তিগুলি পরিচালনা করবেন সে সম্পর্কে আরও নির্দেশনার জন্য, অ্যাপ স্টোর সংযোগ সহায়তা দেখুন।
অ্যাপ-মধ্যস্থ কেনাকাটা পরীক্ষা করার জন্য, আপনার একটি স্যান্ডবক্স পরীক্ষার ব্যবহারকারী প্রয়োজন। এই পরীক্ষা ব্যবহারকারীকে iTunes-এর সাথে সংযুক্ত করা উচিত নয়—এটি শুধুমাত্র অ্যাপ-মধ্যস্থ কেনাকাটা পরীক্ষা করার জন্য ব্যবহার করা হয়। আপনি এমন একটি ইমেল ঠিকানা ব্যবহার করতে পারবেন না যা ইতিমধ্যে একটি Apple অ্যাকাউন্টের জন্য ব্যবহৃত হয়েছে৷ ব্যবহারকারী এবং অ্যাক্সেসে , একটি নতুন স্যান্ডবক্স অ্যাকাউন্ট তৈরি করতে বা বিদ্যমান স্যান্ডবক্স অ্যাপল আইডিগুলি পরিচালনা করতে স্যান্ডবক্সের অধীনে পরীক্ষক- এ যান৷
এখন আপনি সেটিংস > অ্যাপ স্টোর > স্যান্ডবক্স-অ্যাকাউন্টে গিয়ে আপনার আইফোনে আপনার স্যান্ডবক্স ব্যবহারকারী সেট আপ করতে পারেন।
আপনার অ্যাপ-মধ্যস্থ কেনাকাটা কনফিগার করা হচ্ছে
এখন আপনি তিনটি ক্রয়যোগ্য আইটেম কনফিগার করবেন:
-
dash_consumable_2k
: একটি ভোগ্য ক্রয় যা অনেকবার ক্রয় করা যায়, যা ব্যবহারকারীকে প্রতি ক্রয় 2000 ড্যাশ (অ্যাপ-এর মুদ্রা) প্রদান করে। -
dash_upgrade_3d
: একটি অ-ব্যবহারযোগ্য "আপগ্রেড" ক্রয় যা শুধুমাত্র একবার কেনা যায় এবং ব্যবহারকারীকে ক্লিক করার জন্য একটি প্রসাধনীভাবে ভিন্ন ড্যাশ দেয়। -
dash_subscription_doubler
: একটি সাবস্ক্রিপশন যা ব্যবহারকারীকে সাবস্ক্রিপশনের সময়কালের জন্য প্রতি ক্লিকে দ্বিগুণ ড্যাশ দেয়।
অ্যাপ-মধ্যস্থ কেনাকাটা > পরিচালনায় যান।
নির্দিষ্ট আইডি দিয়ে আপনার অ্যাপ-মধ্যস্থ কেনাকাটা তৈরি করুন:
-
dash_consumable_2k
একটি Consumable হিসাবে সেট আপ করুন।
পণ্য আইডি হিসাবে dash_consumable_2k
ব্যবহার করুন। রেফারেন্স নামটি শুধুমাত্র অ্যাপ স্টোর সংযোগে ব্যবহার করা হয়, শুধু এটিকে dash consumable 2k
এ সেট করুন এবং ক্রয়ের জন্য আপনার স্থানীয়করণ যোগ করুন। ক্রয়কে কল করুন Spring is in the air
2000 dashes fly out
বর্ণনা হিসাবে।
-
dash_upgrade_3d
একটি অ-ভোগযোগ্য হিসাবে সেট আপ করুন।
পণ্য আইডি হিসাবে dash_upgrade_3d
ব্যবহার করুন। dash upgrade 3d
এ রেফারেন্স নাম সেট করুন এবং ক্রয়ের জন্য আপনার স্থানীয়করণ যোগ করুন। ক্রয় 3D Dash
সাথে কল করুন বর্ণনা হিসাবে Brings your dash back to the future
।
- একটি স্বতঃ পুনর্নবীকরণ সাবস্ক্রিপশন হিসাবে
dash_subscription_doubler
সেট আপ করুন।
সাবস্ক্রিপশনের প্রবাহ একটু ভিন্ন। প্রথমে আপনাকে রেফারেন্স নাম এবং পণ্য আইডি সেট করতে হবে:
এর পরে, আপনাকে একটি সাবস্ক্রিপশন গ্রুপ তৈরি করতে হবে। যখন একাধিক সাবস্ক্রিপশন একই গোষ্ঠীর অংশ হয়, তখন একজন ব্যবহারকারী একই সময়ে শুধুমাত্র একটিতে সাবস্ক্রাইব করতে পারে, কিন্তু সহজেই এই সদস্যতার মধ্যে আপগ্রেড বা ডাউনগ্রেড করতে পারে। শুধু এই গ্রুপ subscriptions
কল.
এরপরে, সাবস্ক্রিপশনের সময়কাল এবং স্থানীয়করণ লিখুন। বর্ণনা সহ এই সাবস্ক্রিপশনের নাম Jet Engine
দিন Doubles your clicks
। Save এ ক্লিক করুন।
আপনি সংরক্ষণ বোতামে ক্লিক করার পরে, একটি সাবস্ক্রিপশন মূল্য যোগ করুন। আপনি চান যে কোনো মূল্য চয়ন করুন.
আপনি এখন ক্রয়ের তালিকায় তিনটি ক্রয় দেখতে পাবেন:
5. প্লে স্টোর সেট আপ করুন৷
অ্যাপ স্টোরের মতো, আপনার প্লে স্টোরের জন্য একটি বিকাশকারী অ্যাকাউন্টও প্রয়োজন। আপনার যদি এখনও একটি না থাকে তবে একটি অ্যাকাউন্ট নিবন্ধন করুন ৷
একটি নতুন অ্যাপ তৈরি করুন
গুগল প্লে কনসোলে একটি নতুন অ্যাপ তৈরি করুন:
- প্লে কনসোল খুলুন।
- সমস্ত অ্যাপ নির্বাচন করুন > অ্যাপ তৈরি করুন।
- একটি ডিফল্ট ভাষা নির্বাচন করুন এবং আপনার অ্যাপের জন্য একটি শিরোনাম যোগ করুন। আপনার অ্যাপের নামটি টাইপ করুন যেভাবে আপনি এটিকে Google Play-তে দেখাতে চান। আপনি পরে নাম পরিবর্তন করতে পারেন.
- আপনার অ্যাপ্লিকেশন একটি খেলা উল্লেখ করুন. আপনি পরে এটি পরিবর্তন করতে পারেন।
- আপনার আবেদন বিনামূল্যে বা অর্থপ্রদান কিনা তা উল্লেখ করুন।
- একটি ইমেল ঠিকানা যোগ করুন যা প্লে স্টোর ব্যবহারকারীরা এই অ্যাপ্লিকেশন সম্পর্কে আপনার সাথে যোগাযোগ করতে ব্যবহার করতে পারে৷
- বিষয়বস্তু নির্দেশিকা এবং মার্কিন রপ্তানি আইন ঘোষণা সম্পূর্ণ করুন।
- অ্যাপ তৈরি করুন নির্বাচন করুন।
আপনার অ্যাপ তৈরি হওয়ার পরে, ড্যাশবোর্ডে যান এবং আপনার অ্যাপ সেট আপ বিভাগে সমস্ত কাজ সম্পূর্ণ করুন। এখানে, আপনি আপনার অ্যাপ সম্পর্কে কিছু তথ্য প্রদান করেন, যেমন কন্টেন্ট রেটিং এবং স্ক্রিনশট।
আবেদনে স্বাক্ষর করুন
অ্যাপ-মধ্যস্থ কেনাকাটা পরীক্ষা করতে সক্ষম হওয়ার জন্য, আপনাকে Google Play-এ অন্তত একটি বিল্ড আপলোড করতে হবে।
এর জন্য, আপনার রিলিজ বিল্ডটি ডিবাগ কী ব্যতীত অন্য কিছুর সাথে স্বাক্ষর করতে হবে।
একটি কীস্টোর তৈরি করুন
আপনার যদি একটি বিদ্যমান কীস্টোর থাকে তবে পরবর্তী ধাপে যান। যদি তা না হয়, কমান্ড লাইনে নিম্নলিখিতটি চালিয়ে একটি তৈরি করুন।
ম্যাক/লিনাক্সে, নিম্নলিখিত কমান্ডটি ব্যবহার করুন:
keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key
উইন্ডোজে, নিম্নলিখিত কমান্ডটি ব্যবহার করুন:
keytool -genkey -v -keystore c:\Users\USER_NAME\key.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias key
এই কমান্ডটি আপনার হোম ডিরেক্টরিতে key.jks
ফাইল সংরক্ষণ করে। আপনি যদি ফাইলটি অন্য কোথাও সংরক্ষণ করতে চান, তাহলে আপনি -keystore
প্যারামিটারে পাস করা যুক্তিটি পরিবর্তন করুন। রাখুন
keystore
ফাইল ব্যক্তিগত; পাবলিক সোর্স কন্ট্রোলে এটি পরীক্ষা করবেন না!
অ্যাপ থেকে কীস্টোর রেফারেন্স করুন
<your app dir>/android/key.properties
নামে একটি ফাইল তৈরি করুন যাতে আপনার কীস্টোরের একটি রেফারেন্স রয়েছে:
storePassword=<password from previous step>
keyPassword=<password from previous step>
keyAlias=key
storeFile=<location of the key store file, such as /Users/<user name>/key.jks>
Gradle-এ সাইনিং কনফিগার করুন
<your app dir>/android/app/build.gradle
ফাইলটি সম্পাদনা করে আপনার অ্যাপের জন্য সাইন ইন কনফিগার করুন।
android
ব্লকের আগে আপনার বৈশিষ্ট্য ফাইল থেকে কীস্টোর তথ্য যোগ করুন:
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
// omitted
}
keystoreProperties
অবজেক্টে key.properties
ফাইলটি লোড করুন।
buildTypes
ব্লকের আগে নিম্নলিখিত কোড যোগ করুন:
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now,
// so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
সাইনিং কনফিগারেশন তথ্য সহ আপনার মডিউলের build.gradle
ফাইলে signingConfigs
ব্লক কনফিগার করুন:
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
আপনার অ্যাপের রিলিজ বিল্ডগুলি এখন স্বয়ংক্রিয়ভাবে স্বাক্ষরিত হবে।
আপনার অ্যাপে স্বাক্ষর করার বিষয়ে আরও তথ্যের জন্য, developer.android.com- এ আপনার অ্যাপ সাইন করুন দেখুন।
আপনার প্রথম বিল্ড আপলোড করুন
আপনার অ্যাপ্লিকেশান সাইনিং করার জন্য কনফিগার করার পরে, আপনি চালানোর মাধ্যমে আপনার অ্যাপ্লিকেশন তৈরি করতে সক্ষম হবেন:
flutter build appbundle
এই কমান্ডটি ডিফল্টরূপে একটি রিলিজ বিল্ড তৈরি করে এবং আউটপুট <your app dir>/build/app/outputs/bundle/release/
এ পাওয়া যাবে।
Google Play Console-এর ড্যাশবোর্ড থেকে, Release > Testing > Closed testing- এ যান এবং একটি নতুন, ক্লোজড টেস্টিং রিলিজ তৈরি করুন।
এই কোডল্যাবের জন্য, আপনি অ্যাপটিতে সাইন করার জন্য Google-এ লেগে থাকবেন, তাই অপ্ট-ইন করতে প্লে অ্যাপ সাইনিং-এর অধীনে চালিয়ে যান টিপুন।
এরপর, app-release.aab
অ্যাপ বান্ডেল আপলোড করুন যা বিল্ড কমান্ড দ্বারা তৈরি করা হয়েছিল।
সংরক্ষণ ক্লিক করুন এবং তারপর রিভিউ রিলিজ ক্লিক করুন.
অবশেষে, অভ্যন্তরীণ পরীক্ষার রিলিজ সক্রিয় করতে অভ্যন্তরীণ পরীক্ষায় রোলআউট শুরু করুন ক্লিক করুন।
পরীক্ষা ব্যবহারকারীদের সেট আপ করুন
অ্যাপ-মধ্যস্থ কেনাকাটা পরীক্ষা করতে সক্ষম হওয়ার জন্য, আপনার পরীক্ষকদের Google অ্যাকাউন্ট দুটি স্থানে Google Play কনসোলে যোগ করতে হবে:
- নির্দিষ্ট টেস্ট ট্র্যাকের কাছে (অভ্যন্তরীণ পরীক্ষা)
- লাইসেন্স পরীক্ষক হিসেবে
প্রথমে, অভ্যন্তরীণ টেস্টিং ট্র্যাকে পরীক্ষক যোগ করে শুরু করুন। রিলিজ > টেস্টিং > ইন্টারনাল টেস্টিং- এ ফিরে যান এবং পরীক্ষক ট্যাবে ক্লিক করুন।
ইমেল তালিকা তৈরি করুন ক্লিক করে একটি নতুন ইমেল তালিকা তৈরি করুন। তালিকার একটি নাম দিন, এবং অ্যাপ-মধ্যস্থ কেনাকাটার পরীক্ষা করার জন্য অ্যাক্সেস প্রয়োজন এমন Google অ্যাকাউন্টগুলির ইমেল ঠিকানাগুলি যোগ করুন৷
এরপরে, তালিকার জন্য চেকবক্স নির্বাচন করুন এবং পরিবর্তনগুলি সংরক্ষণ করুন ক্লিক করুন।
তারপর, লাইসেন্স পরীক্ষক যোগ করুন:
- Google Play Console-এর সমস্ত অ্যাপ ভিউতে ফিরে যান।
- সেটিংস > লাইসেন্স পরীক্ষায় যান।
- অ্যাপ-মধ্যস্থ কেনাকাটা পরীক্ষা করতে সক্ষম হওয়া পরীক্ষকদের একই ইমেল ঠিকানা যোগ করুন।
-
RESPOND_NORMALLY
এ লাইসেন্স প্রতিক্রিয়া সেট করুন। - পরিবর্তনগুলি সংরক্ষণ করুন ক্লিক করুন।
আপনার অ্যাপ-মধ্যস্থ কেনাকাটা কনফিগার করা হচ্ছে
এখন আপনি অ্যাপের মধ্যে ক্রয়যোগ্য আইটেমগুলি কনফিগার করবেন।
অ্যাপ স্টোরের মতো, আপনাকে তিনটি ভিন্ন ক্রয় সংজ্ঞায়িত করতে হবে:
-
dash_consumable_2k
: একটি ভোগ্য ক্রয় যা অনেকবার ক্রয় করা যায়, যা ব্যবহারকারীকে প্রতি ক্রয় 2000 ড্যাশ (অ্যাপ-এর মুদ্রা) প্রদান করে। -
dash_upgrade_3d
: একটি অ-ব্যবহারযোগ্য "আপগ্রেড" ক্রয় যা শুধুমাত্র একবার কেনা যায়, যা ব্যবহারকারীকে ক্লিক করার জন্য একটি প্রসাধনীভাবে ভিন্ন ড্যাশ দেয়। -
dash_subscription_doubler
: একটি সাবস্ক্রিপশন যা ব্যবহারকারীকে সাবস্ক্রিপশনের সময়কালের জন্য প্রতি ক্লিকে দ্বিগুণ ড্যাশ দেয়।
প্রথমে, ব্যবহারযোগ্য এবং অ-ব্যবহারযোগ্য যোগ করুন।
- গুগল প্লে কনসোলে যান এবং আপনার অ্যাপ্লিকেশন নির্বাচন করুন।
- মনিটাইজ > পণ্য > অ্যাপ-মধ্যস্থ পণ্যগুলিতে যান।
- পণ্য তৈরি করুন ক্লিক করুন
- আপনার পণ্যের জন্য প্রয়োজনীয় সমস্ত তথ্য লিখুন। আপনি যে আইডিটি ব্যবহার করতে চান তার সাথে পণ্যের আইডি মেলে তা নিশ্চিত করুন।
- Save এ ক্লিক করুন।
- সক্রিয় ক্লিক করুন.
- অ-ভোগযোগ্য "আপগ্রেড" ক্রয়ের জন্য প্রক্রিয়াটি পুনরাবৃত্তি করুন।
পরবর্তী, সদস্যতা যোগ করুন:
- গুগল প্লে কনসোলে যান এবং আপনার অ্যাপ্লিকেশন নির্বাচন করুন।
- মনিটাইজ > পণ্য > সাবস্ক্রিপশন- এ যান।
- সাবস্ক্রিপশন তৈরি করুন ক্লিক করুন
- আপনার সদস্যতার জন্য প্রয়োজনীয় সমস্ত তথ্য লিখুন। নিশ্চিত করুন যে পণ্যের আইডিটি আপনি যে আইডিটি ব্যবহার করতে চান তার সাথে মেলে।
- Save এ ক্লিক করুন
আপনার কেনাকাটা এখন প্লে কনসোলে সেট আপ করা উচিত।
6. Firebase সেট আপ করুন৷
এই কোডল্যাবে, আপনি ব্যবহারকারীদের ক্রয় যাচাই এবং ট্র্যাক করতে একটি ব্যাকএন্ড পরিষেবা ব্যবহার করবেন৷
একটি ব্যাকএন্ড পরিষেবা ব্যবহার করার বিভিন্ন সুবিধা রয়েছে:
- আপনি নিরাপদে লেনদেন যাচাই করতে পারেন.
- আপনি অ্যাপ স্টোর থেকে বিলিং ইভেন্টগুলিতে প্রতিক্রিয়া জানাতে পারেন।
- আপনি একটি ডাটাবেসে ক্রয়ের ট্র্যাক রাখতে পারেন।
- ব্যবহারকারীরা তাদের সিস্টেম ঘড়ি রিওয়াইন্ড করে প্রিমিয়াম বৈশিষ্ট্য প্রদান করে আপনার অ্যাপকে বোকা বানাতে পারবে না।
যদিও একটি ব্যাকএন্ড পরিষেবা সেট আপ করার অনেক উপায় আছে, আপনি Google এর নিজস্ব ফায়ারবেস ব্যবহার করে ক্লাউড ফাংশন এবং ফায়ারস্টোর ব্যবহার করে এটি করবেন।
ব্যাকএন্ড লেখাকে এই কোডল্যাবের সুযোগের বাইরে বিবেচনা করা হয়, তাই স্টার্টার কোডে ইতিমধ্যেই একটি ফায়ারবেস প্রকল্প অন্তর্ভুক্ত রয়েছে যা আপনাকে শুরু করতে প্রাথমিক কেনাকাটা পরিচালনা করে।
ফায়ারবেস প্লাগইনগুলিও স্টার্টার অ্যাপের সাথে অন্তর্ভুক্ত করা হয়েছে।
আপনার নিজের ফায়ারবেস প্রজেক্ট তৈরি করা, ফায়ারবেসের জন্য অ্যাপ এবং ব্যাকএন্ড উভয় কনফিগার করা এবং অবশেষে ব্যাকএন্ড স্থাপন করা।
একটি ফায়ারবেস প্রকল্প তৈরি করুন
Firebase কনসোলে যান, এবং একটি নতুন Firebase প্রকল্প তৈরি করুন৷ এই উদাহরণের জন্য, প্রকল্পটিকে কল করুন ড্যাশ ক্লিকার।
ব্যাকএন্ড অ্যাপে, আপনি একটি নির্দিষ্ট ব্যবহারকারীর সাথে কেনাকাটা টাই করেন, তাই আপনার প্রমাণীকরণ প্রয়োজন। এর জন্য, Google সাইন-ইন দিয়ে Firebase-এর প্রমাণীকরণ মডিউল ব্যবহার করুন।
- ফায়ারবেস ড্যাশবোর্ড থেকে, প্রমাণীকরণে যান এবং প্রয়োজনে এটি সক্ষম করুন।
- সাইন-ইন পদ্ধতি ট্যাবে যান এবং Google সাইন-ইন প্রদানকারী সক্ষম করুন।
যেহেতু আপনি ফায়ারবেসের ফায়ারস্টোর ডাটাবেসও ব্যবহার করবেন, এটিও সক্ষম করুন।
এই মত ক্লাউড ফায়ারস্টোর নিয়ম সেট করুন:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /purchases/{purchaseId} {
allow read: if request.auth != null && request.auth.uid == resource.data.userId
}
}
}
ফ্লটারের জন্য Firebase সেট আপ করুন
Flutter অ্যাপে Firebase ইনস্টল করার প্রস্তাবিত উপায় হল FlutterFire CLI ব্যবহার করা। সেটআপ পৃষ্ঠায় বর্ণিত নির্দেশাবলী অনুসরণ করুন।
flutterfire কনফিগার চালানোর সময়, আপনি আগের ধাপে তৈরি করা প্রকল্পটি নির্বাচন করুন।
$ flutterfire configure
i Found 5 Firebase projects.
? Select a Firebase project to configure your Flutter application with ›
❯ in-app-purchases-1234 (in-app-purchases-1234)
other-flutter-codelab-1 (other-flutter-codelab-1)
other-flutter-codelab-2 (other-flutter-codelab-2)
other-flutter-codelab-3 (other-flutter-codelab-3)
other-flutter-codelab-4 (other-flutter-codelab-4)
<create a new project>
এরপরে, দুটি প্ল্যাটফর্ম নির্বাচন করে iOS এবং Android সক্ষম করুন।
? Which platforms should your configuration support (use arrow keys & space to select)? ›
✔ android
✔ ios
macos
web
Firebase_options.dart ওভাররাইড করার বিষয়ে অনুরোধ করা হলে, হ্যাঁ নির্বাচন করুন।
? Generated FirebaseOptions file lib/firebase_options.dart already exists, do you want to override it? (y/n) › yes
Android এর জন্য Firebase সেট আপ করুন: আরও ধাপ
ফায়ারবেস ড্যাশবোর্ড থেকে, প্রজেক্ট ওভারভিউতে যান, সেটিংস নির্বাচন করুন এবং সাধারণ ট্যাব নির্বাচন করুন।
আপনার অ্যাপে নিচে স্ক্রোল করুন এবং ড্যাশক্লিকার (অ্যান্ড্রয়েড) অ্যাপটি নির্বাচন করুন।
ডিবাগ মোডে Google সাইন-ইন করার অনুমতি দিতে, আপনাকে অবশ্যই আপনার ডিবাগ শংসাপত্রের SHA-1 হ্যাশ ফিঙ্গারপ্রিন্ট প্রদান করতে হবে।
আপনার ডিবাগ স্বাক্ষর শংসাপত্র হ্যাশ পান
আপনার Flutter অ্যাপ প্রকল্পের মূলে, android/
ফোল্ডারে ডিরেক্টরি পরিবর্তন করুন তারপর একটি স্বাক্ষর প্রতিবেদন তৈরি করুন।
cd android ./gradlew :app:signingReport
আপনাকে সাইনিং কীগুলির একটি বড় তালিকা উপস্থাপন করা হবে। যেহেতু আপনি ডিবাগ শংসাপত্রের জন্য হ্যাশ খুঁজছেন, debug
সেট করা Variant
এবং Config
বৈশিষ্ট্য সহ শংসাপত্রটি সন্ধান করুন। .android/debug.keystore
অধীনে আপনার হোম ফোল্ডারে কীস্টোরটি থাকার সম্ভাবনা রয়েছে।
> Task :app:signingReport
Variant: debug
Config: debug
Store: /<USER_HOME_FOLDER>/.android/debug.keystore
Alias: AndroidDebugKey
MD5: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
SHA1: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
SHA-256: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
Valid until: Tuesday, January 19, 2038
SHA-1 হ্যাশ অনুলিপি করুন এবং অ্যাপ জমা দেওয়ার মডেল ডায়ালগে শেষ ক্ষেত্রটি পূরণ করুন।
iOS এর জন্য Firebase সেট আপ করুন: আরও ধাপ
Xcode
দিয়ে ios/Runnder.xcworkspace
খুলুন। অথবা আপনার পছন্দের IDE দিয়ে।
VSCode-এ ios/
ফোল্ডারে ডান ক্লিক করুন এবং তারপর open in xcode
।
অ্যান্ড্রয়েড স্টুডিওতে ios/
ফোল্ডারে রাইট ক্লিক করুন তারপর open iOS module in Xcode
দ্বারা flutter
ক্লিক করুন।
iOS-এ Google সাইন-ইন করার অনুমতি দিতে, আপনার বিল্ড plist
ফাইলগুলিতে CFBundleURLTypes
কনফিগারেশন বিকল্প যোগ করুন। (আরো তথ্যের জন্য google_sign_in
প্যাকেজ ডক্স দেখুন।) এই ক্ষেত্রে, ফাইলগুলি হল ios/Runner/Info-Debug.plist
এবং ios/Runner/Info-Release.plist
।
মূল-মান জোড়া ইতিমধ্যেই যোগ করা হয়েছে, কিন্তু তাদের মান অবশ্যই প্রতিস্থাপন করতে হবে:
-
GoogleService-Info.plist
ফাইল থেকেREVERSED_CLIENT_ID
এর মান পান, এটিকে ঘিরে থাকা<string>..</string>
উপাদান ছাড়াই। -
CFBundleURLTypes
কী-এর অধীনে আপনারios/Runner/Info-Debug.plist
এবংios/Runner/Info-Release.plist
ফাইল উভয়ের মান প্রতিস্থাপন করুন।
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<!-- TODO Replace this value: -->
<!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID -->
<string>com.googleusercontent.apps.REDACTED</string>
</array>
</dict>
</array>
আপনি এখন Firebase সেটআপ সম্পন্ন করেছেন।
7. ক্রয় আপডেট শুনুন
কোডল্যাবের এই অংশে আপনি পণ্য কেনার জন্য অ্যাপটি প্রস্তুত করবেন। অ্যাপটি শুরু হওয়ার পর ক্রয় সংক্রান্ত আপডেট এবং ত্রুটি শোনা এই প্রক্রিয়ার অন্তর্ভুক্ত।
ক্রয় আপডেট শুনুন
main.dart,
MyHomePage
উইজেটটি খুঁজুন যেখানে একটি Scaffold
রয়েছে যার একটি BottomNavigationBar
রয়েছে যেখানে দুটি পৃষ্ঠা রয়েছে। এই পৃষ্ঠাটি DashCounter
, DashUpgrades,
এবং DashPurchases
এর জন্য তিনটি Provider
তৈরি করে। DashCounter
ড্যাশের বর্তমান গণনা ট্র্যাক করে এবং তাদের স্বয়ংক্রিয়ভাবে বৃদ্ধি করে। DashUpgrades
আপগ্রেডগুলি পরিচালনা করে যা আপনি Dashes দিয়ে কিনতে পারেন। এই কোডল্যাবটি DashPurchases
উপর ফোকাস করে।
ডিফল্টরূপে, একটি প্রদানকারীর বস্তুটি সংজ্ঞায়িত করা হয় যখন সেই বস্তুটি প্রথম অনুরোধ করা হয়। অ্যাপটি শুরু হলে এই বস্তুটি ক্রয় আপডেটগুলি সরাসরি শোনে, তাই এই অবজেক্টে অলস লোডিং অক্ষম করুন lazy: false
:
lib/main.dart
ChangeNotifierProvider<DashPurchases>(
create: (context) => DashPurchases(
context.read<DashCounter>(),
),
lazy: false,
),
এছাড়াও আপনার InAppPurchaseConnection
এর একটি উদাহরণ প্রয়োজন। যাইহোক, অ্যাপটিকে পরীক্ষাযোগ্য রাখতে আপনার সংযোগটিকে উপহাস করার কিছু উপায় প্রয়োজন। এটি করার জন্য, একটি উদাহরণ পদ্ধতি তৈরি করুন যা পরীক্ষায় ওভাররাইড করা যেতে পারে এবং এটি main.dart
এ যোগ করুন।
lib/main.dart
// Gives the option to override in tests.
class IAPConnection {
static InAppPurchase? _instance;
static set instance(InAppPurchase value) {
_instance = value;
}
static InAppPurchase get instance {
_instance ??= InAppPurchase.instance;
return _instance!;
}
}
আপনি যদি পরীক্ষাটি কাজ চালিয়ে যেতে চান তবে আপনাকে অবশ্যই পরীক্ষাটি কিছুটা আপডেট করতে হবে। TestIAPConnection
এর সম্পূর্ণ কোডের জন্য GitHub-এ widget_test.dart দেখুন।
test/widget_test.dart
void main() {
testWidgets('App starts', (WidgetTester tester) async {
IAPConnection.instance = TestIAPConnection();
await tester.pumpWidget(const MyApp());
expect(find.text('Tim Sneath'), findsOneWidget);
});
}
lib/logic/dash_purchases.dart
এ, DashPurchases ChangeNotifier
এর কোডে যান। বর্তমানে, শুধুমাত্র একটি DashCounter
আছে যা আপনি আপনার কেনা ড্যাশে যোগ করতে পারেন।
একটি স্ট্রিম সাবস্ক্রিপশন প্রপার্টি যোগ করুন, _subscription
(প্রকার StreamSubscription<List<PurchaseDetails>> _subscription;
), IAPConnection.instance,
এবং ইম্পোর্ট। ফলাফল কোড নিম্নলিখিত দেখা উচিত:
lib/logic/dash_purchases.dart
import 'package:in_app_purchase/in_app_purchase.dart';
class DashPurchases extends ChangeNotifier {
late StreamSubscription<List<PurchaseDetails>> _subscription;
final iapConnection = IAPConnection.instance;
DashPurchases(this.counter);
}
_subscription
এ late
কীওয়ার্ড যোগ করা হয়েছে কারণ _subscription
কনস্ট্রাক্টরে আরম্ভ করা হয়েছে। এই প্রজেক্টটি ডিফল্টরূপে নন-নালবল হতে সেট আপ করা হয়েছে (NNBD), যার অর্থ হল যে বৈশিষ্ট্যগুলি বাতিলযোগ্য বলে ঘোষণা করা হয় না তাদের অবশ্যই একটি নন-নাল মান থাকতে হবে। late
কোয়ালিফায়ার আপনাকে এই মান নির্ধারণে বিলম্ব করতে দেয়।
কনস্ট্রাক্টরে, purchaseUpdatedStream
পান এবং স্ট্রীম শুনতে শুরু করুন। dispose()
পদ্ধতিতে, স্ট্রিম সাবস্ক্রিপশন বাতিল করুন।
lib/logic/dash_purchases.dart
class DashPurchases extends ChangeNotifier {
DashCounter counter;
late StreamSubscription<List<PurchaseDetails>> _subscription;
final iapConnection = IAPConnection.instance;
DashPurchases(this.counter) {
final purchaseUpdated =
iapConnection.purchaseStream;
_subscription = purchaseUpdated.listen(
_onPurchaseUpdate,
onDone: _updateStreamOnDone,
onError: _updateStreamOnError,
);
}
@override
void dispose() {
_subscription.cancel();
super.dispose();
}
Future<void> buy(PurchasableProduct product) async {
// omitted
}
void _onPurchaseUpdate(List<PurchaseDetails> purchaseDetailsList) {
// Handle purchases here
}
void _updateStreamOnDone() {
_subscription.cancel();
}
void _updateStreamOnError(dynamic error) {
//Handle error here
}
}
এখন, অ্যাপটি ক্রয়ের আপডেটগুলি গ্রহণ করে তাই, পরবর্তী বিভাগে, আপনি একটি ক্রয় করবেন!
আপনি এগিয়ে যাওয়ার আগে, সবকিছু সঠিকভাবে সেট আপ করা হয়েছে তা যাচাই করতে " flutter test"
দিয়ে পরীক্ষা চালান।
$ flutter test
00:01 +1: All tests passed!
8. কেনাকাটা করুন
কোডল্যাবের এই অংশে, আপনি বর্তমানে বিদ্যমান মক পণ্যগুলিকে প্রকৃত ক্রয়যোগ্য পণ্যগুলির সাথে প্রতিস্থাপন করবেন। এই পণ্যগুলি স্টোর থেকে লোড করা হয়, একটি তালিকায় দেখানো হয় এবং পণ্যটি ট্যাপ করার সময় কেনা হয়।
ক্রয়যোগ্য পণ্য মানিয়ে নিন
PurchasableProduct
একটি উপহাস পণ্য প্রদর্শন করে। নিম্নলিখিত কোড দিয়ে purchasable_product.dart
এ PurchasableProduct
ক্লাস প্রতিস্থাপন করে প্রকৃত সামগ্রী দেখানোর জন্য এটি আপডেট করুন:
lib/model/purchasable_product.dart
import 'package:in_app_purchase/in_app_purchase.dart';
enum ProductStatus {
purchasable,
purchased,
pending,
}
class PurchasableProduct {
String get id => productDetails.id;
String get title => productDetails.title;
String get description => productDetails.description;
String get price => productDetails.price;
ProductStatus status;
ProductDetails productDetails;
PurchasableProduct(this.productDetails) : status = ProductStatus.purchasable;
}
dash_purchases.dart,
ডামি কেনাকাটাগুলি সরিয়ে ফেলুন এবং একটি খালি তালিকা দিয়ে প্রতিস্থাপন করুন, List<PurchasableProduct> products = [];
উপলব্ধ ক্রয় লোড
একজন ব্যবহারকারীকে কেনাকাটা করার ক্ষমতা দিতে, দোকান থেকে কেনাকাটা লোড করুন। প্রথমে, দোকান পাওয়া যায় কিনা তা পরীক্ষা করুন। স্টোরটি উপলব্ধ না হলে, storeState
notAvailable
এ সেট করা ব্যবহারকারীর কাছে একটি ত্রুটি বার্তা প্রদর্শন করে।
lib/logic/dash_purchases.dart
Future<void> loadPurchases() async {
final available = await iapConnection.isAvailable();
if (!available) {
storeState = StoreState.notAvailable;
notifyListeners();
return;
}
}
দোকান উপলব্ধ হলে, উপলব্ধ কেনাকাটা লোড করুন. পূর্ববর্তী ফায়ারবেস সেটআপ দেওয়া, storeKeyConsumable
, storeKeySubscription,
এবং storeKeyUpgrade
দেখার প্রত্যাশা করুন। একটি প্রত্যাশিত ক্রয় উপলব্ধ না হলে, কনসোলে এই তথ্য মুদ্রণ করুন; আপনি ব্যাকএন্ড পরিষেবাতে এই তথ্য পাঠাতে চাইতে পারেন।
await iapConnection.queryProductDetails(ids)
পদ্ধতিটি খুঁজে পাওয়া যায়নি এমন আইডি এবং পাওয়া যায় এমন ক্রয়যোগ্য পণ্য উভয়ই ফেরত দেয়। UI আপডেট করতে প্রতিক্রিয়া থেকে productDetails
ব্যবহার করুন এবং StoreState
available
হিসাবে সেট করুন।
lib/logic/dash_purchases.dart
import '../constants.dart';
Future<void> loadPurchases() async {
final available = await iapConnection.isAvailable();
if (!available) {
storeState = StoreState.notAvailable;
notifyListeners();
return;
}
const ids = <String>{
storeKeyConsumable,
storeKeySubscription,
storeKeyUpgrade,
};
final response = await iapConnection.queryProductDetails(ids);
for (var element in response.notFoundIDs) {
debugPrint('Purchase $element not found');
}
products = response.productDetails.map((e) => PurchasableProduct(e)).toList();
storeState = StoreState.available;
notifyListeners();
}
কনস্ট্রাক্টরে loadPurchases()
ফাংশনটি কল করুন:
lib/logic/dash_purchases.dart
DashPurchases(this.counter) {
final purchaseUpdated = iapConnection.purchaseStream;
_subscription = purchaseUpdated.listen(
_onPurchaseUpdate,
onDone: _updateStreamOnDone,
onError: _updateStreamOnError,
);
loadPurchases();
}
অবশেষে, storeState
ক্ষেত্রের মান StoreState.available
থেকে StoreState.loading:
lib/logic/dash_purchases.dart
StoreState storeState = StoreState.loading;
ক্রয়যোগ্য পণ্য দেখান
purchase_page.dart
ফাইলটি বিবেচনা করুন। PurchasePage
উইজেট StoreState
উপর নির্ভর করে _PurchasesLoading
, _PurchaseList,
অথবা _PurchasesNotAvailable,
দেখায়। উইজেট ব্যবহারকারীর অতীত কেনাকাটাও দেখায় যা পরবর্তী ধাপে ব্যবহার করা হয়।
_PurchaseList
উইজেট ক্রয়যোগ্য পণ্যের তালিকা দেখায় এবং DashPurchases
অবজেক্টে কেনার অনুরোধ পাঠায়।
lib/pages/purchase_page.dart
class _PurchaseList extends StatelessWidget {
@override
Widget build(BuildContext context) {
var purchases = context.watch<DashPurchases>();
var products = purchases.products;
return Column(
children: products
.map((product) => _PurchaseWidget(
product: product,
onPressed: () {
purchases.buy(product);
}))
.toList(),
);
}
}
আপনি Android এবং iOS স্টোরগুলিতে উপলব্ধ পণ্যগুলি দেখতে সক্ষম হবেন যদি সেগুলি সঠিকভাবে কনফিগার করা থাকে। নোট করুন যে সংশ্লিষ্ট কনসোলগুলিতে প্রবেশ করার সময় কেনাকাটাগুলি উপলব্ধ হওয়ার আগে কিছু সময় লাগতে পারে।
dash_purchases.dart
এ ফিরে যান এবং একটি পণ্য কিনতে ফাংশনটি বাস্তবায়ন করুন। আপনাকে শুধুমাত্র অ-ভোগ্য দ্রব্য থেকে ভোগ্যপণ্য আলাদা করতে হবে। আপগ্রেড এবং সাবস্ক্রিপশন পণ্য অ-ভোগযোগ্য.
lib/logic/dash_purchases.dart
Future<void> buy(PurchasableProduct product) async {
final purchaseParam = PurchaseParam(productDetails: product.productDetails);
switch (product.id) {
case storeKeyConsumable:
await iapConnection.buyConsumable(purchaseParam: purchaseParam);
break;
case storeKeySubscription:
case storeKeyUpgrade:
await iapConnection.buyNonConsumable(purchaseParam: purchaseParam);
break;
default:
throw ArgumentError.value(
product.productDetails, '${product.id} is not a known product');
}
}
চালিয়ে যাওয়ার আগে, _beautifiedDashUpgrade
ভেরিয়েবলটি তৈরি করুন এবং এটিকে রেফারেন্স করতে beautifiedDash
গেটার আপডেট করুন।
lib/logic/dash_purchases.dart
bool get beautifiedDash => _beautifiedDashUpgrade;
bool _beautifiedDashUpgrade = false;
_onPurchaseUpdate
পদ্ধতি ক্রয় আপডেট গ্রহণ করে, ক্রয় পৃষ্ঠায় প্রদর্শিত পণ্যের স্থিতি আপডেট করে এবং পাল্টা যুক্তিতে ক্রয়কে প্রয়োগ করে। ক্রয়টি পরিচালনা করার পরে completePurchase
কল করা গুরুত্বপূর্ণ যাতে দোকানটি জানে যে ক্রয়টি সঠিকভাবে পরিচালনা করা হয়েছে৷
lib/logic/dash_purchases.dart
Future<void> _onPurchaseUpdate(
List<PurchaseDetails> purchaseDetailsList) async {
for (var purchaseDetails in purchaseDetailsList) {
await _handlePurchase(purchaseDetails);
}
notifyListeners();
}
Future<void> _handlePurchase(PurchaseDetails purchaseDetails) async {
if (purchaseDetails.status == PurchaseStatus.purchased) {
switch (purchaseDetails.productID) {
case storeKeySubscription:
counter.applyPaidMultiplier();
break;
case storeKeyConsumable:
counter.addBoughtDashes(2000);
break;
case storeKeyUpgrade:
_beautifiedDashUpgrade = true;
break;
}
}
if (purchaseDetails.pendingCompletePurchase) {
await iapConnection.completePurchase(purchaseDetails);
}
}
9. ব্যাকএন্ড সেট আপ করুন
ক্রয় ট্র্যাকিং এবং যাচাই করার আগে, এটি করার জন্য সমর্থন করার জন্য একটি ডার্ট ব্যাকএন্ড সেট আপ করুন।
এই বিভাগে, dart-backend/
ফোল্ডার থেকে রুট হিসাবে কাজ করুন।
নিশ্চিত করুন যে আপনার নিম্নলিখিত সরঞ্জামগুলি ইনস্টল করা আছে:
- ডার্ট
- ফায়ারবেস CLI
বেস প্রকল্প ওভারভিউ
কারণ এই প্রকল্পের কিছু অংশ এই কোডল্যাবের সুযোগের বাইরে বিবেচিত হয়, সেগুলি স্টার্টার কোডে অন্তর্ভুক্ত করা হয়। আপনি শুরু করার আগে স্টার্টার কোডে যা আছে তা দেখে নেওয়া একটি ভাল ধারণা, আপনি কীভাবে জিনিসগুলি গঠন করতে যাচ্ছেন সে সম্পর্কে ধারণা পেতে।
এই ব্যাকএন্ড কোডটি আপনার মেশিনে স্থানীয়ভাবে চলতে পারে, এটি ব্যবহার করার জন্য আপনাকে এটি স্থাপন করার প্রয়োজন নেই। যাইহোক, আপনাকে আপনার ডেভেলপমেন্ট ডিভাইস (Android বা iPhone) থেকে সেই মেশিনে সংযোগ করতে সক্ষম হতে হবে যেখানে সার্ভারটি চলবে। এর জন্য, তাদের একই নেটওয়ার্কে থাকতে হবে এবং আপনাকে আপনার মেশিনের আইপি ঠিকানা জানতে হবে।
নিম্নলিখিত কমান্ড ব্যবহার করে সার্ভার চালানোর চেষ্টা করুন:
$ dart ./bin/server.dart
Serving at http://0.0.0.0:8080
ডার্ট ব্যাকএন্ড API এন্ডপয়েন্ট পরিবেশন করতে shelf
এবং shelf_router
ব্যবহার করে। ডিফল্টরূপে, সার্ভার কোনো রুট প্রদান করে না। পরে আপনি ক্রয় যাচাইকরণ প্রক্রিয়া পরিচালনা করার জন্য একটি রুট তৈরি করবেন।
একটি অংশ যা ইতিমধ্যেই স্টার্টার কোডে অন্তর্ভুক্ত করা হয়েছে তা হল lib/iap_repository.dart
এ IapRepository
। যেহেতু ফায়ারস্টোর বা সাধারণভাবে ডেটাবেসের সাথে কীভাবে ইন্টারঅ্যাক্ট করতে হয় তা শেখা এই কোডল্যাবের সাথে প্রাসঙ্গিক বলে বিবেচিত হয় না, স্টার্টার কোডটিতে আপনার জন্য Firestore-এ কেনাকাটা তৈরি বা আপডেট করার ফাংশন রয়েছে, সেইসাথে সেই কেনাকাটার জন্য সমস্ত ক্লাস রয়েছে৷
Firebase অ্যাক্সেস সেট আপ করুন
Firebase Firestore অ্যাক্সেস করতে, আপনার একটি পরিষেবা অ্যাকাউন্ট অ্যাক্সেস কী প্রয়োজন৷ Firebase প্রোজেক্ট সেটিংস খোলার জন্য একটি তৈরি করুন এবং পরিষেবা অ্যাকাউন্ট বিভাগে নেভিগেট করুন, তারপর নতুন ব্যক্তিগত কী তৈরি করুন নির্বাচন করুন।
ডাউনলোড করা JSON ফাইলটিকে assets/
ফোল্ডারে কপি করুন, এবং service-account-firebase.json
এ নাম পরিবর্তন করুন।
Google Play অ্যাক্সেস সেট আপ করুন
কেনাকাটা যাচাই করার জন্য প্লে স্টোর অ্যাক্সেস করতে, আপনাকে অবশ্যই এই অনুমতিগুলির সাথে একটি পরিষেবা অ্যাকাউন্ট তৈরি করতে হবে এবং এর জন্য JSON শংসাপত্রগুলি ডাউনলোড করতে হবে৷
- Google Play Console-এ যান এবং সমস্ত অ্যাপ পৃষ্ঠা থেকে শুরু করুন।
- সেটআপ > API অ্যাক্সেসে যান। যদি Google Play Console অনুরোধ করে যে আপনি একটি বিদ্যমান প্রোজেক্ট তৈরি বা লিঙ্ক করুন, প্রথমে তা করুন এবং তারপরে এই পৃষ্ঠায় ফিরে আসুন।
- বিভাগটি খুঁজুন যেখানে আপনি পরিষেবা অ্যাকাউন্টগুলি সংজ্ঞায়িত করতে পারেন এবং নতুন পরিষেবা অ্যাকাউন্ট তৈরি করুন ক্লিক করুন৷
- পপ আপ হওয়া ডায়ালগে Google ক্লাউড প্ল্যাটফর্ম লিঙ্কে ক্লিক করুন।
- আপনার প্রকল্প নির্বাচন করুন. আপনি যদি এটি দেখতে না পান তবে নিশ্চিত করুন যে আপনি উপরের ডানদিকে অ্যাকাউন্ট ড্রপ-ডাউন তালিকার অধীনে সঠিক Google অ্যাকাউন্টে সাইন ইন করেছেন৷
- আপনার প্রকল্প নির্বাচন করার পরে, উপরের মেনু বারে + পরিষেবা অ্যাকাউন্ট তৈরি করুন ক্লিক করুন।
- পরিষেবা অ্যাকাউন্টের জন্য একটি নাম প্রদান করুন, ঐচ্ছিকভাবে একটি বিবরণ প্রদান করুন যাতে আপনি এটি কিসের জন্য তা মনে রাখতে পারেন এবং পরবর্তী ধাপে যান৷
- পরিষেবা অ্যাকাউন্টটিকে সম্পাদকের ভূমিকা বরাদ্দ করুন।
- উইজার্ডটি শেষ করুন, বিকাশকারী কনসোলের মধ্যে API অ্যাক্সেস পৃষ্ঠায় ফিরে যান এবং পরিষেবা অ্যাকাউন্টগুলি রিফ্রেশ করুন ক্লিক করুন৷ আপনি তালিকায় আপনার নতুন তৈরি অ্যাকাউন্ট দেখতে হবে.
- আপনার নতুন পরিষেবা অ্যাকাউন্টের জন্য অ্যাক্সেস মঞ্জুর করুন ক্লিক করুন৷
- পরবর্তী পৃষ্ঠায় স্ক্রোল করুন, আর্থিক ডেটা ব্লকে। আর্থিক ডেটা, অর্ডার এবং বাতিলকরণ সমীক্ষার প্রতিক্রিয়া দেখুন এবং অর্ডার এবং সদস্যতা পরিচালনা করুন উভয়ই নির্বাচন করুন।
- ব্যবহারকারীকে আমন্ত্রণ করুন ক্লিক করুন।
- এখন যেহেতু অ্যাকাউন্ট সেট আপ করা হয়েছে, আপনাকে শুধু কিছু শংসাপত্র তৈরি করতে হবে। ক্লাউড কনসোলে ফিরে, পরিষেবা অ্যাকাউন্টের তালিকায় আপনার পরিষেবা অ্যাকাউন্ট খুঁজুন, তিনটি উল্লম্ব বিন্দুতে ক্লিক করুন এবং কীগুলি পরিচালনা করুন বেছে নিন।
- একটি নতুন JSON কী তৈরি করুন এবং এটি ডাউনলোড করুন।
- ডাউনলোড করা ফাইলটিকে
service-account-google-play.json,
এ পুনঃনামকরণ করুন এবং এটিকেassets/
ডিরেক্টরিতে স্থানান্তর করুন৷
আমাদের আরও একটি জিনিস করতে হবে তা হল lib/constants.dart,
এবং আপনার Android অ্যাপের জন্য বেছে নেওয়া প্যাকেজ আইডি দিয়ে androidPackageId
এর মান প্রতিস্থাপন করুন।
অ্যাপল অ্যাপ স্টোর অ্যাক্সেস সেট আপ করুন
কেনাকাটা যাচাই করার জন্য অ্যাপ স্টোর অ্যাক্সেস করতে, আপনাকে একটি ভাগ করা গোপন সেট আপ করতে হবে:
- অ্যাপ স্টোর কানেক্ট খুলুন।
- My Apps এ যান এবং আপনার অ্যাপ নির্বাচন করুন।
- সাইডবার নেভিগেশনে, অ্যাপ-মধ্যস্থ কেনাকাটা > পরিচালনায় যান।
- তালিকার উপরের ডানদিকে, অ্যাপ-স্পেসিফিক শেয়ারড সিক্রেট ক্লিক করুন।
- একটি নতুন গোপন তৈরি করুন এবং এটি অনুলিপি করুন।
-
lib/constants.dart,
খুলুন এবংappStoreSharedSecret
এর মানটি আপনার সদ্য জেনারেট করা শেয়ার্ড সিক্রেট দিয়ে প্রতিস্থাপন করুন।
ধ্রুবক কনফিগারেশন ফাইল
এগিয়ে যাওয়ার আগে, নিশ্চিত করুন যে নিম্নলিখিত ধ্রুবকগুলি lib/constants.dart
ফাইলে কনফিগার করা হয়েছে:
-
androidPackageId
: অ্যান্ড্রয়েডে ব্যবহৃত প্যাকেজ আইডি। যেমনcom.example.dashclicker
-
appStoreSharedSecret
: ক্রয় যাচাইকরণ সম্পাদন করতে অ্যাপ স্টোর কানেক্ট অ্যাক্সেস করার জন্য ভাগ করা গোপনীয়তা। -
bundleId
: আইওএসে ব্যবহৃত বান্ডিল আইডি। যেমনcom.example.dashclicker
আপনি আপাতত বাকী ধ্রুবকগুলি উপেক্ষা করতে পারেন।
10. ক্রয় যাচাই করুন
ক্রয়ের যাচাইয়ের জন্য সাধারণ প্রবাহ আইওএস এবং অ্যান্ড্রয়েডের জন্য অনুরূপ।
উভয় স্টোরের জন্য, আপনার অ্যাপ্লিকেশনটি যখন কোনও ক্রয় করা হয় তখন একটি টোকেন পায়।
এই টোকেনটি অ্যাপ্লিকেশন দ্বারা আপনার ব্যাকএন্ড পরিষেবাতে প্রেরণ করা হয়, যা তারপরে, সরবরাহিত টোকেন ব্যবহার করে সংশ্লিষ্ট স্টোরের সার্ভারগুলির সাথে ক্রয়টি যাচাই করে।
এরপরে ব্যাকএন্ড পরিষেবাটি ক্রয়টি সঞ্চয় করতে বেছে নিতে পারে এবং ক্রয়টি বৈধ ছিল কি না তা অ্যাপ্লিকেশনটির জবাব দিতে পারে।
ব্যাকএন্ড পরিষেবাটি আপনার ব্যবহারকারীর ডিভাইসে চলমান অ্যাপ্লিকেশনটির পরিবর্তে স্টোরগুলির সাথে বৈধতাটি করে, আপনি ব্যবহারকারীকে প্রিমিয়াম বৈশিষ্ট্যগুলিতে অ্যাক্সেস অর্জন করতে বাধা দিতে পারেন, উদাহরণস্বরূপ, তাদের সিস্টেম ঘড়িটি রিওয়াইন্ড করে।
ঝাঁকুনির দিকটি সেট আপ করুন
প্রমাণীকরণ সেট আপ করুন
আপনি যখন আপনার ব্যাকএন্ড পরিষেবাতে ক্রয়গুলি প্রেরণ করতে যাচ্ছেন, আপনি নিশ্চিত করতে চান যে কোনও ক্রয় করার সময় ব্যবহারকারী অনুমোদিত হয়েছে। স্টার্টার প্রকল্পে আপনার জন্য ইতিমধ্যে বেশিরভাগ প্রমাণীকরণের যুক্তি যুক্ত করা হয়েছে, আপনাকে কেবল নিশ্চিত করতে হবে যে PurchasePage
লগইন বোতামটি দেখায় যখন ব্যবহারকারী এখনও লগ ইন না করা হয়। PurchasePage
বিল্ড পদ্ধতির শুরুতে নিম্নলিখিত কোডটি যুক্ত করুন:
lib/পৃষ্ঠা/ক্রয়_পেজ.ডার্ট
import '../logic/firebase_notifier.dart';
import '../model/firebase_state.dart';
import 'login_page.dart';
class PurchasePage extends StatelessWidget {
const PurchasePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
var firebaseNotifier = context.watch<FirebaseNotifier>();
if (firebaseNotifier.state == FirebaseState.loading) {
return _PurchasesLoading();
} else if (firebaseNotifier.state == FirebaseState.notAvailable) {
return _PurchasesNotAvailable();
}
if (!firebaseNotifier.loggedIn) {
return const LoginPage();
}
// omitted
অ্যাপ থেকে যাচাইকরণ শেষ পয়েন্ট কল করুন
অ্যাপটিতে, _verifyPurchase(PurchaseDetails purchaseDetails)
ফাংশন তৈরি করুন যা এইচটিটিপি পোস্ট কল ব্যবহার করে আপনার ডার্ট ব্যাকএন্ডে /verifypurchase
এন্ডপয়েন্টকে কল করে।
নির্বাচিত স্টোর (প্লে স্টোরের জন্য google_play
বা অ্যাপ স্টোরের জন্য app_store
), serverVerificationData
এবং productID
প্রেরণ করুন। ক্রয়টি যাচাই করা হয়েছে কিনা তা নির্দেশ করে সার্ভার স্ট্যাটাস কোডটি ফেরত দেয়।
অ্যাপ কনস্ট্যান্টগুলিতে, আপনার স্থানীয় মেশিন আইপি ঠিকানায় সার্ভার আইপি কনফিগার করুন।
lib/লজিক/ড্যাশ_প্রেসেস.ডার্ট
FirebaseNotifier firebaseNotifier;
DashPurchases(this.counter, this.firebaseNotifier) {
// omitted
}
মেইন.ডার্টে DashPurchases
তৈরির সাথে firebaseNotifier
যুক্ত করুন main.dart:
lib/main.dart
ChangeNotifierProvider<DashPurchases>(
create: (context) => DashPurchases(
context.read<DashCounter>(),
context.read<FirebaseNotifier>(),
),
lazy: false,
),
ফায়ারবেসেনোটিফায়ারে ব্যবহারকারীর জন্য একটি গেটার যুক্ত করুন, যাতে আপনি ব্যবহারকারী আইডিটি যাচাই ক্রয়ের ফাংশনে পাস করতে পারেন।
lib/লজিক/ফায়ারবেস_নোটিফায়ার.ডার্ট
User? get user => FirebaseAuth.instance.currentUser;
DashPurchases
ক্লাসে ফাংশন _verifyPurchase
যুক্ত করুন। এই async
ফাংশনটি একটি বুলিয়ান ফেরত দেয় যা ক্রয়টি বৈধ হয়েছে কিনা তা নির্দেশ করে।
lib/লজিক/ড্যাশ_প্রেসেস.ডার্ট
Future<bool> _verifyPurchase(PurchaseDetails purchaseDetails) async {
final url = Uri.parse('http://$serverIp:8080/verifypurchase');
const headers = {
'Content-type': 'application/json',
'Accept': 'application/json',
};
final response = await http.post(
url,
body: jsonEncode({
'source': purchaseDetails.verificationData.source,
'productId': purchaseDetails.productID,
'verificationData':
purchaseDetails.verificationData.serverVerificationData,
'userId': firebaseNotifier.user?.uid,
}),
headers: headers,
);
if (response.statusCode == 200) {
print('Successfully verified purchase');
return true;
} else {
print('failed request: ${response.statusCode} - ${response.body}');
return false;
}
}
আপনি ক্রয়টি প্রয়োগ করার ঠিক আগে _ _handlePurchase
_verifyPurchase
ফাংশনটি কল করুন। এটি যাচাই করা হয় কেবল তখনই আপনার ক্রয়টি প্রয়োগ করা উচিত। একটি প্রোডাকশন অ্যাপে, আপনি এটিকে আরও নির্দিষ্ট করতে পারেন, উদাহরণস্বরূপ, স্টোরটি অস্থায়ীভাবে অনুপলব্ধ থাকাকালীন একটি ট্রায়াল সাবস্ক্রিপশন প্রয়োগ করুন। তবে, এই উদাহরণের জন্য, এটি সহজ রাখুন এবং ক্রয়টি সফলভাবে যাচাই করা হলে কেবল ক্রয়টি প্রয়োগ করুন।
lib/লজিক/ড্যাশ_প্রেসেস.ডার্ট
Future<void> _onPurchaseUpdate(
List<PurchaseDetails> purchaseDetailsList) async {
for (var purchaseDetails in purchaseDetailsList) {
await _handlePurchase(purchaseDetails);
}
notifyListeners();
}
Future<void> _handlePurchase(PurchaseDetails purchaseDetails) async {
if (purchaseDetails.status == PurchaseStatus.purchased) {
// Send to server
var validPurchase = await _verifyPurchase(purchaseDetails);
if (validPurchase) {
// Apply changes locally
switch (purchaseDetails.productID) {
case storeKeySubscription:
counter.applyPaidMultiplier();
break;
case storeKeyConsumable:
counter.addBoughtDashes(1000);
break;
}
}
}
if (purchaseDetails.pendingCompletePurchase) {
await iapConnection.completePurchase(purchaseDetails);
}
}
অ্যাপটিতে সবকিছু এখন ক্রয়গুলি বৈধ করার জন্য প্রস্তুত।
ব্যাকএন্ড পরিষেবা সেট আপ করুন
এরপরে, ব্যাকএন্ডে ক্রয়গুলি যাচাই করার জন্য ক্লাউড ফাংশন সেট আপ করুন।
ক্রয় হ্যান্ডলারগুলি তৈরি করুন
যেহেতু উভয় স্টোরের জন্য যাচাইকরণ প্রবাহ অভিন্নর কাছাকাছি, প্রতিটি স্টোরের জন্য পৃথক বাস্তবায়ন সহ একটি বিমূর্ত PurchaseHandler
ক্লাস সেট আপ করুন।
lib/
ফোল্ডারে একটি purchase_handler.dart
ফাইল যুক্ত করে শুরু করুন, যেখানে আপনি দুটি ভিন্ন ধরণের ক্রয়ের যাচাই করার জন্য দুটি বিমূর্ত পদ্ধতি সহ একটি বিমূর্ত PurchaseHandler
শ্রেণীর সংজ্ঞায়িত করেছেন: সাবস্ক্রিপশন এবং নন-সাবস্ক্রিপশন।
lib/ক্রয়_হ্যান্ডলার.ডার্ট
import 'products.dart';
/// Generic purchase handler,
/// must be implemented for Google Play and Apple Store
abstract class PurchaseHandler {
/// Verify if non-subscription purchase (aka consumable) is valid
/// and update the database
Future<bool> handleNonSubscription({
required String userId,
required ProductData productData,
required String token,
});
/// Verify if subscription purchase (aka non-consumable) is valid
/// and update the database
Future<bool> handleSubscription({
required String userId,
required ProductData productData,
required String token,
});
}
আপনি দেখতে পাচ্ছেন, প্রতিটি পদ্ধতিতে তিনটি পরামিতি প্রয়োজন:
-
userId:
লগ-ইন ব্যবহারকারীর আইডি, যাতে আপনি ব্যবহারকারীর সাথে ক্রয় বেঁধে রাখতে পারেন। -
productData:
পণ্য সম্পর্কে ডেটা। আপনি এক মিনিটের মধ্যে এটি সংজ্ঞায়িত করতে যাচ্ছেন। -
token:
টোকেনটি স্টোরের মাধ্যমে ব্যবহারকারীকে সরবরাহ করেছে।
অতিরিক্তভাবে, এই ক্রয় হ্যান্ডলারগুলি ব্যবহার করা সহজ করার জন্য, একটি verifyPurchase()
পদ্ধতি যুক্ত করুন যা সাবস্ক্রিপশন এবং নন-সাবস্ক্রিপশন উভয়ের জন্য ব্যবহার করা যেতে পারে:
lib/ক্রয়_হ্যান্ডলার.ডার্ট
/// Verify if purchase is valid and update the database
Future<bool> verifyPurchase({
required String userId,
required ProductData productData,
required String token,
}) async {
switch (productData.type) {
case ProductType.subscription:
return handleSubscription(
userId: userId,
productData: productData,
token: token,
);
case ProductType.nonSubscription:
return handleNonSubscription(
userId: userId,
productData: productData,
token: token,
);
}
}
এখন, আপনি উভয় ক্ষেত্রেই কেবল verifyPurchase
কল করতে পারেন, তবে এখনও পৃথক বাস্তবায়ন রয়েছে!
ProductData
ক্লাসে বিভিন্ন ক্রয়যোগ্য পণ্য সম্পর্কে প্রাথমিক তথ্য রয়েছে, যার মধ্যে পণ্য আইডি (কখনও কখনও এসকেইউ হিসাবেও পরিচিত) এবং ProductType
অন্তর্ভুক্ত রয়েছে।
lib/product.dart
class ProductData {
final String productId;
final ProductType type;
const ProductData(this.productId, this.type);
}
ProductType
হয় সাবস্ক্রিপশন বা নন-সাবস্ক্রিপশন হতে পারে।
lib/product.dart
enum ProductType {
subscription,
nonSubscription,
}
অবশেষে, পণ্যগুলির তালিকা একই ফাইলের মানচিত্র হিসাবে সংজ্ঞায়িত করা হয়।
lib/product.dart
const productDataMap = {
'dash_consumable_2k': ProductData(
'dash_consumable_2k',
ProductType.nonSubscription,
),
'dash_upgrade_3d': ProductData(
'dash_upgrade_3d',
ProductType.nonSubscription,
),
'dash_subscription_doubler': ProductData(
'dash_subscription_doubler',
ProductType.subscription,
),
};
এরপরে, গুগল প্লে স্টোর এবং অ্যাপল অ্যাপ স্টোরের জন্য কিছু স্থানধারক বাস্তবায়ন সংজ্ঞায়িত করুন। গুগল প্লে দিয়ে শুরু করুন:
lib/google_play_purchase_handler.dart
তৈরি করুন এবং এমন একটি ক্লাস যুক্ত করুন যা আপনি কেবল লিখেছেন এমন PurchaseHandler
প্রসারিত করে:
lib/google_ple_purchase_handler.dart
import 'dart:async';
import 'package:googleapis/androidpublisher/v3.dart' as ap;
import 'constants.dart';
import 'iap_repository.dart';
import 'products.dart';
import 'purchase_handler.dart';
class GooglePlayPurchaseHandler extends PurchaseHandler {
final ap.AndroidPublisherApi androidPublisher;
final IapRepository iapRepository;
GooglePlayPurchaseHandler(
this.androidPublisher,
this.iapRepository,
);
@override
Future<bool> handleNonSubscription({
required String? userId,
required ProductData productData,
required String token,
}) async {
return true;
}
@override
Future<bool> handleSubscription({
required String? userId,
required ProductData productData,
required String token,
}) async {
return true;
}
}
আপাতত, এটি হ্যান্ডলার পদ্ধতির জন্য true
প্রত্যাবর্তন করে; আপনি পরে তাদের কাছে পাবেন।
আপনি যেমন লক্ষ্য করেছেন, কনস্ট্রাক্টর IapRepository
উদাহরণ নেন। ক্রয় হ্যান্ডলার পরে ফায়ারস্টোরে ক্রয় সম্পর্কিত তথ্য সঞ্চয় করতে এই উদাহরণটি ব্যবহার করে। গুগল প্লে এর সাথে যোগাযোগ করতে, আপনি সরবরাহিত AndroidPublisherApi
ব্যবহার করেন।
এরপরে, অ্যাপ স্টোর হ্যান্ডলারের জন্য একই কাজ করুন। lib/app_store_purchase_handler.dart
তৈরি করুন এবং একটি ক্লাস যুক্ত করুন যা আবার PurchaseHandler
প্রসারিত করে:
lib/app_store_purchase_handler.dart
import 'dart:async';
import 'package:app_store_server_sdk/app_store_server_sdk.dart';
import 'constants.dart';
import 'iap_repository.dart';
import 'products.dart';
import 'purchase_handler.dart';
class AppStorePurchaseHandler extends PurchaseHandler {
final IapRepository iapRepository;
AppStorePurchaseHandler(
this.iapRepository,
);
@override
Future<bool> handleNonSubscription({
required String userId,
required ProductData productData,
required String token,
}) {
return true;
}
@override
Future<bool> handleSubscription({
required String userId,
required ProductData productData,
required String token,
}) {
return true;
}
}
দারুণ! এখন আপনার দুটি ক্রয় হ্যান্ডলার রয়েছে। এরপরে, আসুন ক্রয় যাচাইকরণ এপিআই এন্ডপয়েন্টটি তৈরি করুন।
ক্রয় হ্যান্ডলারগুলি ব্যবহার করুন
bin/server.dart
খুলুন এবং shelf_route
ব্যবহার করে একটি এপিআই এন্ডপয়েন্ট তৈরি করুন:
বিন/সার্ভার.ডার্ট
Future<void> main() async {
final router = Router();
final purchaseHandlers = await _createPurchaseHandlers();
router.post('/verifypurchase', (Request request) async {
final dynamic payload = json.decode(await request.readAsString());
final (:userId, :source, :productData, :token) = getPurchaseData(payload);
final result = await purchaseHandlers[source]!.verifyPurchase(
userId: userId,
productData: productData,
token: token,
);
if (result) {
return Response.ok('all good!');
} else {
return Response.internalServerError();
}
});
await serveHandler(router);
}
({
String userId,
String source,
ProductData productData,
String token,
}) getPurchaseData(dynamic payload) {
if (payload
case {
'userId': String userId,
'source': String source,
'productId': String productId,
'verificationData': String token,
}) {
return (
userId: userId,
source: source,
productData: productDataMap[productId]!,
token: token,
);
} else {
throw const FormatException('Unexpected JSON');
}
}
উপরের কোডটি নিম্নলিখিতগুলি করছে:
- একটি পোস্ট এন্ডপয়েন্টটি সংজ্ঞায়িত করুন যা আপনি আগে তৈরি করা অ্যাপ্লিকেশন থেকে কল করা হবে।
- JSON পে -লোড ডিকোড করুন এবং নিম্নলিখিত তথ্যগুলি বের করুন:
-
userId
: বর্তমানে ব্যবহারকারী আইডি লগ ইন -
source
:app_store
বাgoogle_play
হয় স্টোর ব্যবহৃত হয়। -
productData
: আপনি আগে তৈরিproductDataMap
থেকে প্রাপ্ত। -
token
: স্টোরগুলিতে প্রেরণের জন্য যাচাইকরণের ডেটা রয়েছে। - উত্সের উপর নির্ভর করে
GooglePlayPurchaseHandler
বাAppStorePurchaseHandler
জন্য,verifyPurchase
পদ্ধতিতে কল করুন। - যদি যাচাইকরণ সফল হয় তবে পদ্ধতিটি একটি
Response.ok
দেয় ok ক্লায়েন্টকে। - যদি যাচাইকরণ ব্যর্থ হয় তবে পদ্ধতিটি একটি
Response.internalServerError
দেয় Clien
এপিআই এন্ডপয়েন্ট তৈরি করার পরে, আপনাকে দুটি ক্রয় হ্যান্ডলারগুলি কনফিগার করতে হবে। এর জন্য আপনার পূর্ববর্তী পদক্ষেপে প্রাপ্ত পরিষেবা অ্যাকাউন্ট কীগুলি লোড করা এবং অ্যান্ড্রয়েড প্রকাশক এপিআই এবং ফায়ারবেস ফায়ারস্টোর এপিআই সহ বিভিন্ন পরিষেবাগুলিতে অ্যাক্সেস কনফিগার করতে হবে। তারপরে, বিভিন্ন নির্ভরতা সহ দুটি ক্রয় হ্যান্ডলার তৈরি করুন:
বিন/সার্ভার.ডার্ট
Future<Map<String, PurchaseHandler>> _createPurchaseHandlers() async {
// Configure Android Publisher API access
final serviceAccountGooglePlay =
File('assets/service-account-google-play.json').readAsStringSync();
final clientCredentialsGooglePlay =
auth.ServiceAccountCredentials.fromJson(serviceAccountGooglePlay);
final clientGooglePlay =
await auth.clientViaServiceAccount(clientCredentialsGooglePlay, [
ap.AndroidPublisherApi.androidpublisherScope,
]);
final androidPublisher = ap.AndroidPublisherApi(clientGooglePlay);
// Configure Firestore API access
final serviceAccountFirebase =
File('assets/service-account-firebase.json').readAsStringSync();
final clientCredentialsFirebase =
auth.ServiceAccountCredentials.fromJson(serviceAccountFirebase);
final clientFirebase =
await auth.clientViaServiceAccount(clientCredentialsFirebase, [
fs.FirestoreApi.cloudPlatformScope,
]);
final firestoreApi = fs.FirestoreApi(clientFirebase);
final dynamic json = jsonDecode(serviceAccountFirebase);
final projectId = json['project_id'] as String;
final iapRepository = IapRepository(firestoreApi, projectId);
return {
'google_play': GooglePlayPurchaseHandler(
androidPublisher,
iapRepository,
),
'app_store': AppStorePurchaseHandler(
iapRepository,
),
};
}
অ্যান্ড্রয়েড ক্রয়গুলি যাচাই করুন: ক্রয়ের হ্যান্ডারটি প্রয়োগ করুন
এরপরে, গুগল প্লে ক্রয় হ্যান্ডলারটি বাস্তবায়ন চালিয়ে যান।
গুগল ইতিমধ্যে আপনার ক্রয়গুলি যাচাই করতে প্রয়োজনীয় এপিআইগুলির সাথে ইন্টারঅ্যাক্ট করার জন্য ডার্ট প্যাকেজ সরবরাহ করে। আপনি এগুলি server.dart
ফাইলে আরম্ভ করেছেন এবং এখন এগুলি GooglePlayPurchaseHandler
ক্লাসে ব্যবহার করুন।
নন-সাবস্ক্রিপশন-টাইপ ক্রয়ের জন্য হ্যান্ডলারটি প্রয়োগ করুন:
lib/google_ple_purchase_handler.dart
@override
Future<bool> handleNonSubscription({
required String? userId,
required ProductData productData,
required String token,
}) async {
print(
'GooglePlayPurchaseHandler.handleNonSubscription'
'($userId, ${productData.productId}, ${token.substring(0, 5)}...)',
);
try {
// Verify purchase with Google
final response = await androidPublisher.purchases.products.get(
androidPackageId,
productData.productId,
token,
);
print('Purchases response: ${response.toJson()}');
// Make sure an order id exists
if (response.orderId == null) {
print('Could not handle purchase without order id');
return false;
}
final orderId = response.orderId!;
final purchaseData = NonSubscriptionPurchase(
purchaseDate: DateTime.fromMillisecondsSinceEpoch(
int.parse(response.purchaseTimeMillis ?? '0'),
),
orderId: orderId,
productId: productData.productId,
status: _nonSubscriptionStatusFrom(response.purchaseState),
userId: userId,
iapSource: IAPSource.googleplay,
);
// Update the database
if (userId != null) {
// If we know the userId,
// update the existing purchase or create it if it does not exist.
await iapRepository.createOrUpdatePurchase(purchaseData);
} else {
// If we do not know the user id, a previous entry must already
// exist, and thus we'll only update it.
await iapRepository.updatePurchase(purchaseData);
}
return true;
} on ap.DetailedApiRequestError catch (e) {
print(
'Error on handle NonSubscription: $e\n'
'JSON: ${e.jsonResponse}',
);
} catch (e) {
print('Error on handle NonSubscription: $e\n');
}
return false;
}
আপনি সাবস্ক্রিপশন ক্রয় হ্যান্ডলারটিকে একইভাবে আপডেট করতে পারেন:
lib/google_ple_purchase_handler.dart
/// Handle subscription purchases.
///
/// Retrieves the purchase status from Google Play and updates
/// the Firestore Database accordingly.
@override
Future<bool> handleSubscription({
required String? userId,
required ProductData productData,
required String token,
}) async {
print(
'GooglePlayPurchaseHandler.handleSubscription'
'($userId, ${productData.productId}, ${token.substring(0, 5)}...)',
);
try {
// Verify purchase with Google
final response = await androidPublisher.purchases.subscriptions.get(
androidPackageId,
productData.productId,
token,
);
print('Subscription response: ${response.toJson()}');
// Make sure an order id exists
if (response.orderId == null) {
print('Could not handle purchase without order id');
return false;
}
final orderId = extractOrderId(response.orderId!);
final purchaseData = SubscriptionPurchase(
purchaseDate: DateTime.fromMillisecondsSinceEpoch(
int.parse(response.startTimeMillis ?? '0'),
),
orderId: orderId,
productId: productData.productId,
status: _subscriptionStatusFrom(response.paymentState),
userId: userId,
iapSource: IAPSource.googleplay,
expiryDate: DateTime.fromMillisecondsSinceEpoch(
int.parse(response.expiryTimeMillis ?? '0'),
),
);
// Update the database
if (userId != null) {
// If we know the userId,
// update the existing purchase or create it if it does not exist.
await iapRepository.createOrUpdatePurchase(purchaseData);
} else {
// If we do not know the user id, a previous entry must already
// exist, and thus we'll only update it.
await iapRepository.updatePurchase(purchaseData);
}
return true;
} on ap.DetailedApiRequestError catch (e) {
print(
'Error on handle Subscription: $e\n'
'JSON: ${e.jsonResponse}',
);
} catch (e) {
print('Error on handle Subscription: $e\n');
}
return false;
}
}
অর্ডার আইডিগুলির পার্সিংয়ের সুবিধার্থে নিম্নলিখিত পদ্ধতিটি যুক্ত করুন, পাশাপাশি ক্রয়ের স্থিতি পার্স করার জন্য দুটি পদ্ধতি যুক্ত করুন।
lib/google_ple_purchase_handler.dart
/// If a subscription suffix is present (..#) extract the orderId.
String extractOrderId(String orderId) {
final orderIdSplit = orderId.split('..');
if (orderIdSplit.isNotEmpty) {
orderId = orderIdSplit[0];
}
return orderId;
}
NonSubscriptionStatus _nonSubscriptionStatusFrom(int? state) {
return switch (state) {
0 => NonSubscriptionStatus.completed,
2 => NonSubscriptionStatus.pending,
_ => NonSubscriptionStatus.cancelled,
};
}
SubscriptionStatus _subscriptionStatusFrom(int? state) {
return switch (state) {
// Payment pending
0 => SubscriptionStatus.pending,
// Payment received
1 => SubscriptionStatus.active,
// Free trial
2 => SubscriptionStatus.active,
// Pending deferred upgrade/downgrade
3 => SubscriptionStatus.pending,
// Expired or cancelled
_ => SubscriptionStatus.expired,
};
}
আপনার গুগল প্লে ক্রয়গুলি এখন যাচাই করা উচিত এবং ডাটাবেসে সংরক্ষণ করা উচিত।
এরপরে, আইওএসের জন্য অ্যাপ স্টোর ক্রয়ের দিকে এগিয়ে যান।
আইওএস ক্রয়গুলি যাচাই করুন: ক্রয় হ্যান্ডলারটি প্রয়োগ করুন
অ্যাপ স্টোর দিয়ে ক্রয় যাচাই করার জন্য, একটি তৃতীয় পক্ষের ডার্ট প্যাকেজটি app_store_server_sdk
নামযুক্ত যা প্রক্রিয়াটিকে আরও সহজ করে তোলে।
ITunesApi
উদাহরণ তৈরি করে শুরু করুন। স্যান্ডবক্স কনফিগারেশনটি ব্যবহার করুন, পাশাপাশি ত্রুটি ডিবাগিংয়ের সুবিধার্থে লগিং সক্ষম করুন।
lib/app_store_purchase_handler.dart
final _iTunesAPI = ITunesApi(
ITunesHttpClient(
ITunesEnvironment.sandbox(),
loggingEnabled: true,
),
);
এখন, গুগল প্লে এপিআইগুলির বিপরীতে, অ্যাপ স্টোরটি সাবস্ক্রিপশন এবং নন-সাবস্ক্রিপশন উভয়ের জন্য একই এপিআই এন্ডপয়েন্টগুলি ব্যবহার করে। এর অর্থ হ'ল আপনি উভয় হ্যান্ডলারের জন্য একই যুক্তি ব্যবহার করতে পারেন। তাদের একত্রে মার্জ করুন যাতে তারা একই বাস্তবায়ন বলে:
lib/app_store_purchase_handler.dart
@override
Future<bool> handleNonSubscription({
required String userId,
required ProductData productData,
required String token,
}) {
return handleValidation(userId: userId, token: token);
}
@override
Future<bool> handleSubscription({
required String userId,
required ProductData productData,
required String token,
}) {
return handleValidation(userId: userId, token: token);
}
/// Handle purchase validation.
Future<bool> handleValidation({
required String userId,
required String token,
}) async {
//..
}
এখন, handleValidation
প্রয়োগ করুন:
lib/app_store_purchase_handler.dart
/// Handle purchase validation.
Future<bool> handleValidation({
required String userId,
required String token,
}) async {
print('AppStorePurchaseHandler.handleValidation');
final response = await _iTunesAPI.verifyReceipt(
password: appStoreSharedSecret,
receiptData: token,
);
print('response: $response');
if (response.status == 0) {
print('Successfully verified purchase');
final receipts = response.latestReceiptInfo ?? [];
for (final receipt in receipts) {
final product = productDataMap[receipt.productId];
if (product == null) {
print('Error: Unknown product: ${receipt.productId}');
continue;
}
switch (product.type) {
case ProductType.nonSubscription:
await iapRepository.createOrUpdatePurchase(NonSubscriptionPurchase(
userId: userId,
productId: receipt.productId ?? '',
iapSource: IAPSource.appstore,
orderId: receipt.originalTransactionId ?? '',
purchaseDate: DateTime.fromMillisecondsSinceEpoch(
int.parse(receipt.originalPurchaseDateMs ?? '0')),
type: product.type,
status: NonSubscriptionStatus.completed,
));
break;
case ProductType.subscription:
await iapRepository.createOrUpdatePurchase(SubscriptionPurchase(
userId: userId,
productId: receipt.productId ?? '',
iapSource: IAPSource.appstore,
orderId: receipt.originalTransactionId ?? '',
purchaseDate: DateTime.fromMillisecondsSinceEpoch(
int.parse(receipt.originalPurchaseDateMs ?? '0')),
type: product.type,
expiryDate: DateTime.fromMillisecondsSinceEpoch(
int.parse(receipt.expiresDateMs ?? '0')),
status: SubscriptionStatus.active,
));
break;
}
}
return true;
} else {
print('Error: Status: ${response.status}');
return false;
}
}
আপনার অ্যাপ স্টোর ক্রয়গুলি এখন যাচাই করা উচিত এবং ডাটাবেসে সংরক্ষণ করা উচিত!
ব্যাকএন্ড চালান
এই মুহুর্তে, আপনি /verifypurchase
এন্ডপয়েন্টটি পরিবেশন করতে dart bin/server.dart
চালাতে পারেন।
$ dart bin/server.dart
Serving at http://0.0.0.0:8080
১১. ক্রয়ের উপর নজর রাখুন
আপনার ব্যবহারকারীদের ক্রয়গুলি ট্র্যাক করার প্রস্তাবিত উপায়টি ব্যাকএন্ড পরিষেবাতে। এটি কারণ আপনার ব্যাকএন্ড স্টোর থেকে ইভেন্টগুলিতে সাড়া দিতে পারে এবং এভাবে ক্যাশিংয়ের কারণে পুরানো তথ্যগুলিতে দৌড়াতে কম ঝুঁকির পাশাপাশি টেম্পার হওয়ার জন্য কম সংবেদনশীল হতে পারে।
প্রথমে, আপনি যে ডার্ট ব্যাকএন্ডটি তৈরি করছেন তার সাথে ব্যাকএন্ডে স্টোর ইভেন্টগুলির প্রক্রিয়াকরণ সেট আপ করুন।
ব্যাকএন্ডে স্টোর ইভেন্টগুলি প্রক্রিয়া করুন
স্টোরগুলিতে আপনার যে কোনও বিলিং ইভেন্টগুলি ঘটে তার ব্যাকএন্ডকে অবহিত করার ক্ষমতা রয়েছে যেমন সাবস্ক্রিপশন পুনর্নবীকরণ। আপনার ডাটাবেস কারেন্টে ক্রয়গুলি রাখতে আপনি আপনার ব্যাকএন্ডে এই ইভেন্টগুলি প্রক্রিয়া করতে পারেন। এই বিভাগে, এটি গুগল প্লে স্টোর এবং অ্যাপল অ্যাপ স্টোর উভয়ের জন্য সেট আপ করুন।
প্রক্রিয়া গুগল প্লে বিলিং ইভেন্ট
গুগল প্লে তারা ক্লাউড পাব/সাব বিষয়কে যা বলে তার মাধ্যমে বিলিং ইভেন্টগুলি সরবরাহ করে। এগুলি মূলত বার্তা সারি যা বার্তাগুলি প্রকাশ করা যেতে পারে, পাশাপাশি গ্রাস করা যায়।
যেহেতু এটি গুগল প্লে সম্পর্কিত কার্যকারিতা নির্দিষ্ট, আপনি এই কার্যকারিতাটি GooglePlayPurchaseHandler
অন্তর্ভুক্ত করেছেন।
lib/google_play_purchase_handler.dart
খোলার মাধ্যমে এবং পাবসুবাপি আমদানি যুক্ত করে শুরু করুন:
lib/google_ple_purchase_handler.dart
import 'package:googleapis/pubsub/v1.dart' as pubsub;
তারপরে, PubsubApi
GooglePlayPurchaseHandler
কাছে পাস করুন এবং নিম্নলিখিত হিসাবে একটি Timer
তৈরি করতে ক্লাস কনস্ট্রাক্টরকে সংশোধন করুন:
lib/google_ple_purchase_handler.dart
class GooglePlayPurchaseHandler extends PurchaseHandler {
final ap.AndroidPublisherApi androidPublisher;
final IapRepository iapRepository;
final pubsub.PubsubApi pubsubApi; // new
GooglePlayPurchaseHandler(
this.androidPublisher,
this.iapRepository,
this.pubsubApi, // new
) {
// Poll messages from Pub/Sub every 10 seconds
Timer.periodic(Duration(seconds: 10), (_) {
_pullMessageFromPubSub();
});
}
Timer
প্রতি দশ সেকেন্ডে _ _pullMessageFromSubSub
পদ্ধতিতে কল করার জন্য কনফিগার করা হয়। আপনি সময়কালটি আপনার নিজের পছন্দকে সামঞ্জস্য করতে পারেন।
তারপরে, _pullMessageFromSubSub
তৈরি করুন
lib/google_ple_purchase_handler.dart
/// Process messages from Google Play
/// Called every 10 seconds
Future<void> _pullMessageFromPubSub() async {
print('Polling Google Play messages');
final request = pubsub.PullRequest(
maxMessages: 1000,
);
final topicName =
'projects/$googlePlayProjectName/subscriptions/$googlePlayPubsubBillingTopic-sub';
final pullResponse = await pubsubApi.projects.subscriptions.pull(
request,
topicName,
);
final messages = pullResponse.receivedMessages ?? [];
for (final message in messages) {
final data64 = message.message?.data;
if (data64 != null) {
await _processMessage(data64, message.ackId);
}
}
}
Future<void> _processMessage(String data64, String? ackId) async {
final dataRaw = utf8.decode(base64Decode(data64));
print('Received data: $dataRaw');
final dynamic data = jsonDecode(dataRaw);
if (data['testNotification'] != null) {
print('Skip test messages');
if (ackId != null) {
await _ackMessage(ackId);
}
return;
}
final dynamic subscriptionNotification = data['subscriptionNotification'];
final dynamic oneTimeProductNotification =
data['oneTimeProductNotification'];
if (subscriptionNotification != null) {
print('Processing Subscription');
final subscriptionId =
subscriptionNotification['subscriptionId'] as String;
final purchaseToken = subscriptionNotification['purchaseToken'] as String;
final productData = productDataMap[subscriptionId]!;
final result = await handleSubscription(
userId: null,
productData: productData,
token: purchaseToken,
);
if (result && ackId != null) {
await _ackMessage(ackId);
}
} else if (oneTimeProductNotification != null) {
print('Processing NonSubscription');
final sku = oneTimeProductNotification['sku'] as String;
final purchaseToken =
oneTimeProductNotification['purchaseToken'] as String;
final productData = productDataMap[sku]!;
final result = await handleNonSubscription(
userId: null,
productData: productData,
token: purchaseToken,
);
if (result && ackId != null) {
await _ackMessage(ackId);
}
} else {
print('invalid data');
}
}
/// ACK Messages from Pub/Sub
Future<void> _ackMessage(String id) async {
print('ACK Message');
final request = pubsub.AcknowledgeRequest(
ackIds: [id],
);
final subscriptionName =
'projects/$googlePlayProjectName/subscriptions/$googlePlayPubsubBillingTopic-sub';
await pubsubApi.projects.subscriptions.acknowledge(
request,
subscriptionName,
);
}
আপনি সবেমাত্র যুক্ত হওয়া কোডটি প্রতি দশ সেকেন্ডে গুগল ক্লাউড থেকে পাব/সাব বিষয়ের সাথে যোগাযোগ করে এবং নতুন বার্তাগুলির জন্য জিজ্ঞাসা করে। তারপরে, _processMessage
পদ্ধতিতে প্রতিটি বার্তা প্রক্রিয়া করে।
এই পদ্ধতিটি আগত বার্তাগুলি ডিকোড করে এবং প্রতিটি ক্রয় সম্পর্কে আপডেট হওয়া তথ্য, উভয় সাবস্ক্রিপশন এবং নন-সাবস্ক্রিপশন সম্পর্কে বিদ্যমান handleSubscription
বা handleNonSubscription
প্রয়োজনে কল করে।
প্রতিটি বার্তা _askMessage
পদ্ধতিতে স্বীকৃত হওয়া দরকার।
এরপরে, server.dart
ফাইলে প্রয়োজনীয় নির্ভরতা যুক্ত করুন। শংসাপত্রগুলি কনফিগারেশনে পাবসুবাপি.ক্লাউডপ্ল্যাটফর্মস্কোপ যুক্ত করুন:
বিন/সার্ভার.ডার্ট
final clientGooglePlay =
await auth.clientViaServiceAccount(clientCredentialsGooglePlay, [
ap.AndroidPublisherApi.androidpublisherScope,
pubsub.PubsubApi.cloudPlatformScope, // new
]);
তারপরে, পাবসুবাপি উদাহরণ তৈরি করুন:
বিন/সার্ভার.ডার্ট
final pubsubApi = pubsub.PubsubApi(clientGooglePlay);
এবং শেষ অবধি, এটি GooglePlayPurchaseHandler
কনস্ট্রাক্টরকে পাস করুন:
বিন/সার্ভার.ডার্ট
return {
'google_play': GooglePlayPurchaseHandler(
androidPublisher,
iapRepository,
pubsubApi, // new
),
'app_store': AppStorePurchaseHandler(
iapRepository,
),
};
গুগল প্লে সেটআপ
আপনি পাব/সাব বিষয় থেকে বিলিং ইভেন্টগুলি গ্রাস করার জন্য কোডটি লিখেছেন, তবে আপনি পাব/সাব বিষয় তৈরি করেন নি, বা আপনি কোনও বিলিং ইভেন্ট প্রকাশ করছেন না। এটি সেট আপ করার সময়।
প্রথমত, একটি পাব/সাব বিষয় তৈরি করুন:
- গুগল ক্লাউড কনসোলে ক্লাউড পাব/সাব পৃষ্ঠাটি দেখুন।
- আপনি আপনার ফায়ারবেস প্রকল্পে রয়েছেন তা নিশ্চিত করুন এবং + ক্লিক করুন বিষয় ক্লিক করুন।
- নতুন বিষয়টিকে একটি নাম দিন,
GOOGLE_PLAY_PUBSUB_BILLING_TOPIC
জন্যconstants.ts
সেটটির মান সেট করুন। এই ক্ষেত্রে, এটিplay_billing
নাম দিন। আপনি যদি অন্য কিছু চয়ন করেন তবেconstants.ts
আপডেট করার বিষয়টি নিশ্চিত করুন। বিষয় তৈরি করুন। - আপনার পাব/উপ -বিষয়গুলির তালিকায়, আপনি সবেমাত্র তৈরি করা বিষয়টির জন্য তিনটি উল্লম্ব বিন্দুতে ক্লিক করুন এবং অনুমতিগুলি দেখুন ক্লিক করুন।
- ডানদিকে সাইডবারে, অধ্যক্ষ যুক্ত করুন চয়ন করুন।
- এখানে,
google-play-developer-notifications@system.gserviceaccount.com
যুক্ত করুন এবং এটিকে পাব/সাব প্রকাশকের ভূমিকা প্রদান করুন। - অনুমতি পরিবর্তন সংরক্ষণ করুন।
- আপনি সবেমাত্র তৈরি করা বিষয়টির বিষয়টির নামটি অনুলিপি করুন।
- আবার প্লে কনসোলটি খুলুন এবং সমস্ত অ্যাপ্লিকেশন তালিকা থেকে আপনার অ্যাপ্লিকেশনটি চয়ন করুন।
- নীচে স্ক্রোল করুন এবং নগদীকরণ> নগদীকরণ সেটআপে যান।
- সম্পূর্ণ বিষয় পূরণ করুন এবং আপনার পরিবর্তনগুলি সংরক্ষণ করুন।
সমস্ত গুগল প্লে বিলিং ইভেন্টগুলি এখন বিষয়টিতে প্রকাশিত হবে।
প্রক্রিয়া অ্যাপ স্টোর বিলিং ইভেন্টগুলি
এরপরে, অ্যাপ স্টোর বিলিং ইভেন্টগুলির জন্য একই করুন। অ্যাপ স্টোরের জন্য ক্রয়গুলিতে হ্যান্ডলিং আপডেটগুলি বাস্তবায়নের দুটি কার্যকর উপায় রয়েছে। একটি হ'ল আপনি অ্যাপলকে সরবরাহ করেন এমন একটি ওয়েবহুক প্রয়োগ করে এবং তারা আপনার সার্ভারের সাথে যোগাযোগের জন্য ব্যবহার করে। দ্বিতীয় উপায়, যা আপনি এই কোডেল্যাবটিতে পাবেন তা হ'ল অ্যাপ স্টোর সার্ভার এপিআইয়ের সাথে সংযোগ স্থাপন এবং ম্যানুয়ালি সাবস্ক্রিপশন তথ্য প্রাপ্তি।
এই কোডল্যাবটি দ্বিতীয় সমাধানের দিকে মনোনিবেশ করার কারণ হ'ল ওয়েবহুকটি বাস্তবায়নের জন্য আপনাকে আপনার সার্ভারটি ইন্টারনেটে প্রকাশ করতে হবে।
একটি উত্পাদন পরিবেশে, আদর্শভাবে আপনি উভয়ই থাকতে চান। অ্যাপ স্টোর থেকে ইভেন্টগুলি পেতে ওয়েবহুক এবং আপনি যদি কোনও ইভেন্ট মিস করেন বা সাবস্ক্রিপশনের স্থিতি ডাবল চেক করতে হবে তবে সার্ভার এপিআই।
lib/app_store_purchase_handler.dart
খোলার মাধ্যমে শুরু করুন এবং অ্যাপস্টোরস সার্ভারাপি নির্ভরতা যুক্ত করে:
lib/app_store_purchase_handler.dart
final AppStoreServerAPI appStoreServerAPI;
AppStorePurchaseHandler(
this.iapRepository,
this.appStoreServerAPI, // new
)
একটি টাইমার যুক্ত করতে কনস্ট্রাক্টরকে সংশোধন করুন যা _pullStatus
পদ্ধতিতে কল করবে। এই টাইমারটি প্রতি 10 সেকেন্ডে _ _pullStatus
পদ্ধতিতে কল করবে। আপনি এই টাইমার সময়কালটি আপনার প্রয়োজনের সাথে সামঞ্জস্য করতে পারেন।
lib/app_store_purchase_handler.dart
AppStorePurchaseHandler(
this.iapRepository,
this.appStoreServerAPI,
) {
// Poll Subscription status every 10 seconds.
Timer.periodic(Duration(seconds: 10), (_) {
_pullStatus();
});
}
তারপরে, নিম্নরূপ _Pullstatus পদ্ধতিটি তৈরি করুন:
lib/app_store_purchase_handler.dart
Future<void> _pullStatus() async {
print('Polling App Store');
final purchases = await iapRepository.getPurchases();
// filter for App Store subscriptions
final appStoreSubscriptions = purchases.where((element) =>
element.type == ProductType.subscription &&
element.iapSource == IAPSource.appstore);
for (final purchase in appStoreSubscriptions) {
final status =
await appStoreServerAPI.getAllSubscriptionStatuses(purchase.orderId);
// Obtain all subscriptions for the order id.
for (final subscription in status.data) {
// Last transaction contains the subscription status.
for (final transaction in subscription.lastTransactions) {
final expirationDate = DateTime.fromMillisecondsSinceEpoch(
transaction.transactionInfo.expiresDate ?? 0);
// Check if subscription has expired.
final isExpired = expirationDate.isBefore(DateTime.now());
print('Expiration Date: $expirationDate - isExpired: $isExpired');
// Update the subscription status with the new expiration date and status.
await iapRepository.updatePurchase(SubscriptionPurchase(
userId: null,
productId: transaction.transactionInfo.productId,
iapSource: IAPSource.appstore,
orderId: transaction.originalTransactionId,
purchaseDate: DateTime.fromMillisecondsSinceEpoch(
transaction.transactionInfo.originalPurchaseDate),
type: ProductType.subscription,
expiryDate: expirationDate,
status: isExpired
? SubscriptionStatus.expired
: SubscriptionStatus.active,
));
}
}
}
}
এই পদ্ধতিটি নিম্নরূপ কাজ করে:
- আইএপ্রেসিটরি ব্যবহার করে ফায়ারস্টোর থেকে সক্রিয় সাবস্ক্রিপশনগুলির তালিকা অর্জন করে।
- প্রতিটি ক্রমের জন্য, এটি অ্যাপ স্টোর সার্ভার এপিআইতে সাবস্ক্রিপশন স্থিতি অনুরোধ করে।
- সেই সাবস্ক্রিপশন ক্রয়ের জন্য শেষ লেনদেনটি গ্রহণ করে।
- মেয়াদ শেষ হওয়ার তারিখ পরীক্ষা করে।
- ফায়ারস্টোরে সাবস্ক্রিপশন স্থিতি আপডেট করে, যদি এটি মেয়াদোত্তীর্ণ হয় তবে এটি চিহ্নিত করা হবে।
অবশেষে, অ্যাপ স্টোর সার্ভার এপিআই অ্যাক্সেস কনফিগার করতে সমস্ত প্রয়োজনীয় কোড যুক্ত করুন:
বিন/সার্ভার.ডার্ট
// add from here
final subscriptionKeyAppStore =
File('assets/SubscriptionKey.p8').readAsStringSync();
// Configure Apple Store API access
var appStoreEnvironment = AppStoreEnvironment.sandbox(
bundleId: bundleId,
issuerId: appStoreIssuerId,
keyId: appStoreKeyId,
privateKey: subscriptionKeyAppStore,
);
// Stored token for Apple Store API access, if available
final file = File('assets/appstore.token');
String? appStoreToken;
if (file.existsSync() && file.lengthSync() > 0) {
appStoreToken = file.readAsStringSync();
}
final appStoreServerAPI = AppStoreServerAPI(
AppStoreServerHttpClient(
appStoreEnvironment,
jwt: appStoreToken,
jwtTokenUpdatedCallback: (token) {
file.writeAsStringSync(token);
},
),
);
// to here
return {
'google_play': GooglePlayPurchaseHandler(
androidPublisher,
iapRepository,
pubsubApi,
),
'app_store': AppStorePurchaseHandler(
iapRepository,
appStoreServerAPI, // new
),
};
অ্যাপ স্টোর সেটআপ
এরপরে, অ্যাপ স্টোর সেট আপ করুন:
- অ্যাপ স্টোর সংযোগে লগ ইন করুন এবং ব্যবহারকারীদের নির্বাচন করুন এবং অ্যাক্সেস করুন ।
- কী টাইপ> ইন-অ্যাপ্লিকেশন ক্রয়ে যান।
- একটি নতুন যুক্ত করতে "প্লাস" আইকনে আলতো চাপুন।
- এটি একটি নাম দিন, যেমন "কোডেল্যাব কী"।
- কীযুক্ত পি 8 ফাইলটি ডাউনলোড করুন।
-
SubscriptionKey.p8
নাম সহ এটি সম্পদ ফোল্ডারে অনুলিপি করুন। - সদ্য নির্মিত কী থেকে কী আইডিটি অনুলিপি করুন এবং এটি
lib/constants.dart
ফাইলেappStoreKeyId
ধ্রুবকটিতে সেট করুন। - কী তালিকার শীর্ষে ইস্যুকারী আইডিটি অনুলিপি করুন এবং এটি
lib/constants.dart
ফাইলটিতেappStoreIssuerId
ধ্রুবকটিতে সেট করুন।
ডিভাইসে ক্রয় ট্র্যাক করুন
আপনার ক্রয়গুলি ট্র্যাক করার সর্বাধিক সুরক্ষিত উপায়টি সার্ভার সাইডে রয়েছে কারণ ক্লায়েন্টটি সুরক্ষিত করা শক্ত, তবে আপনার কাছে ক্লায়েন্টের কাছে তথ্য ফিরে পাওয়ার জন্য কিছু উপায় থাকতে হবে যাতে অ্যাপ্লিকেশনটি সাবস্ক্রিপশন স্থিতির তথ্যে কাজ করতে পারে। ফায়ারস্টোরে ক্রয়গুলি সংরক্ষণ করে আপনি সহজেই ক্লায়েন্টের সাথে ডেটা সিঙ্ক করতে পারেন এবং এটি স্বয়ংক্রিয়ভাবে আপডেট রাখতে পারেন।
আপনি ইতিমধ্যে অ্যাপটিতে আইপ্রেপো অন্তর্ভুক্ত করেছেন, এটি ফায়ারস্টোর রিপোজিটরি যা ব্যবহারকারীর সমস্ত ক্রয়ের ডেটা List<PastPurchase> purchases
সমস্ত ক্রয়ের ডেটা ধারণ করে। সংগ্রহস্থলেও hasActiveSubscription,
যা সত্য যখন কোনও স্ট্যাটাস সহ productId storeKeySubscription
সহ একটি ক্রয় হয় যা মেয়াদ শেষ হয় না। যখন ব্যবহারকারী লগ ইন না করে, তালিকাটি খালি থাকে।
lib/repo/iap_repo.dart
void updatePurchases() {
_purchaseSubscription?.cancel();
var user = _user;
if (user == null) {
purchases = [];
hasActiveSubscription = false;
hasUpgrade = false;
return;
}
var purchaseStream = _firestore
.collection('purchases')
.where('userId', isEqualTo: user.uid)
.snapshots();
_purchaseSubscription = purchaseStream.listen((snapshot) {
purchases = snapshot.docs.map((DocumentSnapshot document) {
var data = document.data();
return PastPurchase.fromJson(data);
}).toList();
hasActiveSubscription = purchases.any((element) =>
element.productId == storeKeySubscription &&
element.status != Status.expired);
hasUpgrade = purchases.any(
(element) => element.productId == storeKeyUpgrade,
);
notifyListeners();
});
}
সমস্ত ক্রয়ের যুক্তি DashPurchases
ক্লাসে রয়েছে এবং যেখানে সাবস্ক্রিপশনগুলি প্রয়োগ বা অপসারণ করা উচিত। সুতরাং, ক্লাসে সম্পত্তি হিসাবে iapRepo
যুক্ত করুন এবং কনস্ট্রাক্টরে iapRepo
বরাদ্দ করুন। এরপরে, সরাসরি কনস্ট্রাক্টারে শ্রোতা যুক্ত করুন এবং শ্রোতাকে dispose()
পদ্ধতিতে সরিয়ে দিন। প্রথমদিকে, শ্রোতা কেবল একটি খালি ফাংশন হতে পারে। যেহেতু IAPRepo
একটি ChangeNotifier
এবং আপনি যখন ফায়ারস্টোর পরিবর্তনের ক্ষেত্রে ক্রয়গুলি প্রতিবার notifyListeners()
কল করেন, ক্রয়কৃত পণ্যগুলি পরিবর্তিত হলে purchasesUpdate()
পদ্ধতিটি সর্বদা কল করা হয়।
lib/লজিক/ড্যাশ_প্রেসেস.ডার্ট
IAPRepo iapRepo;
DashPurchases(this.counter, this.firebaseNotifier, this.iapRepo) {
final purchaseUpdated =
iapConnection.purchaseStream;
_subscription = purchaseUpdated.listen(
_onPurchaseUpdate,
onDone: _updateStreamOnDone,
onError: _updateStreamOnError,
);
iapRepo.addListener(purchasesUpdate);
loadPurchases();
}
@override
void dispose() {
iapRepo.removeListener(purchasesUpdate);
_subscription.cancel();
super.dispose();
}
void purchasesUpdate() {
//TODO manage updates
}
এরপরে, main.dart.
কনস্ট্রাক্টরকে IAPRepo
সরবরাহ করুন। আপনি context.read
ব্যবহার করে সংগ্রহস্থলটি পেতে পারেন Read পড়ুন কারণ এটি ইতিমধ্যে কোনও Provider
মধ্যে তৈরি হয়েছে।
lib/main.dart
ChangeNotifierProvider<DashPurchases>(
create: (context) => DashPurchases(
context.read<DashCounter>(),
context.read<FirebaseNotifier>(),
context.read<IAPRepo>(),
),
lazy: false,
),
এরপরে, purchaseUpdate()
ফাংশনের জন্য কোডটি লিখুন। dash_counter.dart,
applyPaidMultiplier
এবং removePaidMultiplier
পদ্ধতিগুলি যথাক্রমে 10 বা 1 এ গুণক সেট করে, সুতরাং আপনাকে সাবস্ক্রিপশনটি ইতিমধ্যে প্রয়োগ করা হয়েছে কিনা তা পরীক্ষা করতে হবে না। যখন সাবস্ক্রিপশনের স্থিতি পরিবর্তন হয়, আপনি ক্রয়যোগ্য পণ্যের স্থিতিও আপডেট করেন যাতে আপনি ক্রয় পৃষ্ঠায় এটি ইতিমধ্যে সক্রিয় রয়েছে তা দেখাতে পারেন। আপগ্রেড কেনা হয় কিনা তার উপর ভিত্তি করে _beautifiedDashUpgrade
সম্পত্তি সেট করুন।
lib/লজিক/ড্যাশ_প্রেসেস.ডার্ট
void purchasesUpdate() {
var subscriptions = <PurchasableProduct>[];
var upgrades = <PurchasableProduct>[];
// Get a list of purchasable products for the subscription and upgrade.
// This should be 1 per type.
if (products.isNotEmpty) {
subscriptions = products
.where((element) => element.productDetails.id == storeKeySubscription)
.toList();
upgrades = products
.where((element) => element.productDetails.id == storeKeyUpgrade)
.toList();
}
// Set the subscription in the counter logic and show/hide purchased on the
// purchases page.
if (iapRepo.hasActiveSubscription) {
counter.applyPaidMultiplier();
for (var element in subscriptions) {
_updateStatus(element, ProductStatus.purchased);
}
} else {
counter.removePaidMultiplier();
for (var element in subscriptions) {
_updateStatus(element, ProductStatus.purchasable);
}
}
// Set the Dash beautifier and show/hide purchased on
// the purchases page.
if (iapRepo.hasUpgrade != _beautifiedDashUpgrade) {
_beautifiedDashUpgrade = iapRepo.hasUpgrade;
for (var element in upgrades) {
_updateStatus(
element,
_beautifiedDashUpgrade
? ProductStatus.purchased
: ProductStatus.purchasable);
}
notifyListeners();
}
}
void _updateStatus(PurchasableProduct product, ProductStatus status) {
if (product.status != ProductStatus.purchased) {
product.status = ProductStatus.purchased;
notifyListeners();
}
}
আপনি এখন নিশ্চিত করেছেন যে সাবস্ক্রিপশন এবং আপগ্রেডের স্থিতি সর্বদা ব্যাকএন্ড পরিষেবাতে বর্তমান এবং অ্যাপ্লিকেশনটির সাথে সিঙ্ক্রোনাইজড। অ্যাপটি সেই অনুযায়ী কাজ করে এবং আপনার ড্যাশ ক্লিকার গেমটিতে সাবস্ক্রিপশন এবং আপগ্রেড বৈশিষ্ট্যগুলি প্রয়োগ করে।
12. সব শেষ!
অভিনন্দন!!! আপনি কোডেল্যাব শেষ করেছেন। আপনি এই কোডল্যাবের জন্য সম্পূর্ণ কোড খুঁজে পেতে পারেন সম্পূর্ণ ফোল্ডার।
আরও জানতে, অন্যান্য ফ্লাটার কোডল্যাবগুলি চেষ্টা করে দেখুন।