আপনার অ্যান্ড্রয়েড অ্যাপে Google এর মাধ্যমে সাইন ইন কীভাবে প্রয়োগ করবেন তা জানুন

1. আপনি শুরু করার আগে

এই কোডল্যাবে আপনি শিখবেন কিভাবে ক্রেডেনশিয়াল ম্যানেজার ব্যবহার করে Android-এ Google-এর সাথে সাইন ইন করতে হয়।

পূর্বশর্ত

  • অ্যান্ড্রয়েড বিকাশের জন্য কোটলিন ব্যবহার করার প্রাথমিক ধারণা
  • জেটপ্যাক রচনার প্রাথমিক ধারণা (আরো তথ্য এখানে পাওয়া যাবে)

আপনি কি শিখবেন

  • কিভাবে একটি গুগল ক্লাউড প্রজেক্ট তৈরি করবেন
  • গুগল ক্লাউড কনসোলে কীভাবে OAuth ক্লায়েন্ট তৈরি করবেন
  • বটম শিট ফ্লো ব্যবহার করে কিভাবে Google এর মাধ্যমে সাইন ইন বাস্তবায়ন করবেন
  • কিভাবে বাটন ফ্লো ব্যবহার করে Google এর মাধ্যমে সাইন ইন বাস্তবায়ন করবেন

আপনার যা প্রয়োজন

2. একটি অ্যান্ড্রয়েড স্টুডিও প্রকল্প তৈরি করুন৷

সময়কাল 3:00 - 5:00

শুরু করার জন্য, আমাদের অ্যান্ড্রয়েড স্টুডিওতে একটি নতুন প্রকল্প তৈরি করতে হবে:

  1. অ্যান্ড্রয়েড স্টুডিও খুলুন
  2. নতুন প্রকল্প ক্লিক করুন অ্যান্ড্রয়েড স্টুডিও স্বাগতম
  3. ফোন এবং ট্যাবলেট এবং খালি কার্যকলাপ নির্বাচন করুন অ্যান্ড্রয়েড স্টুডিও প্রকল্প
  4. Next ক্লিক করুন
  5. এখন এই প্রকল্পের কয়েকটি টুকরা সেট আপ করার সময়:
    • নাম : এটি আপনার প্রকল্পের নাম
    • প্যাকেজের নাম : এটি আপনার প্রকল্পের নামের উপর ভিত্তি করে স্বয়ংক্রিয়ভাবে জনবহুল হবে
    • অবস্থান সংরক্ষণ করুন : এটি সেই ফোল্ডারে ডিফল্ট হওয়া উচিত যেখানে Android স্টুডিও আপনার প্রকল্পগুলি সংরক্ষণ করে৷ আপনি এটিকে যেখানে চান সেখানে পরিবর্তন করতে পারেন৷
    • ন্যূনতম SDK : এটি Android SDK-এর সর্বনিম্ন সংস্করণ যা আপনার অ্যাপটি চালানোর জন্য তৈরি করা হয়েছে৷ এই কোডল্যাবে, আমরা API 36 (বাকলাভা) ব্যবহার করব
    অ্যান্ড্রয়েড স্টুডিও সেটআপ প্রকল্প
  6. Finish এ ক্লিক করুন
  7. অ্যান্ড্রয়েড স্টুডিও প্রকল্পটি তৈরি করবে এবং বেস অ্যাপ্লিকেশনের জন্য প্রয়োজনীয় কোনো নির্ভরতা ডাউনলোড করবে, এতে কয়েক মিনিট সময় লাগতে পারে। এটি ঘটতে দেখতে, শুধু বিল্ড আইকনে ক্লিক করুন: অ্যান্ড্রয়েড স্টুডিও প্রজেক্ট বিল্ডিং
  8. একবার এটি সম্পূর্ণ হয়ে গেলে, অ্যান্ড্রয়েড স্টুডিও এর মতো দেখতে হবে: অ্যান্ড্রয়েড স্টুডিও প্রকল্প নির্মিত

3. আপনার Google ক্লাউড প্রকল্প সেট আপ করুন৷

একটি Google ক্লাউড প্রকল্প তৈরি করুন

  1. গুগল ক্লাউড কনসোলে যান
  2. আপনার প্রকল্প খুলুন বা একটি নতুন প্রকল্প তৈরি করুন GCP নতুন প্রকল্প তৈরি করুনGCP নতুন প্রকল্প তৈরি করুন 2GCP নতুন প্রকল্প তৈরি করুন 3
  3. APIs এবং পরিষেবাগুলিতে ক্লিক করুনGCP API এবং পরিষেবা
  4. OAuth সম্মতি স্ক্রিনে যান GCP OAuth সম্মতি স্ক্রীন
  5. চালিয়ে যেতে আপনাকে ওভারভিউতে ক্ষেত্রগুলি পূরণ করতে হবে। এই তথ্যটি পূরণ করতে শুরু করুন ক্লিক করুন:GCP Get Start বাটন
    • অ্যাপের নাম : এই অ্যাপটির নাম, যা আপনি অ্যান্ড্রয়েড স্টুডিওতে প্রজেক্ট তৈরি করার সময় ব্যবহার করেছেন তার মতোই হওয়া উচিত
    • ইউজার সাপোর্ট ইমেল : এটি আপনার লগইন করা Google অ্যাকাউন্ট এবং আপনার পরিচালনা করা যেকোনো Google গ্রুপ দেখাবে
    GCP অ্যাপ তথ্য
    • শ্রোতা :
      • শুধুমাত্র আপনার প্রতিষ্ঠানের মধ্যে ব্যবহৃত একটি অ্যাপের জন্য অভ্যন্তরীণ। আপনার যদি Google ক্লাউড প্রকল্পের সাথে যুক্ত কোনো সংস্থা না থাকে তাহলে আপনি এটি নির্বাচন করতে পারবেন না।
      • আমরা যা ব্যবহার করছি তা বহিরাগত হবে।
    GCP দর্শক
    • যোগাযোগের তথ্য : এটিতে এমন কোনও ইমেল থাকতে পারে যা আপনি অ্যাপ্লিকেশনটির জন্য যোগাযোগের বিন্দু হতে চান
    GCP যোগাযোগের তথ্য
    • Google API পরিষেবাগুলি পর্যালোচনা করুন: ব্যবহারকারীর ডেটা নীতি৷
  6. একবার আপনি পর্যালোচনা করে এবং ব্যবহারকারীর ডেটা নীতিতে সম্মত হলে, তৈরি করুন ক্লিক করুন৷GCP তৈরি করুন

OAuth ক্লায়েন্ট সেট আপ করুন

এখন যেহেতু আমাদের একটি Google ক্লাউড প্রজেক্ট সেট আপ করা আছে, আমাদের একটি ওয়েব ক্লায়েন্ট এবং অ্যান্ড্রয়েড ক্লায়েন্ট যোগ করতে হবে যাতে আমরা তাদের ক্লায়েন্ট আইডিগুলির সাথে OAuth ব্যাকএন্ড সার্ভারে API কল করতে পারি৷

অ্যান্ড্রয়েড ওয়েব ক্লায়েন্টের জন্য, আপনার প্রয়োজন হবে:

  • আপনার অ্যাপের প্যাকেজের নাম (যেমন com.example.example)
  • আপনার অ্যাপের SHA-1 স্বাক্ষর
    • একটি SHA-1 স্বাক্ষর কি?
      • SHA-1 ফিঙ্গারপ্রিন্ট হল একটি ক্রিপ্টোগ্রাফিক হ্যাশ যা আপনার অ্যাপের সাইনিং কী থেকে তৈরি হয়। এটি আপনার নির্দিষ্ট অ্যাপের সাইনিং শংসাপত্রের জন্য একটি অনন্য শনাক্তকারী হিসাবে সত্য। এটিকে আপনার অ্যাপের জন্য একটি ডিজিটাল "স্বাক্ষর" এর মত মনে করুন।
    • কেন আমাদের SHA-1 স্বাক্ষর প্রয়োজন?
      • SHA-1 ফিঙ্গারপ্রিন্ট নিশ্চিত করে যে শুধুমাত্র আপনার অ্যাপ, আপনার নির্দিষ্ট সাইনিং কী দিয়ে সাইন করা হয়েছে, আপনার OAuth 2.0 ক্লায়েন্ট আইডি ব্যবহার করে অ্যাক্সেস টোকেনগুলির অনুরোধ করতে পারে, অন্য অ্যাপগুলিকে (এমনকি একই প্যাকেজ নামেরও) আপনার প্রকল্পের সংস্থান এবং ব্যবহারকারীর ডেটা অ্যাক্সেস করতে বাধা দেয়৷
      • এটিকে এভাবে ভাবুন:
        • আপনার অ্যাপের সাইনিং কী আপনার অ্যাপের "দরজা" এর ফিজিক্যাল চাবির মতো। এটি অ্যাপের অভ্যন্তরীণ কাজগুলিতে অ্যাক্সেসের অনুমতি দেয়।
        • SHA-1 ফিঙ্গারপ্রিন্ট হল একটি অনন্য কীকার্ড আইডির মতো যা আপনার ফিজিক্যাল কী-এর সাথে লিঙ্ক করা আছে। এটি একটি নির্দিষ্ট কোড যা সেই নির্দিষ্ট কীটিকে সনাক্ত করে।
        • OAuth 2.0 ক্লায়েন্ট আইডি একটি নির্দিষ্ট Google সংস্থান বা পরিষেবার (যেমন Google সাইন-ইন) এন্ট্রি কোডের মতো।
        • OAuth ক্লায়েন্ট সেটআপের সময় আপনি যখন SHA-1 ফিঙ্গারপ্রিন্ট প্রদান করেন, তখন আপনি মূলত Google কে বলছেন: "শুধুমাত্র এই নির্দিষ্ট আইডি (SHA-1) সহ কীকার্ডটি এই অ্যাক্সেস কোড (ক্লায়েন্ট আইডি) খুলতে পারে।" এটি নিশ্চিত করে যে শুধুমাত্র আপনার অ্যাপ সেই এন্ট্রি কোডের সাথে লিঙ্ক করা Google পরিষেবাগুলি অ্যাক্সেস করতে পারে।"

ওয়েব ক্লায়েন্টের জন্য, আমাদের শুধু সেই নামটি প্রয়োজন যা আপনি কনসোলে ক্লায়েন্ট সনাক্ত করার জন্য ব্যবহার করতে চান।

Android OAuth 2.0 ক্লায়েন্ট তৈরি করুন

  1. ক্লায়েন্ট পৃষ্ঠায় যানGCP ক্লায়েন্ট
  2. ক্লায়েন্ট তৈরি করুন ক্লিক করুন GCP ক্লায়েন্ট তৈরি করুন
  3. অ্যাপ্লিকেশন ধরনের জন্য Android নির্বাচন করুন
  4. আপনাকে আপনার অ্যাপের প্যাকেজের নাম উল্লেখ করতে হবে
  5. অ্যান্ড্রয়েড স্টুডিও থেকে আমাদের অ্যাপের SHA-1 স্বাক্ষর পেতে হবে এবং এটি এখানে কপি/পেস্ট করতে হবে:
    1. অ্যান্ড্রয়েড স্টুডিওতে যান এবং টার্মিনাল খুলুন
    2. এই কমান্ডটি চালান:
      keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
      
      এই কমান্ডটি একটি কীস্টোরের মধ্যে একটি নির্দিষ্ট এন্ট্রির (উনাম) বিবরণ তালিকাভুক্ত করার জন্য ডিজাইন করা হয়েছে।
      • -list : এই বিকল্পটি কীস্টোরের বিষয়বস্তু তালিকাভুক্ত করতে কী-টুলকে বলে।
      • -v : এই বিকল্পটি ভার্বোজ আউটপুট সক্ষম করে, এন্ট্রি সম্পর্কে আরও বিস্তারিত তথ্য প্রদান করে।
      • -keystore ~/.android/debug.keystore : এটি কীস্টোর ফাইলের পথ নির্দিষ্ট করে।
      • -alias androiddebugkey : আপনি যে কী পরিদর্শন করতে চান সেটির উপনাম (প্রবেশের নাম) এটি নির্দিষ্ট করে।
      • -storepass android : এটি কীস্টোর ফাইলের জন্য পাসওয়ার্ড প্রদান করে।
      • -keypass android : এটি নির্দিষ্ট উপনামের ব্যক্তিগত কী-এর জন্য পাসওয়ার্ড প্রদান করে।
    3. SHA-1 স্বাক্ষরের মান অনুলিপি করুন:
    SHA স্বাক্ষর
    1. Google ক্লাউড উইন্ডোতে ফিরে যান এবং SHA-1 স্বাক্ষর মান পেস্ট করুন:
  6. আপনার স্ক্রীনটি এখন এর অনুরূপ হওয়া উচিত এবং আপনি তৈরি করুন ক্লিক করতে পারেন: অ্যান্ড্রয়েড ক্লায়েন্টের বিবরণঅ্যান্ড্রয়েড ক্লায়েন্ট

ওয়েব OAuth 2.0 ক্লায়েন্ট তৈরি করুন

  1. একটি ওয়েব অ্যাপ্লিকেশন ক্লায়েন্ট আইডি তৈরি করতে, অ্যান্ড্রয়েড ক্লায়েন্ট তৈরি করুন বিভাগ থেকে ধাপ 1-2 পুনরাবৃত্তি করুন এবং অ্যাপ্লিকেশন প্রকারের জন্য ওয়েব অ্যাপ্লিকেশন নির্বাচন করুন
  2. ক্লায়েন্টকে একটি নাম দিন (এটি OAuth ক্লায়েন্ট হবে):ওয়েব ক্লায়েন্ট বিবরণ
  3. তৈরি করুন ক্লিক করুনওয়েব ক্লায়েন্ট
  4. এগিয়ে যান এবং পপআপ উইন্ডো থেকে ক্লায়েন্ট আইডি কপি করুন, আপনার এটি পরে প্রয়োজন হবে ক্লায়েন্ট আইডি কপি করুন

এখন যেহেতু আমাদের OAuth ক্লায়েন্ট সব সেট আপ হয়ে গেছে, আমরা Android স্টুডিওতে ফিরে যেতে পারি Google Android অ্যাপ দিয়ে সাইন ইন করুন!

4. অ্যান্ড্রয়েড ভার্চুয়াল ডিভাইস সেট আপ করুন

কোনও শারীরিক অ্যান্ড্রয়েড ডিভাইস ছাড়াই আপনার অ্যাপ্লিকেশনের দ্রুত পরীক্ষার জন্য, আপনি একটি অ্যান্ড্রয়েড ভার্চুয়াল ডিভাইস তৈরি করতে চাইবেন যা আপনি অ্যান্ড্রয়েড স্টুডিও থেকে আপনার অ্যাপ তৈরি করতে এবং অবিলম্বে চালাতে পারেন। আপনি যদি একটি শারীরিক অ্যান্ড্রয়েড ডিভাইসের সাথে পরীক্ষা করতে চান তবে আপনি Android বিকাশকারী ডকুমেন্টেশন থেকে নির্দেশাবলী অনুসরণ করতে পারেন

একটি অ্যান্ড্রয়েড ভার্চুয়াল ডিভাইস তৈরি করুন

  1. অ্যান্ড্রয়েড স্টুডিওতে, ডিভাইস ম্যানেজার খুলুন ডিভাইস ম্যানেজার
  2. + বোতামে ক্লিক করুন > ভার্চুয়াল ডিভাইস তৈরি করুন ভার্চুয়াল ডিভাইস তৈরি করুন
  3. এখান থেকে আপনি আপনার প্রজেক্টের জন্য প্রয়োজনীয় যেকোন ডিভাইস যোগ করতে পারেন। এই কোডল্যাবের উদ্দেশ্যে, মিডিয়াম ফোন নির্বাচন করুন তারপর পরবর্তী ক্লিক করুনমাঝারি ফোন
  4. এখন আপনি আপনার প্রোজেক্টের জন্য ডিভাইসটিকে একটি অনন্য নাম দিয়ে কনফিগার করতে পারেন, Android এর যে সংস্করণটি চলবে সেটি বেছে নিয়ে এবং আরও অনেক কিছু। নিশ্চিত করুন যে API API 36 "Baklava" এ সেট করা আছে; Android 16 তারপর Finish এ ক্লিক করুন ভার্চুয়াল ডিভাইস কনফিগার করুন
  5. আপনার ডিভাইস ম্যানেজারে নতুন ডিভাইসটি প্রদর্শিত হওয়া উচিত। ডিভাইস চলছে কিনা তা যাচাই করতে, এগিয়ে যান এবং ক্লিক করুনডিভাইস চালান আপনার তৈরি করা ডিভাইসের পাশেডিভাইস 2 চালান
  6. ডিভাইস এখন চলমান করা উচিত! চলমান ডিভাইস

অ্যান্ড্রয়েড ভার্চুয়াল ডিভাইসে সাইন ইন করুন

আপনি এইমাত্র যে ডিভাইসটি তৈরি করেছেন সেটি কাজ করে, এখন Google এর মাধ্যমে সাইন ইন করার পরীক্ষা করার সময় ত্রুটি প্রতিরোধ করতে আমাদের একটি Google অ্যাকাউন্ট দিয়ে ডিভাইসে সাইন ইন করতে হবে৷

  1. সেটিংসে যান:
    1. ভার্চুয়াল ডিভাইসে স্ক্রিনের কেন্দ্রে ক্লিক করুন এবং উপরে সোয়াইপ করুন
    ক্লিক করুন এবং সোয়াইপ করুন
    1. সেটিংস অ্যাপটি দেখুন এবং এটিতে ক্লিক করুন
    সেটিংস অ্যাপ
  2. সেটিংসে Google- এ ক্লিক করুন Google পরিষেবা এবং পছন্দগুলি৷
  3. সাইন ইন ক্লিক করুন এবং আপনার Google অ্যাকাউন্টে সাইন ইন করতে প্রম্পটগুলি অনুসরণ করুন৷ ডিভাইস সাইন ইন
  1. আপনার এখন ডিভাইসে সাইন ইন করা উচিতডিভাইস সাইন ইন

আপনার ভার্চুয়াল অ্যান্ড্রয়েড ডিভাইস এখন পরীক্ষার জন্য প্রস্তুত!

5. নির্ভরতা যোগ করুন

সময়কাল 5:00

OAuth API কল করার জন্য, আমাদের প্রথমে প্রয়োজনীয় লাইব্রেরিগুলিকে সংহত করতে হবে যা আমাদের প্রমাণীকরণের অনুরোধ করতে এবং সেই অনুরোধগুলি করার জন্য Google ID ব্যবহার করতে দেয়:

  • libs.googleid
  • libs.play.services.auth
  1. ফাইল > প্রকল্প কাঠামোতে যান:প্রকল্পের কাঠামো
  2. তারপর Dependencies > app > '+' > Library Dependency- এ যাননির্ভরতা
  3. এখন আমাদের লাইব্রেরি যোগ করতে হবে:
    1. অনুসন্ধান ডায়ালগে, googleid টাইপ করুন এবং অনুসন্ধানে ক্লিক করুন
    2. শুধুমাত্র একটি এন্ট্রি থাকা উচিত, এগিয়ে যান এবং এটি নির্বাচন করুন এবং উপলব্ধ সর্বোচ্চ সংস্করণ (এই কোডল্যাব itis 1.1.1 এর সময়ে)
    3. ওকে ক্লিক করুন গুগল আইডি প্যাকেজ
    4. ধাপ 1-3 পুনরাবৃত্তি করুন কিন্তু "play-services-auth" এর পরিবর্তে অনুসন্ধান করুন এবং গ্রুপ আইডি হিসাবে "com.google.android.gms" এবং আর্টিফ্যাক্ট নাম হিসাবে "play-services-auth" সহ লাইনটি নির্বাচন করুন প্লে পরিষেবা প্রমাণীকরণ
  4. ওকে ক্লিক করুন সমাপ্ত নির্ভরতা

6. নীচের শীট প্রবাহ

নীচে শীট প্রবাহ

ব্যবহারকারীদের Android এ তাদের Google অ্যাকাউন্ট ব্যবহার করে আপনার অ্যাপে সাইন ইন করার জন্য একটি সুবিন্যস্ত উপায়ের জন্য নীচের শীট ফ্লো ক্রেডেনশিয়াল ম্যানেজার API-এর সুবিধা দেয়৷ এটি দ্রুত এবং সুবিধাজনক হতে ডিজাইন করা হয়েছে, বিশেষ করে ফিরে আসা ব্যবহারকারীদের জন্য। এই প্রবাহটি অ্যাপ লঞ্চের সময় ট্রিগার করা উচিত।

সাইন-ইন অনুরোধ তৈরি করুন

  1. শুরু করতে, এগিয়ে যান এবং MainActivity.kt থেকে Greeting() এবং GreetingPreview() ফাংশনগুলি সরিয়ে ফেলুন, আমাদের সেগুলির প্রয়োজন হবে না৷
  2. এখন আমাদের নিশ্চিত করতে হবে যে আমাদের প্রয়োজনীয় প্যাকেজগুলি এই প্রকল্পের জন্য আমদানি করা হয়েছে। এগিয়ে যান এবং লাইন 3 থেকে শুরু হওয়া বিদ্যমানগুলির পরে নিম্নলিখিত import বিবৃতি যোগ করুন:
    import android.content.ContentValues.TAG
    import android.content.Context
    import android.credentials.GetCredentialException
    import android.os.Build
    import android.util.Log
    import android.widget.Toast
    import androidx.annotation.RequiresApi
    import androidx.compose.foundation.clickable
    import androidx.compose.foundation.Image
    import androidx.compose.foundation.layout.Arrangement
    import androidx.compose.foundation.layout.Column
    import androidx.compose.material3.MaterialTheme
    import androidx.compose.material3.Surface
    import androidx.compose.runtime.rememberCoroutineScope
    import androidx.compose.ui.Alignment
    import androidx.compose.ui.platform.LocalContext
    import androidx.compose.ui.res.painterResource
    import androidx.credentials.CredentialManager
    import androidx.credentials.exceptions.GetCredentialCancellationException
    import androidx.credentials.exceptions.GetCredentialCustomException
    import androidx.credentials.exceptions.NoCredentialException
    import androidx.credentials.GetCredentialRequest
    import com.google.android.libraries.identity.googleid.GetGoogleIdOption
    import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption
    import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
    import java.security.SecureRandom
    import java.util.Base64
    import kotlinx.coroutines.CoroutineScope
    import androidx.compose.runtime.LaunchedEffect
    import kotlinx.coroutines.delay
    import kotlinx.coroutines.launch
    
  3. এর পরে, নীচের শীট অনুরোধ তৈরি করার জন্য আমাদের ফাংশন তৈরি করতে হবে। MainActivity ক্লাসের নিচে এই কোডটি পেস্ট করুন
   //This line is not needed for the project to build, but you will see errors if it is not present.
   //This code will not work on Android versions < UpsideDownCake
   @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
   @Composable
    fun BottomSheet(webClientId: String) {
        val context = LocalContext.current

        // LaunchedEffect is used to run a suspend function when the composable is first launched.
        LaunchedEffect(Unit) {
            // Create a Google ID option with filtering by authorized accounts enabled.
            val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
                .setFilterByAuthorizedAccounts(true)
                .setServerClientId(webClientId)
                .setNonce(generateSecureRandomNonce())
                .build()

            // Create a credential request with the Google ID option.
            val request: GetCredentialRequest = GetCredentialRequest.Builder()
                .addCredentialOption(googleIdOption)
                .build()

            // Attempt to sign in with the created request using an authorized account
            val e = signIn(request, context)
            // If the sign-in fails with NoCredentialException,  there are no authorized accounts.
            // In this case, we attempt to sign in again with filtering disabled.
            if (e is NoCredentialException) {
                val googleIdOptionFalse: GetGoogleIdOption = GetGoogleIdOption.Builder()
                    .setFilterByAuthorizedAccounts(false)
                    .setServerClientId(webClientId)
                    .setNonce(generateSecureRandomNonce())
                    .build()

                val requestFalse: GetCredentialRequest = GetCredentialRequest.Builder()
                    .addCredentialOption(googleIdOptionFalse)
                    .build()
                    
                //We will build out this function in a moment
                signIn(requestFalse, context)
            }
        }
    }

   //This function is used to generate a secure nonce to pass in with our request
   fun generateSecureRandomNonce(byteLength: Int = 32): String {
      val randomBytes = ByteArray(byteLength)
      SecureRandom.getInstanceStrong().nextBytes(randomBytes)
      return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes)
   }

এই কোডটি কী করছে তা ভাঙ্গুন:

fun BottomSheet(webClientId: String) {...} : BottomSheet নামে একটি ফাংশন তৈরি করে যা একটি স্ট্রিং আর্গুমেন্ট নেয় যার নাম webClientid

  • val context = LocalContext.current : বর্তমান অ্যান্ড্রয়েড প্রসঙ্গ পুনরুদ্ধার করে। UI উপাদান চালু করা সহ বিভিন্ন ক্রিয়াকলাপের জন্য এটি প্রয়োজন।
  • LaunchedEffect(Unit) { ... } : LaunchedEffect হল একটি জেটপ্যাক কম্পোজ কম্পোজযোগ্য যা আপনাকে কম্পোজেবলের জীবনচক্রের মধ্যে একটি সাসপেন্ড ফাংশন (একটি ফাংশন যা পজ এবং এক্সিকিউশন পুনরায় শুরু করতে পারে) চালানোর অনুমতি দেয়। কী হিসাবে ইউনিটের অর্থ হল এই প্রভাবটি শুধুমাত্র একবারই চলবে যখন কম্পোজেবলটি প্রথম চালু করা হবে।
    • val googleIdOption: GetGoogleIdOption = ... : একটি GetGoogleIdOption অবজেক্ট তৈরি করে। এই বস্তুটি Google থেকে অনুরোধ করা শংসাপত্রের ধরন কনফিগার করে৷
      • .Builder() : একটি বিল্ডার প্যাটার্ন বিকল্পগুলি কনফিগার করতে ব্যবহৃত হয়।
      • .setFilterByAuthorizedAccounts(true) : ব্যবহারকারীকে সমস্ত Google অ্যাকাউন্ট থেকে নির্বাচন করার অনুমতি দেবে, নাকি যেগুলি ইতিমধ্যেই অ্যাপটিকে অনুমোদন করেছে তা নির্দিষ্ট করে৷ এই ক্ষেত্রে, এটি সত্য হিসাবে সেট করা হয়েছে, যার অর্থ এই যে ব্যবহারকারীর পূর্বে এই অ্যাপের সাথে ব্যবহারের জন্য অনুমোদিত শংসাপত্রগুলি ব্যবহার করে অনুরোধ করা হবে, যদি কোনো উপলব্ধ থাকে।
      • .setServerClientId(webClientId) : সার্ভার ক্লায়েন্ট আইডি সেট করে, যা আপনার অ্যাপের ব্যাকএন্ডের জন্য একটি অনন্য শনাক্তকারী। এটি একটি আইডি টোকেন পেতে প্রয়োজন.
      • .setNonce(generateSecureRandomNonce())
      • .build() : নির্দিষ্ট কনফিগারেশনের সাথে GetGoogleIdOption অবজেক্ট তৈরি করে।
    • val request: GetCredentialRequest = ... : একটি GetCredentialRequest অবজেক্ট তৈরি করে। এই বস্তুটি সম্পূর্ণ শংসাপত্রের অনুরোধকে এনক্যাপসুলেট করে।
      • .Builder() : অনুরোধ কনফিগার করতে বিল্ডার প্যাটার্ন শুরু করে।
      • .addCredentialOption(googleIdOption) : অনুরোধে googleIdOption যোগ করে, উল্লেখ করে যে আমরা একটি Google আইডি টোকেন অনুরোধ করতে চাই।
      • .build() : GetCredentialRequest অবজেক্ট তৈরি করে।
    • val e = signIn(request, context) : এটি তৈরি করা অনুরোধ এবং বর্তমান প্রসঙ্গ দিয়ে ব্যবহারকারীকে সাইন ইন করার চেষ্টা করে। সাইনইন ফাংশনের ফলাফল ই-তে সংরক্ষিত হয়। এই ভেরিয়েবলে সফল ফলাফল বা ব্যতিক্রম থাকবে।
    • if (e is NoCredentialException) { ... } : এটি একটি শর্তসাপেক্ষ চেক৷ যদি সাইনইন ফাংশন একটি NoCredentialException এর সাথে ব্যর্থ হয়, তাহলে এর অর্থ হল পূর্বে অনুমোদিত কোনো অ্যাকাউন্ট উপলব্ধ নেই৷
      • val googleIdOptionFalse: GetGoogleIdOption = ... : পূর্ববর্তী signIn ব্যর্থ হলে, এই অংশটি একটি নতুন GetGoogleIdOption তৈরি করে।
      • .setFilterByAuthorizedAccounts(false) : এটি প্রথম বিকল্প থেকে গুরুত্বপূর্ণ পার্থক্য। এটি অনুমোদিত অ্যাকাউন্টগুলির ফিল্টারিং অক্ষম করে, যার অর্থ ডিভাইসে যেকোন Google অ্যাকাউন্ট সাইন ইন করতে ব্যবহার করা যেতে পারে৷
      • val requestFalse: GetCredentialRequest = ... : googleIdOptionFalse দিয়ে একটি নতুন GetCredentialRequest তৈরি করা হয়েছে।
      • signIn(requestFalse, context) : এটি ব্যবহারকারীকে নতুন অনুরোধের সাথে সাইন ইন করার চেষ্টা করে যা যেকোনো অ্যাকাউন্ট ব্যবহার করার অনুমতি দেয়।

সারমর্মে, এই কোডটি প্রদত্ত কনফিগারেশন ব্যবহার করে ব্যবহারকারীর জন্য একটি Google আইডি টোকেন পুনরুদ্ধার করার জন্য ক্রেডেনশিয়াল ম্যানেজার API-এর কাছে একটি অনুরোধ প্রস্তুত করে। GetCredentialRequest তারপর ক্রেডেনশিয়াল ম্যানেজার UI চালু করতে ব্যবহার করা যেতে পারে, যেখানে ব্যবহারকারী তাদের Google অ্যাকাউন্ট নির্বাচন করতে পারে এবং প্রয়োজনীয় অনুমতি দিতে পারে।

fun generateSecureRandomNonce(byteLength: Int = 32): String : এটি generateSecureRandomNonce নামের একটি ফাংশনকে সংজ্ঞায়িত করে। এটি একটি পূর্ণসংখ্যা আর্গুমেন্ট বাইটলেংথ (ডিফল্ট মান 32 সহ) গ্রহণ করে যা বাইটে ননসের কাঙ্ক্ষিত দৈর্ঘ্য নির্দিষ্ট করে। এটি একটি স্ট্রিং প্রদান করে, যা হবে র্যান্ডম বাইটের Base64-এনকোডেড উপস্থাপনা।

  • val randomBytes = ByteArray(byteLength) : র্যান্ডম বাইট ধরে রাখতে নির্দিষ্ট বাইট দৈর্ঘ্যের একটি বাইট অ্যারে তৈরি করে।
  • SecureRandom.getInstanceStrong().nextBytes(randomBytes) :
    • SecureRandom.getInstanceStrong() : এটি একটি ক্রিপ্টোগ্রাফিকভাবে শক্তিশালী র্যান্ডম নম্বর জেনারেটর পায়। এটি নিরাপত্তার জন্য অত্যন্ত গুরুত্বপূর্ণ, কারণ এটি নিশ্চিত করে যে উত্পন্ন সংখ্যাগুলি সত্যিই এলোমেলো এবং অনুমানযোগ্য নয়৷ এটি সিস্টেমে এনট্রপির সবচেয়ে শক্তিশালী উপলব্ধ উৎস ব্যবহার করে।
    • .nextBytes(randomBytes) : এটি SecureRandom দৃষ্টান্ত দ্বারা উত্পন্ন র্যান্ডম বাইট সহ র্যান্ডমবাইট অ্যারেকে পপুলেট করে।
  • return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes) :
    • Base64.getUrlEncoder() : এটি একটি Base64 এনকোডার পায় যা একটি URL-নিরাপদ বর্ণমালা ব্যবহার করে (+ এবং / এর পরিবর্তে - এবং _ ব্যবহার করে)। এটি গুরুত্বপূর্ণ কারণ এটি নিশ্চিত করে যে ফলস্বরূপ স্ট্রিংটি আরও এনকোডিংয়ের প্রয়োজন ছাড়াই ইউআরএলগুলিতে নিরাপদে ব্যবহার করা যেতে পারে।
    • .withoutPadding() : এটি Base64 এনকোড করা স্ট্রিং থেকে যেকোনো প্যাডিং অক্ষর সরিয়ে দেয়। এটি প্রায়শই ননসটিকে কিছুটা ছোট এবং আরও কমপ্যাক্ট করার জন্য বাঞ্ছনীয়।
    • .encodeToString(randomBytes) : এটি একটি বেস64 স্ট্রিং-এ র্যান্ডমবাইট এনকোড করে এবং রিটার্ন করে।

সংক্ষেপে বলতে গেলে, এই ফাংশনটি একটি নির্দিষ্ট দৈর্ঘ্যের একটি ক্রিপ্টোগ্রাফিকভাবে শক্তিশালী র্যান্ডম ননস তৈরি করে, ইউআরএল-নিরাপদ বেস64 ব্যবহার করে এটিকে এনকোড করে এবং ফলস্বরূপ স্ট্রিং প্রদান করে। নিরাপত্তা-সংবেদনশীল প্রেক্ষাপটে ব্যবহারের জন্য নিরাপদ ননস তৈরি করার জন্য এটি একটি আদর্শ অনুশীলন।

সাইন ইন অনুরোধ করুন

এখন যেহেতু আমরা আমাদের সাইন-ইন অনুরোধ তৈরি করতে সক্ষম হয়েছি, আমরা সাইন ইন করার জন্য এটি ব্যবহার করার জন্য ক্রেডেনশিয়াল ম্যানেজার ব্যবহার করতে পারি৷ এটি করার জন্য আমাদের এমন একটি ফাংশন তৈরি করতে হবে যা ক্রেডেনশিয়াল ম্যানেজার ব্যবহার করে পাস করার সাইন-ইন অনুরোধগুলি পরিচালনা করে, যখন আমরা সম্মুখীন হতে পারি এমন সাধারণ ব্যতিক্রমগুলি পরিচালনা করে৷

আপনি এটি সম্পন্ন করতে BottomSheet() ফাংশনের নীচে এই ফাংশনে পেস্ট করতে পারেন।

//This code will not work on Android versions < UPSIDE_DOWN_CAKE when GetCredentialException is
//is thrown.
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
suspend fun signIn(request: GetCredentialRequest, context: Context): Exception? {
    val credentialManager = CredentialManager.create(context)
    val failureMessage = "Sign in failed!"
    var e: Exception? = null
    //using delay() here helps prevent NoCredentialException when the BottomSheet Flow is triggered
    //on the initial running of our app
    delay(250)
    try {
        // The getCredential is called to request a credential from Credential Manager.
        val result = credentialManager.getCredential(
            request = request,
            context = context,
        )
        Log.i(TAG, result.toString())

        Toast.makeText(context, "Sign in successful!", Toast.LENGTH_SHORT).show()
        Log.i(TAG, "(☞゚ヮ゚)☞  Sign in Successful!  ☜(゚ヮ゚☜)")

    } catch (e: GetCredentialException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Failure getting credentials", e)
        
    } catch (e: GoogleIdTokenParsingException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Issue with parsing received GoogleIdToken", e)

    } catch (e: NoCredentialException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": No credentials found", e)
        return e

    } catch (e: GetCredentialCustomException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Issue with custom credential request", e)

    } catch (e: GetCredentialCancellationException) {
        Toast.makeText(context, ": Sign-in cancelled", Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Sign-in was cancelled", e)
    }
    return e
}

এখন কোডটি এখানে কী করছে তা ভাঙ্গাতে:

suspend fun signIn(request: GetCredentialRequest, context: Context): Exception? : এটি সাইনইন নামের একটি সাসপেন্ড ফাংশনকে সংজ্ঞায়িত করে। এর মানে মূল থ্রেড ব্লক না করেই এটিকে বিরতি দেওয়া এবং পুনরায় শুরু করা যেতে পারে। এটি একটি Exception? সাইন ইন সফল হলে যা শূন্য হবে বা সাইন ইন ব্যর্থ হলে নির্দিষ্ট ব্যতিক্রম হবে।

এটি দুটি পরামিতি লাগে:

  • request : একটি GetCredentialRequest অবজেক্ট, যা পুনরুদ্ধার করার জন্য শংসাপত্রের প্রকারের কনফিগারেশন ধারণ করে (যেমন, Google ID)।
  • context : সিস্টেমের সাথে ইন্টারঅ্যাক্ট করার জন্য অ্যান্ড্রয়েড প্রসঙ্গ প্রয়োজন।

ফাংশনের শরীরের জন্য:

  • val credentialManager = CredentialManager.create(context) : CredentialManager-এর একটি উদাহরণ তৈরি করে, যা ক্রেডেনশিয়াল ম্যানেজার API-এর সাথে ইন্টারঅ্যাক্ট করার জন্য প্রধান ইন্টারফেস। এইভাবে অ্যাপটি সাইন ইন ফ্লো শুরু করবে।
  • val failureMessage = "Sign in failed!" : সাইন-ইন ব্যর্থ হলে টোস্টে প্রদর্শিত একটি স্ট্রিং (failureMessage) সংজ্ঞায়িত করে।
  • var e: Exception? = null : এই লাইনটি null দিয়ে শুরু করে প্রক্রিয়া চলাকালীন ঘটতে পারে এমন কোনো ব্যতিক্রম সঞ্চয় করার জন্য একটি ভেরিয়েবল ই শুরু করে।
  • delay(250) : একটি 250-মিলিসেকেন্ড বিলম্ব প্রবর্তন করে। এটি একটি সম্ভাব্য সমস্যার জন্য একটি সমাধান যেখানে অ্যাপটি শুরু হওয়ার সাথে সাথেই NoCredentialException নিক্ষেপ করা হতে পারে, বিশেষ করে যখন BottomSheet ফ্লো ব্যবহার করা হয়। এটি সিস্টেমকে শংসাপত্র ব্যবস্থাপক শুরু করার জন্য সময় দেয়।
  • try { ... } catch (e: Exception) { ... } : একটি ট্রাই-ক্যাচ ব্লক শক্তিশালী ত্রুটি পরিচালনার জন্য ব্যবহৃত হয়। এটি নিশ্চিত করে যে সাইন-ইন প্রক্রিয়া চলাকালীন কোনো ত্রুটি ঘটলে, অ্যাপটি ক্র্যাশ হবে না এবং এটি ব্যতিক্রমটিকে সুন্দরভাবে পরিচালনা করতে পারে।
    • val result = credentialManager.getCredential(request = request, context = context) : এখানেই ক্রেডেনশিয়াল ম্যানেজার এপিআই-তে প্রকৃত কল হয় এবং শংসাপত্র পুনরুদ্ধার প্রক্রিয়া শুরু করে। এটি অনুরোধ এবং প্রসঙ্গকে ইনপুট হিসাবে নেয় এবং একটি শংসাপত্র নির্বাচন করতে ব্যবহারকারীর কাছে একটি UI উপস্থাপন করবে। সফল হলে, এটি নির্বাচিত শংসাপত্র সহ একটি ফলাফল প্রদান করবে। এই অপারেশনের ফলাফল, GetCredentialResponse , result ভেরিয়েবলে সংরক্ষণ করা হয়।
    • Toast.makeText(context, "Sign in successful!", Toast.LENGTH_SHORT).show() : একটি ছোট টোস্ট বার্তা প্রদর্শন করে যা নির্দেশ করে যে সাইন-ইন সফল হয়েছে৷
    • Log.i(TAG, "Sign in Successful!") : লগক্যাটে একটি মজার, সফল বার্তা লগ করে।
    • catch (e: GetCredentialException) : GetCredentialException প্রকারের ব্যতিক্রমগুলি পরিচালনা করে। শংসাপত্র আনার প্রক্রিয়া চলাকালীন ঘটতে পারে এমন কয়েকটি নির্দিষ্ট ব্যতিক্রমের জন্য এটি একটি অভিভাবক শ্রেণী।
    • catch (e: GoogleIdTokenParsingException) : Google আইডি টোকেন পার্স করার সময় একটি ত্রুটি ঘটলে ব্যতিক্রমগুলি পরিচালনা করে।
    • catch (e: NoCredentialException) : NoCredentialException পরিচালনা করে, যা ব্যবহারকারীর জন্য কোনো শংসাপত্র উপলব্ধ না থাকলে নিক্ষেপ করা হয় (যেমন, তারা কোনো সংরক্ষণ করেনি, বা তাদের কোনো Google অ্যাকাউন্ট নেই)।
      • অত্যন্ত গুরুত্বপূর্ণভাবে, এই ফাংশনটি e , NoCredentialException এ সঞ্চিত ব্যতিক্রমটি ফেরত দেয়, যদি কোনো শংসাপত্র উপলব্ধ না থাকে তাহলে কলকারীকে নির্দিষ্ট ক্ষেত্রে পরিচালনা করতে দেয়।
    • catch (e: GetCredentialCustomException) : কাস্টম ব্যতিক্রমগুলি পরিচালনা করে যা শংসাপত্র প্রদানকারী দ্বারা নিক্ষিপ্ত হতে পারে।
    • catch (e: GetCredentialCancellationException) : GetCredentialCancellationException হ্যান্ডেল করে, যা ব্যবহারকারী সাইন-ইন প্রক্রিয়া বাতিল করলে নিক্ষেপ করা হয়।
    • Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show() : একটি টোস্ট বার্তা প্রদর্শন করে যে ইঙ্গিত করে যে ব্যর্থতা মেসেজ ব্যবহার করে সাইন-ইন ব্যর্থ হয়েছে৷
    • Log.e(TAG, "", e) : Log.e ব্যবহার করে Android logcat-এর ব্যতিক্রম লগ করে, যা ত্রুটির জন্য ব্যবহৃত হয়। এটি ডিবাগ করতে সাহায্য করার জন্য ব্যতিক্রমের স্ট্যাকট্রেস অন্তর্ভুক্ত করবে। এটি মজার জন্য রাগান্বিত ইমোটিকনও অন্তর্ভুক্ত করে।
  • return e : কোনো ধরা পড়লে ফাংশন ব্যতিক্রম প্রদান করে, অথবা সাইন ইন সফল হলে শূন্য দেয়।

সংক্ষেপে, এই কোডটি ক্রেডেনশিয়াল ম্যানেজার API ব্যবহার করে ব্যবহারকারীর সাইন-ইন পরিচালনা করার একটি উপায় প্রদান করে, অ্যাসিঙ্ক্রোনাস অপারেশন পরিচালনা করে, সম্ভাব্য ত্রুটিগুলি পরিচালনা করে এবং টোস্ট এবং লগের মাধ্যমে ব্যবহারকারীকে প্রতিক্রিয়া প্রদান করে যখন ত্রুটি পরিচালনায় হাস্যরসের স্পর্শ যোগ করে৷

অ্যাপে নীচের শীট প্রবাহ প্রয়োগ করুন

এখন আমরা নিম্নলিখিত কোড এবং আমাদের ওয়েব অ্যাপ্লিকেশন ক্লায়েন্ট আইডি ব্যবহার করে আমাদের MainActivity ক্লাসে BottomSheet ফ্লো ট্রিগার করার জন্য একটি কল সেট আপ করতে পারি যা আমরা আগে Google Cloud Console থেকে কপি করেছি:

class MainActivity : ComponentActivity() {
    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //replace with your own web client ID from Google Cloud Console
        val webClientId = "YOUR_CLIENT_ID_HERE"

        setContent {
            //ExampleTheme - this is derived from the name of the project not any added library
            //e.g. if this project was named "Testing" it would be generated as TestingTheme
            ExampleTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background,
                ) {
                    //This will trigger on launch
                    BottomSheet(webClientId)
                }
            }
        }
    }
}

এখন আমরা আমাদের প্রকল্প সংরক্ষণ করতে পারি ( ফাইল > সংরক্ষণ করুন ) এবং এটি চালাতে পারি:

  1. রান বোতাম টিপুন:প্রকল্প চালান
  2. একবার আপনার অ্যাপ এমুলেটরে চলে গেলে, আপনি সাইন-ইন বটমশিট পপ আপ দেখতে পাবেন। সাইন-ইন পরীক্ষা করতে এগিয়ে যান এবং অবিরত ক্লিক করুন৷নীচের শীট
  3. আপনি একটি টোস্ট বার্তা দেখতে পাবেন যে সাইন-ইন সফল হয়েছে! নীচের শীট সাফল্য

7. বোতাম প্রবাহ

বোতাম ফ্লো জিআইএফ

Google এর সাথে সাইন ইন করার জন্য বোতাম ফ্লো ব্যবহারকারীদের তাদের বিদ্যমান Google অ্যাকাউন্ট ব্যবহার করে আপনার Android অ্যাপে সাইন আপ করা বা লগ ইন করা সহজ করে তোলে। তারা এটিকে আঘাত করবে যদি তারা নীচের শীটটি খারিজ করে দেয় বা সাইন-ইন বা সাইন-আপের জন্য তাদের Google অ্যাকাউন্ট ব্যবহার করে স্পষ্টভাবে পছন্দ করে। বিকাশকারীদের জন্য, এর অর্থ হল মসৃণ অনবোর্ডিং এবং সাইন-আপের সময় কম ঘর্ষণ৷

যদিও এটি একটি আউট অফ দ্য বক্স জেটপ্যাক কম্পোজ বোতাম দিয়ে করা যেতে পারে, আমরা Google ব্র্যান্ডিং নির্দেশিকা পৃষ্ঠার সাথে সাইন ইন করুন থেকে একটি পূর্ব-অনুমোদিত ব্র্যান্ড আইকন ব্যবহার করব৷

প্রোজেক্টে ব্র্যান্ড আইকন যোগ করুন

  1. এখানে পূর্ব-অনুমোদিত ব্র্যান্ড আইকনগুলির জিপ ডাউনলোড করুন
  2. আপনার ডাউনলোডগুলি থেকে signin-assest.zip কম্প্রেস করুন (এটি আপনার কম্পিউটারের অপারেটিং সিস্টেমের উপর ভিত্তি করে পরিবর্তিত হবে)। এখন আপনি সাইন-ইন-সম্পদ ফোল্ডার খুলতে পারেন এবং উপলব্ধ আইকনগুলি দেখতে পারেন৷ এই কোডল্যাবের জন্য, আমরা signin-assets/Android/png@2x/neutral/android_neutral_sq_SI@2x.png ব্যবহার করব।
  3. ফাইলটি কপি করুন
  4. অ্যানড্রয়েড স্টুডিওতে প্রজেক্টে res > drawable-এর অধীনে ড্রয়েবল ফোল্ডারে ডান ক্লিক করে পেস্ট করুন (এটি দেখার জন্য আপনাকে রেস ফোল্ডারটি প্রসারিত করতে হতে পারে) ক্লিক করে আটকানঅঙ্কনযোগ্য
  5. একটি ডায়ালগ আপনাকে ফাইলটির নাম পরিবর্তন করতে এবং এটি যে ডিরেক্টরিতে যুক্ত করা হবে তা নিশ্চিত করতে অনুরোধ করবে। সম্পদের নাম পরিবর্তন করে siwg_button.png করুন তারপর ওকে ক্লিক করুন বোতাম যোগ করা হচ্ছে

বোতাম প্রবাহ কোড

এই কোডটি একই signIn() ফাংশন ব্যবহার করবে যা BottomSheet() এর জন্য ব্যবহার করা হয় কিন্তু GetGoogleIdOption এর পরিবর্তে GetSignInWithGoogleOption ব্যবহার করে কারণ এই প্রবাহটি সাইন ইন বিকল্পগুলি দেখানোর জন্য ডিভাইসে সঞ্চিত শংসাপত্র এবং পাসকিগুলিকে সুবিধা দেয় না৷ BottomSheet() ফাংশনের নীচে আপনি যে কোডটি পেস্ট করতে পারেন তা এখানে:

@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Composable
fun ButtonUI(webClientId: String) {
    val context = LocalContext.current
    val coroutineScope = rememberCoroutineScope()

    val onClick: () -> Unit = {
        val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption
            .Builder(serverClientId = webClientId)
            .setNonce(generateSecureRandomNonce())
            .build()

        val request: GetCredentialRequest = GetCredentialRequest.Builder()
            .addCredentialOption(signInWithGoogleOption)
            .build()

        coroutineScope.launch {
            signIn(request, context)
        }
    }
    Image(
        painter = painterResource(id = R.drawable.siwg_button),
        contentDescription = "",
        modifier = Modifier
            .fillMaxSize()
            .clickable(enabled = true, onClick = onClick)
    )
}

কোডটি কী করছে তা ভাঙতে:

fun ButtonUI(webClientId: String) : এটি ButtonUI নামের একটি ফাংশন ঘোষণা করে যা একটি webClientId (আপনার Google ক্লাউড প্রকল্পের ক্লায়েন্ট আইডি) একটি যুক্তি হিসেবে গ্রহণ করে।

val context = LocalContext.current : বর্তমান অ্যান্ড্রয়েড প্রসঙ্গ পুনরুদ্ধার করে। UI উপাদান চালু করা সহ বিভিন্ন ক্রিয়াকলাপের জন্য এটি প্রয়োজন।

val coroutineScope = rememberCoroutineScope() : একটি coroutine সুযোগ তৈরি করে। এটি অ্যাসিঙ্ক্রোনাস কাজগুলি পরিচালনা করতে ব্যবহৃত হয়, কোডটিকে মূল থ্রেড ব্লক না করেই চালানোর অনুমতি দেয়। rememberCoroutineScope () হল জেটপ্যাক কম্পোজের একটি সংমিশ্রণযোগ্য ফাংশন যা কম্পোজেবলের জীবনচক্রের সাথে আবদ্ধ একটি সুযোগ প্রদান করবে।

val onClick: () -> Unit = { ... } : এটি একটি ল্যাম্বডা ফাংশন তৈরি করে যা বোতামটি ক্লিক করার সময় কার্যকর করা হবে। ল্যাম্বডা ফাংশন হবে:

  • val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder(serverClientId = webClientId).setNonce(generateSecureRandomNonce()).build() : এই অংশটি একটি GetSignInWithGoogleOption অবজেক্ট তৈরি করে। এই বস্তুটি "Google এর সাথে সাইন ইন করুন" প্রক্রিয়ার প্যারামিটারগুলি নির্দিষ্ট করতে ব্যবহৃত হয়, এটির জন্য webClientId এবং একটি নন্স (নিরাপত্তার জন্য ব্যবহৃত একটি র্যান্ডম স্ট্রিং) প্রয়োজন৷
  • val request: GetCredentialRequest = GetCredentialRequest.Builder().addCredentialOption(signInWithGoogleOption).build() : এটি একটি GetCredentialRequest অবজেক্ট তৈরি করে। এই অনুরোধটি ক্রেডেনশিয়াল ম্যানেজার ব্যবহার করে ব্যবহারকারীর শংসাপত্র পেতে ব্যবহার করা হবে। GetCredentialRequest পূর্বে তৈরি করা GetSignInWithGoogleOption একটি বিকল্প হিসেবে যোগ করে, যাতে একটি "Google এর সাথে সাইন ইন করুন" শংসাপত্রের অনুরোধ করা যায়।
  • coroutineScope.launch { ... } : অ্যাসিঙ্ক্রোনাস অপারেশন পরিচালনা করার জন্য একটি CoroutineScope (করোটিন ব্যবহার করে)।
    • signIn(request, context) : আমাদের পূর্বে সংজ্ঞায়িত signIn () ফাংশনকে কল করে

Image(...) : এটি painterResource ব্যবহার করে একটি ইমেজ রেন্ডার করে যা ছবি R.drawable.siwg_button লোড করে

  • Modifier.fillMaxSize().clickable(enabled = true, onClick = onClick) :
    • fillMaxSize() : ইমেজ উপলব্ধ স্থান পূরণ করে তোলে।
    • clickable(enabled = true, onClick = onClick) : ছবিটিকে ক্লিকযোগ্য করে তোলে এবং ক্লিক করা হলে, এটি পূর্বে সংজ্ঞায়িত অনক্লিক ল্যাম্বডা ফাংশনটি কার্যকর করে।

সংক্ষেপে, এই কোডটি জেটপ্যাক কম্পোজ UI-তে একটি "Google দিয়ে সাইন ইন করুন" বোতাম সেট আপ করে৷ বোতামটি ক্লিক করা হলে, এটি ক্রেডেনশিয়াল ম্যানেজার চালু করার জন্য একটি শংসাপত্রের অনুরোধ প্রস্তুত করে এবং ব্যবহারকারীকে তাদের Google অ্যাকাউন্ট দিয়ে সাইন ইন করার অনুমতি দেয়।

এখন আমাদের ButtonUI() ফাংশন চালানোর জন্য MainActivity ক্লাস আপডেট করতে হবে:

class MainActivity : ComponentActivity() {
    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //replace with your own web client ID from Google Cloud Console
        val webClientId = "YOUR_CLIENT_ID_HERE"

        setContent {
            //ExampleTheme - this is derived from the name of the project not any added library
            //e.g. if this project was named "Testing" it would be generated as TestingTheme
            ExampleTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background,
                ) {
                    Column(
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment = Alignment.CenterHorizontally

                    ) {
                        //This will trigger on launch
                        BottomSheet(webClientId)

                        //This requires the user to press the button
                        ButtonUI(webClientId)
                    }
                }
            }
        }
    }
}

এখন আমরা আমাদের প্রকল্প সংরক্ষণ করতে পারি ( ফাইল > সংরক্ষণ করুন ) এবং এটি চালাতে পারি:

  1. রান বোতাম টিপুন:প্রকল্প চালান
  2. একবার এমুলেটরে অ্যাপগুলি চলে গেলে, বটমশিটটি দেখাতে হবে। এটি বন্ধ করতে এটির বাইরে ক্লিক করুন।এখানে আলতো চাপুন
  3. এখন আপনি অ্যাপটিতে দেখানো বোতামটি দেখতে পাবেন যা আমরা তৈরি করেছি। সাইন-ইন ডায়ালগ দেখতে এগিয়ে যান এবং ক্লিক করুন৷সাইন ইন ডায়ালগ
  4. সাইন ইন করতে আপনার অ্যাকাউন্টে ক্লিক করুন!

8. উপসংহার

আপনি এই কোডল্যাব শেষ! আরও তথ্যের জন্য বা অ্যান্ড্রয়েডে Google এর সাথে সাইন ইন করার বিষয়ে সহায়তার জন্য, নীচের প্রায়শই জিজ্ঞাসিত প্রশ্ন বিভাগটি দেখুন:

প্রায়শই জিজ্ঞাসিত প্রশ্নাবলী

সম্পূর্ণ MainActivity.kt কোড

রেফারেন্সের জন্য MainActivity.kt-এর সম্পূর্ণ কোড এখানে রয়েছে:

package com.example.example

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.example.example.ui.theme.ExampleTheme
import android.content.ContentValues.TAG
import android.content.Context
import android.credentials.GetCredentialException
import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.compose.foundation.clickable
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.credentials.CredentialManager
import androidx.credentials.exceptions.GetCredentialCancellationException
import androidx.credentials.exceptions.GetCredentialCustomException
import androidx.credentials.exceptions.NoCredentialException
import androidx.credentials.GetCredentialRequest
import com.google.android.libraries.identity.googleid.GetGoogleIdOption
import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption
import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
import java.security.SecureRandom
import java.util.Base64
import kotlinx.coroutines.CoroutineScope
import androidx.compose.runtime.LaunchedEffect
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {
    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //replace with your own web client ID from Google Cloud Console
        val webClientId = "YOUR_CLIENT_ID_HERE"

        setContent {
            //ExampleTheme - this is derived from the name of the project not any added library
            //e.g. if this project was named "Testing" it would be generated as TestingTheme
            ExampleTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background,
                ) {
                    Column(
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment = Alignment.CenterHorizontally

                    ) {
                        //This will trigger on launch
                        BottomSheet(webClientId)

                        //This requires the user to press the button
                        ButtonUI(webClientId)
                    }
                }
            }
        }
    }
}

//This line is not needed for the project to build, but you will see errors if it is not present.
//This code will not work on Android versions < UpsideDownCake
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Composable
    fun BottomSheet(webClientId: String) {
        val context = LocalContext.current

        // LaunchedEffect is used to run a suspend function when the composable is first launched.
        LaunchedEffect(Unit) {
            // Create a Google ID option with filtering by authorized accounts enabled.
            val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
                .setFilterByAuthorizedAccounts(true)
                .setServerClientId(webClientId)
                .setNonce(generateSecureRandomNonce())
                .build()

            // Create a credential request with the Google ID option.
            val request: GetCredentialRequest = GetCredentialRequest.Builder()
                .addCredentialOption(googleIdOption)
                .build()

            // Attempt to sign in with the created request using an authorized account
            val e = signIn(request, context)
            // If the sign-in fails with NoCredentialException,  there are no authorized accounts.
            // In this case, we attempt to sign in again with filtering disabled.
            if (e is NoCredentialException) {
                val googleIdOptionFalse: GetGoogleIdOption = GetGoogleIdOption.Builder()
                    .setFilterByAuthorizedAccounts(false)
                    .setServerClientId(webClientId)
                    .setNonce(generateSecureRandomNonce())
                    .build()

                val requestFalse: GetCredentialRequest = GetCredentialRequest.Builder()
                    .addCredentialOption(googleIdOptionFalse)
                    .build()
                    
                signIn(requestFalse, context)
            }
        }
    }

@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Composable
fun ButtonUI(webClientId: String) {
    val context = LocalContext.current
    val coroutineScope = rememberCoroutineScope()

    val onClick: () -> Unit = {
        val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption
            .Builder(serverClientId = webClientId)
            .setNonce(generateSecureRandomNonce())
            .build()

        val request: GetCredentialRequest = GetCredentialRequest.Builder()
            .addCredentialOption(signInWithGoogleOption)
            .build()

        signIn(coroutineScope, request, context)
    }
    Image(
        painter = painterResource(id = R.drawable.siwg_button),
        contentDescription = "",
        modifier = Modifier
            .fillMaxSize()
            .clickable(enabled = true, onClick = onClick)
    )
}

fun generateSecureRandomNonce(byteLength: Int = 32): String {
    val randomBytes = ByteArray(byteLength)
    SecureRandom.getInstanceStrong().nextBytes(randomBytes)
    return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes)
}

//This code will not work on Android versions < UPSIDE_DOWN_CAKE when GetCredentialException is
//is thrown.
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
suspend fun signIn(request: GetCredentialRequest, context: Context): Exception? {
    val credentialManager = CredentialManager.create(context)
    val failureMessage = "Sign in failed!"
    var e: Exception? = null
    //using delay() here helps prevent NoCredentialException when the BottomSheet Flow is triggered
    //on the initial running of our app
    delay(250)
    try {
        // The getCredential is called to request a credential from Credential Manager.
        val result = credentialManager.getCredential(
            request = request,
            context = context,
        )
        Log.i(TAG, result.toString())

        Toast.makeText(context, "Sign in successful!", Toast.LENGTH_SHORT).show()
        Log.i(TAG, "(☞゚ヮ゚)☞  Sign in Successful!  ☜(゚ヮ゚☜)")

    } catch (e: GetCredentialException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Failure getting credentials", e)
        
    } catch (e: GoogleIdTokenParsingException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Issue with parsing received GoogleIdToken", e)

    } catch (e: NoCredentialException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": No credentials found", e)
        return e

    } catch (e: GetCredentialCustomException) {
        Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Issue with custom credential request", e)

    } catch (e: GetCredentialCancellationException) {
        Toast.makeText(context, ": Sign-in cancelled", Toast.LENGTH_SHORT).show()
        Log.e(TAG, failureMessage + ": Sign-in was cancelled", e)
    }
    return e
}