ব্যবহারকারীদের তাদের সংরক্ষিত শংসাপত্র দিয়ে সাইন ইন করুন

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

এক-ট্যাপ সাইন-ইন UI

যখন শংসাপত্রগুলি সফলভাবে পুনরুদ্ধার করা হয়, আপনি সেগুলিকে ব্যবহার করতে পারেন ঘর্ষণহীনভাবে ব্যবহারকারীকে আপনার অ্যাপে সাইন ইন করতে৷

ব্যবহারকারী যদি কোনো শংসাপত্র সংরক্ষণ না করে থাকে, তাহলে কোনো UI উপস্থাপন করা হয় না এবং আপনি আপনার স্বাভাবিক সাইন-আউট অভিজ্ঞতা প্রদান করতে পারেন।

আমার কোথায় ওয়ান ট্যাপ সাইন-ইন ব্যবহার করা উচিত?

আপনার অ্যাপের ব্যবহারকারীদের সাইন ইন করার প্রয়োজন হলে, আপনার সাইন-ইন স্ক্রিনে One Tap UI প্রদর্শন করুন। আপনার কাছে ইতিমধ্যেই একটি "Google দিয়ে সাইন ইন করুন" বোতাম থাকলেও এটি সহায়ক হতে পারে: কারণ ওয়ান ট্যাপ UI শুধুমাত্র সেই শংসাপত্রগুলি দেখানোর জন্য কনফিগার করা যেতে পারে যা ব্যবহারকারী আগে সাইন-ইন করতে ব্যবহার করেন, এটি এমন ব্যবহারকারীদের জন্য একটি অনুস্মারক হতে পারে যারা কদাচিৎ সাইন ইন করেন কিভাবে তারা শেষবার সাইন ইন করেছিল এবং ভুলবশত আপনার অ্যাপ দিয়ে নতুন অ্যাকাউন্ট তৈরি করা থেকে তাদের বাধা দেয়।

যদি আপনার অ্যাপের জন্য সাইন-ইন ঐচ্ছিক হয়, তাহলে সাইন ইন করার মাধ্যমে উন্নত অভিজ্ঞতা আছে এমন যেকোনো স্ক্রিনে ওয়ান ট্যাপ সাইন-ইন ব্যবহার করার কথা বিবেচনা করুন। উদাহরণস্বরূপ, যদি ব্যবহারকারীরা সাইন আউট করার সময় আপনার অ্যাপের সাথে সামগ্রী ব্রাউজ করতে পারে তবে শুধুমাত্র মন্তব্য পোস্ট করতে পারে বা সাইন ইন করার পরে একটি শপিং কার্টে আইটেম যোগ করুন, এটি ওয়ান ট্যাপ সাইন-ইনের জন্য একটি বুদ্ধিমান প্রসঙ্গ হবে।

সাইন-ইন ঐচ্ছিক অ্যাপ্লিকেশানগুলিও উপরে উল্লিখিত কারণগুলির জন্য তাদের সাইন-ইন স্ক্রিনে ওয়ান ট্যাপ সাইন-ইন ব্যবহার করা উচিত৷

তুমি শুরু করার আগে

1. ওয়ান ট্যাপ সাইন-ইন ক্লায়েন্ট কনফিগার করুন

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

যদি আপনার অ্যাপ পাসওয়ার্ড-ভিত্তিক সাইন-ইন ব্যবহার করে, তাহলে পাসওয়ার্ড শংসাপত্রের অনুরোধগুলি সক্ষম করতে setPasswordRequestOptions() ব্যবহার করুন।

যদি আপনার অ্যাপ Google সাইন-ইন ব্যবহার করে, তাহলে Google আইডি টোকেন অনুরোধগুলি সক্ষম ও কনফিগার করতে setGoogleIdTokenRequestOptions() ব্যবহার করুন:

  • Google APIs কনসোলে আপনার তৈরি করা আইডিতে সার্ভার ক্লায়েন্ট আইডি সেট করুন। মনে রাখবেন এটি আপনার সার্ভারের ক্লায়েন্ট আইডি, আপনার অ্যান্ড্রয়েড ক্লায়েন্ট আইডি নয়।

  • অনুমোদিত অ্যাকাউন্ট দ্বারা ফিল্টার করার জন্য ক্লায়েন্টকে কনফিগার করুন। আপনি যখন এই বিকল্পটি সক্ষম করেন, তখন ওয়ান ট্যাপ ক্লায়েন্ট শুধুমাত্র ব্যবহারকারীদের আগে থেকে ব্যবহার করা Google অ্যাকাউন্টগুলির সাথে আপনার অ্যাপে সাইন ইন করতে অনুরোধ করে৷ এটি করা ব্যবহারকারীদের সফলভাবে সাইন ইন করতে সাহায্য করতে পারে যখন তারা নিশ্চিত না যে তাদের কাছে ইতিমধ্যেই একটি অ্যাকাউন্ট আছে বা তারা কোন Google অ্যাকাউন্ট ব্যবহার করেছে এবং ব্যবহারকারীদের ভুলবশত আপনার অ্যাপের সাথে নতুন অ্যাকাউন্ট তৈরি করা থেকে বিরত রাখে।

  • আপনি যদি সম্ভব হলে ব্যবহারকারীদের স্বয়ংক্রিয়ভাবে সাইন ইন করতে চান, তাহলে setAutoSelectEnabled() দিয়ে বৈশিষ্ট্যটি সক্ষম করুন। নিম্নলিখিত মানদণ্ড পূরণ হলে স্বয়ংক্রিয় সাইন-ইন সম্ভব:

    • ব্যবহারকারীর আপনার অ্যাপের জন্য ঠিক একটি শংসাপত্র সংরক্ষিত আছে। অর্থাৎ, একটি সংরক্ষিত পাসওয়ার্ড বা একটি সংরক্ষিত Google অ্যাকাউন্ট।
    • ব্যবহারকারী তাদের Google অ্যাকাউন্ট সেটিংসে স্বয়ংক্রিয় সাইন-ইন অক্ষম করেনি৷
  • ঐচ্ছিক হলেও, আমরা সুপারিশ করছি যে আপনি সাইন-ইন নিরাপত্তা উন্নত করতে এবং রিপ্লে আক্রমণ এড়াতে একটি নন্স ব্যবহার করার বিষয়ে দৃঢ়ভাবে বিবেচনা করুন। প্রতিটি অনুরোধে একটি নন্স অন্তর্ভুক্ত করতে setNonce ব্যবহার করুন। পরামর্শের জন্য SafetyNet-এর প্রাপ্ত একটি নন্স বিভাগ দেখুন এবং একটি ননস তৈরি করার অতিরিক্ত বিশদ বিবরণ।

জাভা

public class YourActivity extends AppCompatActivity {
  // ...

  private SignInClient oneTapClient;
  private BeginSignInRequest signInRequest;

  @Override
  public void onCreate(@Nullable Bundle savedInstanceState,
                       @Nullable PersistableBundle persistentState) {
      super.onCreate(savedInstanceState, persistentState);

      oneTapClient = Identity.getSignInClient(this);
      signInRequest = BeginSignInRequest.builder()
              .setPasswordRequestOptions(PasswordRequestOptions.builder()
                      .setSupported(true)
                      .build())
              .setGoogleIdTokenRequestOptions(GoogleIdTokenRequestOptions.builder()
                      .setSupported(true)
                      // Your server's client ID, not your Android client ID.
                      .setServerClientId(getString(R.string.default_web_client_id))
                      // Only show accounts previously used to sign in.
                      .setFilterByAuthorizedAccounts(true)
                      .build())
              // Automatically sign in when exactly one credential is retrieved.
              .setAutoSelectEnabled(true)
              .build();
      // ...
  }
  // ...
}

কোটলিন

class YourActivity : AppCompatActivity() {
    // ...

    private lateinit var oneTapClient: SignInClient
    private lateinit var signInRequest: BeginSignInRequest

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        oneTapClient = Identity.getSignInClient(this)
        signInRequest = BeginSignInRequest.builder()
            .setPasswordRequestOptions(BeginSignInRequest.PasswordRequestOptions.builder()
                .setSupported(true)
                .build())
            .setGoogleIdTokenRequestOptions(
                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    // Your server's client ID, not your Android client ID.
                    .setServerClientId(getString(R.string.your_web_client_id))
                    // Only show accounts previously used to sign in.
                    .setFilterByAuthorizedAccounts(true)
                    .build())
            // Automatically sign in when exactly one credential is retrieved.
            .setAutoSelectEnabled(true)
            .build()
        // ...
    }
    // ...
}

2. সাইন-ইন করা ব্যবহারকারীর জন্য চেক করুন

আপনার অ্যাক্টিভিটি যদি সাইন-ইন করা ব্যবহারকারী বা সাইন-আউট করা ব্যবহারকারী ব্যবহার করতে পারে, তাহলে ওয়ান ট্যাপ সাইন-ইন UI প্রদর্শন করার আগে ব্যবহারকারীর স্থিতি পরীক্ষা করুন।

প্রম্পটটি বন্ধ করে বা এর বাইরে ট্যাপ করে ব্যবহারকারী ইতিমধ্যে ওয়ান ট্যাপ সাইন-ইন ব্যবহার করতে অস্বীকার করেছেন কিনা তাও আপনার নজর রাখা উচিত। এটি আপনার কার্যকলাপের একটি বুলিয়ান সম্পত্তি হিসাবে সহজ হতে পারে. (নীচে এক ট্যাপ UI প্রদর্শন করা বন্ধ করুন দেখুন।)

3. এক ট্যাপ সাইন-ইন UI প্রদর্শন করুন৷

ব্যবহারকারী যদি সাইন ইন না করে থাকেন এবং ইতিমধ্যেই ওয়ান ট্যাপ সাইন-ইন ব্যবহার করতে অস্বীকার না করেন, তাহলে ক্লায়েন্ট অবজেক্টের beginSignIn() পদ্ধতিতে কল করুন এবং শ্রোতাদের এটি যে Task ফেরত দেয় তাতে সংযুক্ত করুন। অ্যাপ্লিকেশানগুলি সাধারণত একক-অ্যাক্টিভিটি আর্কিটেকচার ব্যবহার করার সময় অ্যাক্টিভিটির onCreate() পদ্ধতিতে বা স্ক্রিন ট্রানজিশনের পরে এটি করে।

ব্যবহারকারীর কাছে আপনার অ্যাপের জন্য কোনো সংরক্ষিত শংসাপত্র থাকলে ওয়ান ট্যাপ ক্লায়েন্ট সফল শ্রোতাকে কল করবে। সফল শ্রোতার মধ্যে, Task ফলাফল থেকে মুলতুবি অভিপ্রায়টি পান এবং ওয়ান ট্যাপ সাইন-ইন UI শুরু করতে startIntentSenderForResult() এ পাস করুন৷

ব্যবহারকারীর কাছে কোনো সংরক্ষিত শংসাপত্র না থাকলে, ওয়ান ট্যাপ ক্লায়েন্ট ব্যর্থ শ্রোতাকে কল করবে। এই ক্ষেত্রে, কোনও পদক্ষেপের প্রয়োজন নেই: আপনি কেবল অ্যাপের সাইন-আউট অভিজ্ঞতা উপস্থাপন করা চালিয়ে যেতে পারেন। যাইহোক, আপনি যদি One Tap সাইন-আপ সমর্থন করেন, তাহলে আপনি একটি নির্বিঘ্ন অ্যাকাউন্ট তৈরির অভিজ্ঞতার জন্য এখানে সেই প্রবাহ শুরু করতে পারেন। এক ট্যাপ দিয়ে নতুন অ্যাকাউন্ট তৈরি করুন দেখুন।

জাভা

oneTapClient.beginSignIn(signUpRequest)
        .addOnSuccessListener(this, new OnSuccessListener<BeginSignInResult>() {
            @Override
            public void onSuccess(BeginSignInResult result) {
                try {
                    startIntentSenderForResult(
                            result.getPendingIntent().getIntentSender(), REQ_ONE_TAP,
                            null, 0, 0, 0);
                } catch (IntentSender.SendIntentException e) {
                    Log.e(TAG, "Couldn't start One Tap UI: " + e.getLocalizedMessage());
                }
            }
        })
        .addOnFailureListener(this, new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // No saved credentials found. Launch the One Tap sign-up flow, or
                // do nothing and continue presenting the signed-out UI.
                Log.d(TAG, e.getLocalizedMessage());
            }
        });

কোটলিন

oneTapClient.beginSignIn(signInRequest)
    .addOnSuccessListener(this) { result ->
        try {
            startIntentSenderForResult(
                result.pendingIntent.intentSender, REQ_ONE_TAP,
                null, 0, 0, 0, null)
        } catch (e: IntentSender.SendIntentException) {
            Log.e(TAG, "Couldn't start One Tap UI: ${e.localizedMessage}")
        }
    }
    .addOnFailureListener(this) { e ->
        // No saved credentials found. Launch the One Tap sign-up flow, or
        // do nothing and continue presenting the signed-out UI.
        Log.d(TAG, e.localizedMessage)
    }

4. ব্যবহারকারীর প্রতিক্রিয়া হ্যান্ডেল

ওয়ান ট্যাপ সাইন-ইন প্রম্পটে ব্যবহারকারীর প্রতিক্রিয়া আপনার অ্যাক্টিভিটির onActivityResult() পদ্ধতি ব্যবহার করে আপনার অ্যাপে রিপোর্ট করা হবে। ব্যবহারকারী যদি সাইন ইন করা বেছে নেন, ফলাফলটি একটি সংরক্ষিত শংসাপত্র হবে৷ যদি ব্যবহারকারী সাইন ইন করতে অস্বীকার করে, হয় One Tap UI বন্ধ করে বা এর বাইরে ট্যাপ করে, ফলাফলটি RESULT_CANCELED কোডের সাথে ফিরে আসবে। আপনার অ্যাপটিকে উভয় সম্ভাবনাই পরিচালনা করতে হবে।

পুনরুদ্ধার করা শংসাপত্র দিয়ে সাইন ইন করুন

ব্যবহারকারী যদি আপনার অ্যাপের সাথে শংসাপত্রগুলি ভাগ করা বেছে নেন, তাহলে আপনি onActivityResult() থেকে One Tap ক্লায়েন্টের getSignInCredentialFromIntent() পদ্ধতিতে উদ্দেশ্য ডেটা পাস করে সেগুলি পুনরুদ্ধার করতে পারেন। যদি ব্যবহারকারী আপনার অ্যাপের সাথে একটি Google অ্যাকাউন্টের শংসাপত্র শেয়ার করেন তাহলে শংসাপত্রটিতে একটি নন-নাল googleIdToken প্রপার্টি থাকবে, অথবা যদি ব্যবহারকারী একটি সেভ করা পাসওয়ার্ড শেয়ার করেন তাহলে একটি নন-নাল password প্রপার্টি থাকবে।

আপনার অ্যাপের ব্যাকএন্ড দিয়ে প্রমাণীকরণ করতে শংসাপত্র ব্যবহার করুন।

  • যদি একটি ব্যবহারকারীর নাম এবং পাসওয়ার্ড যুগল পুনরুদ্ধার করা হয়, সেগুলিকে সাইন ইন করতে একইভাবে ব্যবহার করুন যদি ব্যবহারকারী নিজে সেগুলি সরবরাহ করে থাকে।
  • যদি Google অ্যাকাউন্টের শংসাপত্রগুলি পুনরুদ্ধার করা হয়, তাহলে আপনার ব্যাকএন্ডের সাথে প্রমাণীকরণ করতে আইডি টোকেন ব্যবহার করুন। আপনি যদি রিপ্লে আক্রমণ এড়াতে সাহায্য করার জন্য একটি নন্স ব্যবহার করা বেছে নিয়ে থাকেন তবে আপনার ব্যাকএন্ড সার্ভারে প্রতিক্রিয়া মান পরীক্ষা করুন। আইডি টোকেন ব্যবহার করে একটি ব্যাকএন্ড দিয়ে প্রমাণীকরণ দেখুন।

জাভা

public class YourActivity extends AppCompatActivity {

  // ...
  private static final int REQ_ONE_TAP = 2;  // Can be any integer unique to the Activity.
  private boolean showOneTapUI = true;
  // ...

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
      super.onActivityResult(requestCode, resultCode, data);

      switch (requestCode) {
          case REQ_ONE_TAP:
              try {
                  SignInCredential credential = oneTapClient.getSignInCredentialFromIntent(data);
                  String idToken = credential.getGoogleIdToken();
                  String username = credential.getId();
                  String password = credential.getPassword();
                  if (idToken !=  null) {
                      // Got an ID token from Google. Use it to authenticate
                      // with your backend.
                      Log.d(TAG, "Got ID token.");
                  } else if (password != null) {
                      // Got a saved username and password. Use them to authenticate
                      // with your backend.
                      Log.d(TAG, "Got password.");
                  }
              } catch (ApiException e) {
                  // ...
              }
              break;
      }
  }
}

কোটলিন

class YourActivity : AppCompatActivity() {

    // ...
    private val REQ_ONE_TAP = 2  // Can be any integer unique to the Activity
    private var showOneTapUI = true
    // ...

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        when (requestCode) {
             REQ_ONE_TAP -> {
                try {
                    val credential = oneTapClient.getSignInCredentialFromIntent(data)
                    val idToken = credential.googleIdToken
                    val username = credential.id
                    val password = credential.password
                    when {
                        idToken != null -> {
                            // Got an ID token from Google. Use it to authenticate
                            // with your backend.
                            Log.d(TAG, "Got ID token.")
                        }
                        password != null -> {
                            // Got a saved username and password. Use them to authenticate
                            // with your backend.
                            Log.d(TAG, "Got password.")
                        }
                        else -> {
                            // Shouldn't happen.
                            Log.d(TAG, "No ID token or password!")
                        }
                    }
                } catch (e: ApiException) {
                    // ...
                }
            }
        }
    }
    // ...
}

ওয়ান ট্যাপ UI প্রদর্শন করা বন্ধ করুন

যদি ব্যবহারকারী সাইন ইন করতে অস্বীকার করে, তাহলে getSignInCredentialFromIntent() এ কল করলে একটি ApiException CommonStatusCodes.CANCELED স্ট্যাটাস কোড থাকবে। যখন এটি ঘটে, তখন আপনাকে সাময়িকভাবে ওয়ান ট্যাপ সাইন-ইন UI অক্ষম করতে হবে যাতে আপনি বারবার প্রম্পট দিয়ে আপনার ব্যবহারকারীদের বিরক্ত না করেন। নিম্নলিখিত উদাহরণটি অ্যাক্টিভিটিতে একটি সম্পত্তি সেট করার মাধ্যমে এটি সম্পন্ন করে, যা এটি ব্যবহারকারীকে ওয়ান ট্যাপ সাইন-ইন অফার করবে কিনা তা নির্ধারণ করতে ব্যবহার করে; যাইহোক, আপনি SharedPreferences এ একটি মান সংরক্ষণ করতে পারেন বা অন্য কোনো পদ্ধতি ব্যবহার করতে পারেন।

