Вход в Google Написать

Статья здесь: https://flatteredwithflutter.com/google-signin-compose/

Мы кратко рассмотрим:

  1. Интеграция входа в Google
  2. Архитектура MVVM
  3. Использование Moshi для отправки данных
  4. (Необязательно) Проверьте, есть ли ранее авторизованный пользователь

Примечание. В этой статье предполагается, что читатель знает о Jetpack Compose.

Интеграция входа в Google

Предварительное условие: у вас должен быть проект внутри GoogleCloudPlatform.

Прежде чем начать интеграцию, мы копируем идентификатор клиента (полученный от Google Cloud Platform) и вставляем его в наш res- ›strings.xml.

Примечание. Смотрите видео выше.

<string name="google_cloud_server_client_id">YOUR_ID</string>

Настраивать

  • Установите зависимости внутри build.gradle вашего приложения
implementation 'com.google.android.gms:play-services-auth:19.2.0'
  • Теперь мы можем получить доступ к методам входа в систему с помощью Google. Давайте создадим класс (GoogleApiContract), который отвечает за вызов API Google.
  • Этот класс наследуется от ActivityResultContract, после чего мы переопределяем метод createIntent.

Чтобы настроить вход в Google для запроса идентификаторов пользователей и базовой информации профиля, создайте объект GoogleSignInOptions с параметром DEFAULT_SIGN_IN. Чтобы также запрашивать адреса электронной почты пользователей, создайте объект GoogleSignInOptions с параметром requestEmail.

override fun createIntent(context: Context, input: Int?): Intent {
 GoogleSignInOptions gso = new     GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        .requestIdToken("YOUR_ID_HERE")
        .requestEmail()
        .build();
 val intent =  GoogleSignIn.getClient(context,gso)
 return intent.signInIntent
}
  • Наконец, мы переопределяем метод parseResult.

После того, как пользователь войдет в систему, вы можете получить GoogleSignInAccount объект для пользователя в методе parseResult действия. В противном случае мы возвращаем null

override fun parseResult(resultCode: Int, intent: Intent?): Task<GoogleSignInAccount>? {
    return when (resultCode) {
        Activity.RESULT_OK -> {
            GoogleSignIn.getSignedInAccountFromIntent(intent)
        }
        else -> null
    }
}

Архитектура MVVM

Мы следуем архитектуре MVVM (Model-View-ViewModel) при реализации следующих шагов.

Модель (M)

Мы создаем модель, известную как класс данных GoogleUserModel.

data class GoogleUserModel(
    val name: String?,
    val email: String?
)

ViewModel (ВМ)

Мы создаем класс ViewModel SignInGoogleViewModel, который расширяет AndroidViewModel

class SignInGoogleViewModel(application: Application) : AndroidViewModel(application) {
    private var _userState = MutableLiveData<GoogleUserModel>()
    val googleUser: LiveData<GoogleUserModel> = _userState
    private var _loadingState = MutableLiveData(false)
    val loading: LiveData<Boolean> = _loadingState
    fun fetchSignInUser(email: String?, name: String?) {
      _loadingState.value = true
      viewModelScope.launch {
          _userState.value =
            GoogleUserModel(
              email = email,
              name = name,
            )
       }
      _loadingState.value = false
    }
    fun hideLoading() {
      _loadingState.value = false
    }
    fun showLoading() {
      _loadingState.value = true
    }
}
  • У нас есть один LiveData типа GoogleUserModel, который прослушивает изменения, если они происходят в классе модели.
  • Другой LiveData слушает загрузку, если нужно показать состояние загрузки или нет
  • У нас есть метод fetchSignInUser, который отвечает за изменение состояния нашего класса модели. Мы отмечаем состояние загрузки как истинное, когда изменение вот-вот начнется, и устанавливаем его как ложное, когда оно будет сделано.

Посмотреть (V)

Мы создаем экран аутентификации, содержащий нашу кнопку Войти в Google.

  • Наш экран аутентификации создает экземпляр SignInGoogleViewModel и отслеживает изменения в GoogleUserModel.
val mSignInViewModel: SignInGoogleViewModel =
    
viewModel(factory = SignInGoogleViewModelFactory(context.applicationContext as Application))
val state = mSignInViewModel.googleUser.observeAsState()
val user = state.value

Примечание: мы используем фабрику нашей ViewModel для создания экземпляра.

Так как наш googleUser относится к типу LiveData, мы наблюдаем за его изменениями и получаем уведомления внутри.

  • Мы создаем отдельный компонент компоновки (AuthView) и выставляем параметры как
@Composable
fun AuthView(
    onClick: () -> Unit,
    isError: Boolean = false,
    mSignInViewModel: SignInGoogleViewModel
)

При этом выполняется действие клика, которое вызывается компонентом SignInGoogle.

SignInGoogleButton(
    onClick = {
        mSignInViewModel.showLoading()
        onClick()
    },
)

Так выглядит предварительный просмотр этого компонента Compose.

  • Затем мы определяем функцию щелчка, которая будет вызываться из экрана аутентификации. Эта функция должна инициировать вызовы Google API.
val authResultLauncher =
  rememberLauncherForActivityResult(contract = GoogleApiContract()) { task ->
   try {
     val gsa = task?.getResult(ApiException::class.java)
     if (gsa != null) {
        mSignInViewModel.fetchSignInUser(gsa.email, gsa.displayName)
     } else {
        isError.value = true
     }
   } catch (e: ApiException) {
        Timber.d("Error in AuthScreen%s", e.toString())
   }
}

Мы используем rememberLauncherForActivityResult для запуска активности GoogleSignIn для результата, как указано внутри нашегоGoogleApiContract

  • Как только мы получаем ответ от нашего контракта, мы извлекаем результат, используя getResult, и если ответ не равен нулю, мы вызываем fetchSignInUser модели представления (этот метод отвечает за изменение состояния)
  • В случае ошибки мы устанавливаем для параметра ошибки значение true и соответствующим образом визуализируем пользовательский интерфейс.
  • Наконец, мы передаем параметры нашему AuthView (см. Выше)
AuthView(
    onClick = { authResultLauncher.launch(signInRequestCode) },
    isError = isError.value,
    mSignInViewModel
)

Примечание. authResultLauncher.launch - это функция, отвечающая за инициирование вызова API входа в Google.

Использование Moshi для отправки данных

После того, как пользователь войдет в систему, нам нужно отобразить данные пользователя на главном экране.

Для этого нам нужно передать данные с экрана аутентификации на главный экран.

Представляем Моши

Moshi - это современная библиотека JSON для Android и Java. Это упрощает синтаксический анализ JSON на объекты Java.

Настраивать

  • Установите зависимости внутри build.gradle вашего приложения
implementation "com.squareup.moshi:moshi:$moshi_version"
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"

Реализовать отправку и получение данных

  • Мы меняем наш маршрут Home, чтобы включить параметр user
home/{user}
  • Затем мы аннотируем наш класс данных с помощью generateAdapter и меняем его на
@JsonClass(generateAdapter = true)
data class GoogleUserModel(
    @Json(name = "name")
    val name: String?,
    @Json(name = "email")
    val email: String?
)
  • Готовим данные к отправке из Auth Screen. Получив GoogleUserModel, мы конвертируем его в JSON с помощью Moshi. Наконец, мы заменяем {user} на JSON.
val moshi = Moshi.Builder().build()
val jsonAdapter=moshi.adapter(GoogleUserModel::class.java).lenient()
val userJson = jsonAdapter.toJson(user)
navController.navigate(Destinations.Home.replace("{user}",userJson))
composable(Destinations.Home) { backStackEntry ->
  val userJson = backStackEntry.arguments?.getString("user")
  val moshi = Moshi.Builder().build()
  val jsonAdapter = moshi.adapter(GoogleUserModel::class.java)
  val userObject = jsonAdapter.fromJson(userJson!!)
  HomeView(navController, userModel = userObject!!)
}
  • Аргумент принимается внутри записи заднего стека, конвертируется в GoogleUserModel и передается как параметр в представление.

Проверить наличие ранее авторизованного пользователя

Когда пользователь входит в систему в первый раз, мы не должны снова показывать им экран входа (после того, как они вернутся в наше приложение).

  • Создаем новую функцию checkSignedInUser и вызываем ее внутри init метода нашей ViewModel.
private fun checkSignedInUser(applicationContext: Context) {
  _loadingState.value = true
  val gsa = GoogleSignIn.getLastSignedInAccount(applicationContext)
    if (gsa != null) {
        _userState.value =
         GoogleUserModel(
             email = gsa.email,
             name = gsa.displayName,
         )
    }
  _loadingState.value = false
}
  • В этой функции мы вызываем GoogleSignIn.getLastSignedInAccount и устанавливаем для загрузки значение true.

Если это возвращает объект GoogleSignInAccount (а не null), пользователь уже вошел в ваше приложение с помощью Google.

  • Наконец, мы устанавливаем загрузку на false и переходим к HomeView (из нашей ViewModel).

Source code

Другие статьи: