Вход в Google Написать
Статья здесь: https://flatteredwithflutter.com/google-signin-compose/
Мы кратко рассмотрим:
- Интеграция входа в Google
- Архитектура MVVM
- Использование Moshi для отправки данных
- (Необязательно) Проверьте, есть ли ранее авторизованный пользователь
Примечание. В этой статье предполагается, что читатель знает о 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
Другие статьи: