Вход на Android через FirebaseUI

Эта кодовая лаборатория является частью курса Advanced Android in Kotlin. Вы получите максимальную отдачу от этого курса, если будете последовательно работать с лабораториями кода, но это не обязательно. Все кодовые лаборатории курса перечислены на целевой странице Advanced Android in Kotlin codelabs .

Введение

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

Благодаря персонализированным учетным записям пользователи могут настраивать свои действия в приложении, взаимодействовать с другими пользователями, а также сохранять и передавать свои данные, если они используют приложение на другом устройстве (например, в Интернете или на новом телефоне).

В этой лаборатории кода вы изучите основы поддержки входа в систему для вашего приложения с помощью библиотеки FirebaseUI . Среди прочего, библиотека FirebaseUI упрощает работу разработчиков, которые хотят создать процесс входа в систему, и выполняет работу по управлению учетными записями пользователей за вас.

Что вы уже должны знать

  • Основы создания приложения для Android
  • LiveData и ViewModel

Что вы узнаете

  • Как добавить Firebase в свой проект
  • Как поддерживать вход в приложение для Android
  • Как наблюдать за текущим статусом аутентификации вашего приложения
  • Как выйти из пользователей

Что ты будешь делать

  • Используйте консоль Firebase, чтобы интегрировать Firebase в свое приложение.
  • Реализуйте функцию входа в систему.
  • Добавьте настройки в приложение для пользователей, которые вошли в систему.
  • Реализовать выход пользователей из системы.

Узнайте больше о LiveData и ViewModel

Для приложения в этой кодовой лаборатории вам необходимо базовое понимание LiveData и ViewModel. Прочтите обзоры LiveData и ViewModel , если хотите получить краткий обзор этих концепций.

Вы также можете пройти курс «Разработка приложений для Android с помощью Kotlin», чтобы узнать об основных темах Android, с которыми вы столкнетесь в рамках этой лаборатории кода. Этот курс доступен как в виде курса Udacity, так и в виде курса codelabs .

В этой лабораторной работе вы создадите приложение, отображающее забавные факты об Android. Что еще более важно, в приложении будет кнопка входа/выхода . Когда пользователь входит в приложение, любой отображаемый факт Android будет включать приветствие для пользователя, чтобы добавить немного персонализации.

Скачать пример приложения можно одним из следующих способов:

Скачать ZIP

... или клонируйте репозиторий GitHub из командной строки с помощью следующей команды и переключитесь на start ветвь репозитория:

$  git clone https://github.com/googlecodelabs/android-kotlin-login

Важно: поскольку вы будете интегрировать приложение для использования Firebase, начальное приложение требует некоторой настройки, чтобы оно могло быть построено и запущено. Вы сделаете это на следующем шаге лаборатории кода.

Шаг 1. Создайте проект Firebase.

Прежде чем вы сможете добавить Firebase в свое Android-приложение, вам необходимо создать проект Firebase для подключения к вашему Android-приложению.

  1. В консоли Firebase нажмите Добавить проект.
  2. Выберите или введите имя проекта . Вы можете назвать свой проект как угодно, но постарайтесь выбрать имя, соответствующее приложению, которое вы создаете.
  3. Нажмите Продолжить .
  4. Вы можете пропустить настройку Google Analytics и выбрать вариант « Не прямо сейчас ».
  5. Нажмите «Создать проект» , чтобы завершить настройку проекта Firebase.

Шаг 2. Зарегистрируйте свое приложение в Firebase

Теперь, когда у вас есть проект Firebase, вы можете добавить в него свое Android-приложение.

  1. В центре страницы обзора проекта консоли Firebase щелкните значок Android , чтобы запустить рабочий процесс установки.
  2. Введите идентификатор приложения вашего приложения в поле имени пакета Android . Убедитесь, что вы вводите идентификатор, который использует ваше приложение, так как вы не можете добавить или изменить это значение после того, как вы зарегистрировали свое приложение в своем проекте Firebase.
  1. Идентификатор приложения иногда называют именем пакета .
  2. Найдите этот идентификатор приложения в файле Gradle своего модуля (уровня приложения), обычно это app/build.gradle (пример идентификатора: com.yourcompany.yourproject ).
  3. Введите сертификат подписи отладки SHA-1. Вы можете сгенерировать этот ключ, введя следующую команду в терминале командной строки.
keytool -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v -storepass android
  1. Щелкните Зарегистрировать приложение .

Шаг 3. Добавьте файл конфигурации Firebase в свой проект.

Добавьте файл конфигурации Firebase Android в свое приложение:

  1. Нажмите Загрузить google-services.json , чтобы получить файл конфигурации Firebase Android ( google-services.json ).
  • Вы можете снова загрузить файл конфигурации Firebase Android в любое время.
  • Убедитесь, что файл конфигурации не дополнен дополнительными символами и должен называться только google-services.json .
  1. Переместите файл конфигурации в каталог модуля (уровня приложения) вашего приложения.

Шаг 4. Настройте проект Android для включения продуктов Firebase.

  1. Чтобы включить продукты Firebase в своем приложении, добавьте плагин google-services в свои файлы Gradle.
  1. В файле Gradle корневого уровня (уровня проекта) ( build.gradle ) добавьте правила для включения подключаемого модуля Google Services. Убедитесь, что у вас также есть репозиторий Google Maven.

build.gradle

buildscript {

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
  }

  dependencies {
    // ...

    // Add the following line:
    classpath 'com.google.gms:google-services:4.3.0'  // Google Services plugin
  }
}

allprojects {
  // ...

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
    // ...
  }
}
  1. В файле Gradle вашего модуля (уровня приложения) (обычно app/build.gradle ) добавьте строку в конец файла.

приложение/build.gradle

apply plugin: 'com.android.application'

android {
  // ...
}

// Add the following line to the bottom of the file:
apply plugin: 'com.google.gms.google-services'  // Google Play services Gradle plugin

Шаг 4: Добавьте зависимость от Firebase

В этой кодовой лаборатории основная причина интеграции Firebase — возможность создавать пользователей и управлять ими. Для этого вам нужно добавить библиотеку Firebase, которая позволит вам реализовать вход в систему.

  1. Добавьте следующую зависимость в файл build.gradle (Module:app) , чтобы вы могли использовать SDK в своем приложении. SDK firebase-auth позволяет управлять аутентифицированными пользователями вашего приложения.

приложение/build.gradle:

implementation 'com.firebaseui:firebase-ui-auth:5.0.0'
  1. Синхронизируйте свой проект с файлами gradle, чтобы убедиться, что все зависимости доступны для вашего приложения. Если не появится запрос, выберите «Файл» > «Синхронизировать проект с файлами Gradle» в Android Studio или на панели инструментов.

Шаг 5. Запустите приложение и проверьте код

  1. Запустите приложение на эмуляторе или физическом устройстве, чтобы убедиться, что ваша среда успешно настроена для начала разработки.

В случае успеха вы должны увидеть на главном экране забавный факт об Android и кнопку входа в верхний левый угол. Нажатие кнопки входа пока ничего не делает.

На высоком уровне это приложение с одним действием с несколькими фрагментами. MainFragment содержит весь пользовательский интерфейс, который вы видите на экране ниже. (Вы будете работать с LoginFragment и SettingsFragment в последующей лаборатории кода.)

  1. Ознакомьтесь с кодом. В частности, обратите внимание:
  • FirebaseUserLiveData — это класс, который вы будете реализовывать для наблюдения за текущим пользователем Firebase, связанным с приложением. Вы будете использовать экземпляр FirebaseAuth в качестве точки входа для получения этой информации о пользователе на более позднем этапе.
  • MainFragment привязан к LoginViewModel . LoginViewModel — это класс, который вы будете реализовывать, чтобы использовать FirebaseUserLiveData для создания переменной authenticationState . Используя эту переменную authenticationState , MainFragment может наблюдать за значением для соответствующего обновления пользовательского интерфейса.

На этом шаге вы будете использовать консоль Firebase, чтобы настроить методы аутентификации, которые вы хотите, чтобы ваше приложение поддерживало. В этой лаборатории кода вы сосредоточитесь на том, чтобы позволить пользователям входить в систему с помощью предоставленного ими адреса электронной почты или их учетной записи Google.

  1. Перейдите в консоль Firebase . (Примечание. Если вы все еще находитесь в рабочем процессе добавления Firebase, нажмите X в левом верхнем углу, чтобы вернуться в консоль.
  2. Выберите свой проект, если вы еще не в своем проекте.
  3. Откройте левую панель навигации и выберите « Разработка» > «Аутентификация».

  1. Выберите вкладку « Метод входа » на верхней панели навигации.

  1. Нажмите на строку « Электронная почта/пароль ».
  2. Во всплывающем окне переключите переключатель « Включено » и нажмите « Сохранить ».
  3. Аналогичным образом нажмите на строку Google .
  4. Переключите переключатель « Включено », введите адрес электронной почты службы поддержки проекта и нажмите « Сохранить » .

В этой задаче вы реализуете функцию входа в систему для своих пользователей.

  1. Откройте MainFragment.kt .
  2. В MainFragment обратите внимание на auth_button . В настоящее время он не настроен для обработки любого пользовательского ввода.
  3. В onViewCreated(), добавьте onClickListener в auth_button для вызова launchSignInFlow() .

MainFragment.kt

binding.authButton.setOnClickListener { launchSignInFlow() }
  1. Найдите метод launchSignInFlow() в MainFragment.kt . В настоящее время он содержит TODO .
  2. Выполните launchSignInFlow() , как показано ниже.

MainFragment.kt

private fun launchSignInFlow() {
   // Give users the option to sign in / register with their email or Google account.
   // If users choose to register with their email,
   // they will need to create a password as well.
   val providers = arrayListOf(
       AuthUI.IdpConfig.EmailBuilder().build(), AuthUI.IdpConfig.GoogleBuilder().build()

       // This is where you can provide more ways for users to register and 
       // sign in.
   )

   // Create and launch sign-in intent.
   // We listen to the response of this activity with the
   // SIGN_IN_REQUEST_CODE 
   startActivityForResult(
       AuthUI.getInstance()
           .createSignInIntentBuilder()
           .setAvailableProviders(providers)
           .build(),
       MainFragment.SIGN_IN_REQUEST_CODE
   )
}

Это позволяет пользователям регистрироваться и входить в систему со своим адресом электронной почты или учетной записью Google. Если пользователь решит зарегистрироваться со своим адресом электронной почты, созданная им комбинация адреса электронной почты и пароля будет уникальной для вашего приложения. Это означает, что они смогут войти в ваше приложение с комбинацией адреса электронной почты и пароля, но это не означает, что они также могут войти в любое другое приложение, поддерживаемое Firebase, с теми же учетными данными.

  1. В MainFragment.kt вы можете прослушивать результат процесса входа, реализуя метод onActivityResult() , как показано ниже. Поскольку вы начали процесс входа с помощью SIGN_IN_REQUEST_CODE , вы также можете прослушать результат процесса входа, отфильтровав, когда SIGN_IN_REQUEST_CODE передается обратно в onActivityResult() . Начните с некоторых операторов журнала, чтобы узнать, успешно ли пользователь вошел в систему.

MainFragment.kt

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
   super.onActivityResult(requestCode, resultCode, data)
   if (requestCode == SIGN_IN_REQUEST_CODE) {
       val response = IdpResponse.fromResultIntent(data)
       if (resultCode == Activity.RESULT_OK) {
           // User successfully signed in
           Log.i(TAG, "Successfully signed in user ${FirebaseAuth.getInstance().currentUser?.displayName}!")
       } else {
           // Sign in failed. If response is null the user canceled the
           // sign-in flow using the back button. Otherwise check
           // response.getError().getErrorCode() and handle the error.
           Log.i(TAG, "Sign in unsuccessful ${response?.error?.errorCode}")
       }
   }
}

Теперь ваше приложение должно поддерживать регистрацию и вход пользователей!

  1. Запустите приложение и убедитесь, что при нажатии на кнопку входа открывается экран входа в систему.
  2. Теперь вы можете войти в систему, используя свой адрес электронной почты и пароль, или свою учетную запись Google.
  3. Пользовательский интерфейс не изменится после входа в систему (вы обновите пользовательский интерфейс на следующем шаге), но если все работает правильно, вы должны увидеть сообщение в журнале. Successfully signed in user ${your name}! после прохождения процедуры регистрации.
  4. Вы также можете зайти в консоль Firebase и перейти в раздел « Разработка» > «Аутентификация» > «Пользователи» , чтобы убедиться, что в приложении теперь есть один зарегистрированный пользователь.
  5. Обратите внимание, что когда пользователи создают учетную запись для вашего приложения, эта учетная запись привязывается только к вашему приложению, а не к какому-либо приложению, которое использует Firebase для входа в систему.

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

  1. Откройте класс FirebaseUserLiveData.kt , который уже создан для вас. Первое, что вам нужно сделать, это предоставить другим классам в приложении способ узнать, когда пользователь вошел в систему или вышел из нее. Однако класс пока ничего не делает, так как значение LiveData не обновляется.
  2. Поскольку вы используете библиотеку FirebaseAuth , вы можете прослушивать изменения вошедшего в систему пользователя с помощью обратного вызова FirebaseUser.AuthStateListener , который реализован для вас как часть библиотеки FirebaseUI. Этот обратный вызов запускается всякий раз, когда пользователь входит или выходит из вашего приложения.
  3. Обратите внимание, что FirebaseUserLiveData.kt определяет переменную authStateListener . Вы будете использовать эту переменную для хранения значения LiveData . Переменная authStateListener была создана, чтобы вы могли правильно запускать и прекращать прослушивание изменений в состоянии аутентификации в зависимости от состояния вашего приложения. Например, если пользователь переводит приложение в фоновый режим, приложение должно перестать прослушивать изменения состояния аутентификации, чтобы предотвратить любые потенциальные утечки памяти.
  4. Обновите authStateListener , чтобы значение вашего FirebaseUserLiveData соответствовало текущему пользователю Firebase.

FirebaseUserLiveData.kt

private val authStateListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
   value = firebaseAuth.currentUser
}
  1. Откройте LoginViewModel.kt .
  2. В LoginViewModel.kt создайте переменную authenticationState на основе объекта FirebaseUserLiveData , который вы только что реализовали. Создав эту переменную authenticationState , другие классы теперь могут запрашивать, вошел ли пользователь в систему или нет, через LoginViewModel .

LoginViewModel.kt

val authenticationState = FirebaseUserLiveData().map { user ->
   if (user != null) {
       AuthenticationState.AUTHENTICATED
   } else {
       AuthenticationState.UNAUTHENTICATED
   }
}
  1. Откройте MainFragment.kt.
  2. В MainFragment.kt observeAuthenticationState() вы можете использовать переменную authenticationState , которую вы только что добавили в LoginViewModel и соответствующим образом изменить пользовательский интерфейс. Если есть зарегистрированный пользователь, authButton должен отображать Logout .

MainFragment.kt

private fun observeAuthenticationState() {
   val factToDisplay = viewModel.getFactToDisplay(requireContext())

   viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
       when (authenticationState) {
           LoginViewModel.AuthenticationState.AUTHENTICATED -> {
               binding.authButton.text = getString(R.string.logout_button_text)
               binding.authButton.setOnClickListener {
                   // TODO implement logging out user in next step
               }

                // TODO 2. If the user is logged in, 
                 // you can customize the welcome message they see by
                 // utilizing the getFactWithPersonalization() function provided

           }
           else -> {
               // TODO 3. Lastly, if there is no logged-in user, 
                // auth_button should display Login and
                //  launch the sign in screen when clicked.
           }
       }
   })
}
  1. Если пользователь вошел в систему, вы также можете настроить приветственное сообщение, которое он увидит, используя getFactWithPersonalization() , предоставленную в MainFragment .

MainFragment.kt

binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
  1. Наконец, если нет пользователя, вошедшего в систему (когда authenticationState отличается от LoginViewModel.AuthenticationState.AUTHENTICATED ), auth_button должен отображать Login и запускать экран входа при нажатии. Также не должно быть никакой персонализации отображаемого сообщения.

MainFragment.kt

binding.authButton.text = getString(R.string.login_button_text)
binding.authButton.setOnClickListener { launchSignInFlow() }
binding.welcomeText.text = factToDisplay

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

MainFragment.kt

private fun observeAuthenticationState() {
   val factToDisplay = viewModel.getFactToDisplay(requireContext())

   viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
        // TODO 1. Use the authenticationState variable you just added 
         // in LoginViewModel and change the UI accordingly.
       when (authenticationState) {
            // TODO 2.  If the user is logged in, 
             // you can customize the welcome message they see by
             // utilizing the getFactWithPersonalization() function provided
           LoginViewModel.AuthenticationState.AUTHENTICATED -> {
               binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
               binding.authButton.text = getString(R.string.logout_button_text)
               binding.authButton.setOnClickListener {
                   // TODO implement logging out user in next step
               }
           }
           else -> {
                // TODO 3. Lastly, if there is no logged-in user, 
                 // auth_button should display Login and
                 // launch the sign in screen when clicked.
               binding.welcomeText.text = factToDisplay

               binding.authButton.text = getString(R.string.login_button_text)
               binding.authButton.setOnClickListener {
                   launchSignInFlow()
               }
           }
       }
   })
}
  1. Запустите свое приложение. Пользовательский интерфейс должен обновляться в зависимости от того, вошел ли пользователь в систему или нет. Если все работает правильно и вы вошли в систему, главный экран теперь должен приветствовать вас по имени в дополнение к отображению информации об Android. Кнопка « Войти » теперь также должна отображать « Выход» .

В этой задаче вы реализуете функцию выхода из системы.

Поскольку приложение позволяет пользователям входить в систему, оно также должно предоставлять им возможность выхода из системы. Вот пример того, как выйти из системы с помощью всего одной строки кода:

AuthUI.getInstance().signOut(requireContext())
  1. Откройте MainFragment.kt .
  2. В MainFragment.kt observeAuthenticationState() добавьте логику выхода из системы, чтобы auth_button работала правильно, когда есть пользователь, вошедший в систему. Окончательный результат метода выглядит как код ниже.

MainFragment.kt

private fun observeAuthenticationState() {
   val factToDisplay = viewModel.getFactToDisplay(requireContext())

   viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
       when (authenticationState) {
           LoginViewModel.AuthenticationState.AUTHENTICATED -> {
               binding.welcomeText.text = getFactWithPersonalization(factToDisplay)

               binding.authButton.text = getString(R.string.logout_button_text)
               binding.authButton.setOnClickListener {
                   AuthUI.getInstance().signOut(requireContext())
               }
           }
           else -> {
               binding.welcomeText.text = factToDisplay

               binding.authButton.text = getString(R.string.login_button_text)
               binding.authButton.setOnClickListener {
                   launchSignInFlow()
               }
           }
       }
   })
}
  1. Запустите приложение.
  2. Нажмите кнопку « Выход » и убедитесь, что пользователь вышел из системы, а состояние кнопки изменилось на « Войти ».

Вы можете найти окончательную версию готового приложения здесь https://github.com/googlecodelabs/android-kotlin-login .

В этой лаборатории кода вы узнали:

  • Как добавить Firebase в свой проект, добавив необходимые зависимости в файл gradle и настроив проект в консоли Firebase.
  • Как реализовать вход для вашего приложения с помощью библиотеки FirebaseUI и указать, как вы хотите, чтобы ваши пользователи могли входить в систему. Обратите внимание, что любая учетная запись, которую пользователь создает в вашем приложении, относится только к вашему приложению и не используется всеми приложениями, использующими Firebase для входа в систему.
  • Как наблюдать за текущим статусом аутентификации вашего приложения с помощью LiveData .
  • Как разлогинить пользователей.

В этой лаборатории кода были рассмотрены основы поддержки входа в приложение для Android.

В этой лаборатории кода вы разрешили пользователям регистрироваться и входить в систему, используя свой адрес электронной почты. Однако с помощью библиотеки FirebaseUI вы также можете поддерживать другие методы аутентификации, такие как вход с использованием номера телефона. Чтобы узнать больше о возможностях библиотеки FirebaseUI и о том, как использовать другие предоставляемые ею функции, ознакомьтесь со следующими ресурсами:

Чтобы узнать больше о передовых методах входа в систему, ознакомьтесь с этими другими ресурсами:

Лаборатории кода:

Документация для разработчиков Android:

Видео:

Ссылки на другие лаборатории кода в этом курсе см. на целевой странице Advanced Android in Kotlin codelabs.