ওয়ান ট্যাপ সাইন-ইন প্রম্পটগুলির সীমিত আপনার নিজস্ব হার বাস্তবায়ন করা গুরুত্বপূর্ণ। আপনি যদি তা না করেন, এবং একজন ব্যবহারকারী পরপর একাধিক প্রম্পট বাতিল করে, One Tap ক্লায়েন্ট পরবর্তী 24 ঘন্টার জন্য ব্যবহারকারীকে অনুরোধ করবে না।

জাভা

public class YourActivity extends AppCompatActivity {

  // ...
  private static final int REQ_ONE_TAP = 2;  // Can be any integer unique to the Activity.
  private boolean showOneTapUI = true;
  // ...

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
      super.onActivityResult(requestCode, resultCode, data);

      switch (requestCode) {
          case REQ_ONE_TAP:
              try {
                  // ...
              } catch (ApiException e) {
                  switch (e.getStatusCode()) {
                      case CommonStatusCodes.CANCELED:
                          Log.d(TAG, "One-tap dialog was closed.");
                          // Don't re-prompt the user.
                          showOneTapUI = false;
                          break;
                      case CommonStatusCodes.NETWORK_ERROR:
                          Log.d(TAG, "One-tap encountered a network error.");
                          // Try again or just ignore.
                          break;
                      default:
                          Log.d(TAG, "Couldn't get credential from result."
                                  + e.getLocalizedMessage());
                          break;
                  }
              }
              break;
      }
  }
}

কোটলিন

class YourActivity : AppCompatActivity() {

    // ...
    private val REQ_ONE_TAP = 2  // Can be any integer unique to the Activity
    private var showOneTapUI = true
    // ...

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        when (requestCode) {
            REQ_ONE_TAP -> {
                try {
                    // ...
                } catch (e: ApiException) {
                    when (e.statusCode) {
                        CommonStatusCodes.CANCELED -> {
                            Log.d(TAG, "One-tap dialog was closed.")
                            // Don't re-prompt the user.
                            showOneTapUI = false
                        }
                        CommonStatusCodes.NETWORK_ERROR -> {
                            Log.d(TAG, "One-tap encountered a network error.")
                            // Try again or just ignore.
                        }
                        else -> {
                            Log.d(TAG, "Couldn't get credential from result." +
                                " (${e.localizedMessage})")
                        }
                    }
                }
            }
        }
    }
    // ...
}

5. সাইন-আউট পরিচালনা করুন

যখন কোনো ব্যবহারকারী আপনার অ্যাপ থেকে সাইন আউট করেন, ওয়ান ট্যাপ ক্লায়েন্টের signOut() পদ্ধতিতে কল করুন। কল করা signOut() স্বয়ংক্রিয় সাইন-ইন অক্ষম করে যতক্ষণ না ব্যবহারকারী আবার সাইন ইন করে।

এমনকি আপনি স্বয়ংক্রিয় সাইন-ইন ব্যবহার না করলেও, এই পদক্ষেপটি গুরুত্বপূর্ণ কারণ এটি নিশ্চিত করে যে যখন ব্যবহারকারীরা আপনার অ্যাপ থেকে সাইন আউট করেন, তখন আপনি যে কোনো Play পরিষেবা API ব্যবহার করেন তার প্রমাণীকরণ অবস্থাও রিসেট হয়ে যায়।

পরবর্তী পদক্ষেপ

আপনি যদি Google শংসাপত্রগুলি পুনরুদ্ধার করতে One Tap ক্লায়েন্ট কনফিগার করেন, তাহলে আপনার অ্যাপ এখন Google ID টোকেন পেতে পারে যা আপনার ব্যবহারকারীদের Google অ্যাকাউন্টের প্রতিনিধিত্ব করে। আপনি ব্যাকএন্ডে এই টোকেনগুলি কীভাবে ব্যবহার করতে পারেন তা শিখুন।

আপনি যদি Google সাইন-ইন সমর্থন করেন তবে আপনি আপনার অ্যাপে ঘর্ষণহীন অ্যাকাউন্ট তৈরির প্রবাহ যোগ করতে One Tap ক্লায়েন্ট ব্যবহার করতে পারেন।