Время прочтения: 8 мин.
Разработка Android-приложений даже с несколькими пользователями (до 100 человек) подразумевает решение типовых задач, таких как работа с БД, аутентификация и безопасность, которые могут вызвать трудности у начинающих разработчиков. К счастью, в настоящее время существует несколько сервисов для автоматизации этих процессов.
Для успешного решения типовых задач с помощью этих сервисов, было бы хорошо иметь одну работающую инструкцию, а не кучу документации и публикаций, в которых приводятся решения лишь частично, отдельными кусками.
В данном посте я рассмотрю решение типовой задачи при разработке мобильных/web-приложений, а именно добавление аутентификации пользователей с помощью облачного сервиса. Для этого проанализирую актуальный и мощный инструмент Firebase и рассмотрю процесс подключения и реализации аутентификации по шагам.
Сравнение платформ
Сравню 4 платформы: AWS (Amazon Web Services), Firebase, Google Cloud, Microsoft Azure.

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

Обзор платформы Firebase
Firebase — это облачная платформа, которая предоставляет сервисы для разработки мобильных и веб-приложений, и решения их стандартных задач:
- Authentication – аутентификация пользователей, с помощью нескольких провайдеров (соц. сети, номер телефона, почта).
- Realtime Database и Firestore для синхронизации данных в режиме реального времени и облачного хранения данных.
- Machine Learning для добавления продвинутых функций в приложение.
- Сервисы уведомлений, которые могут использоваться для отправки целевых уведомлений пользователям на основе их поведения и предпочтений.
- Инструменты анализа, которые могут помочь понять, как пользователи взаимодействуют с приложением, а также идентифицировать и исправить проблемы производительности приложения.
- A/B-тестирование разных версий приложения и определения того, какая из них работает лучше.
- Сервисы монетизации для интеграции рекламы в приложение и получения дохода.
Хочу отметить, что у сервиса не просто так два варианта хранения данных. В чем же их отличия?
- Realtime Database — это база данных, основанная на JSON, которая использует древовидную структуру для хранения данных. Она поддерживает быструю синхронизацию данных в реальном времени между клиентскими приложениями и сервером. Простая модель данных -> простая в использовании.
- irestore — это NoSQL база данных, которая использует документы для организации данных. Она предоставляет богатый функционал при создании сложных запросов для поиска данных, а также поддерживает многопоточность. Firestore имеет более гибкую модель данных, чем Realtime Database, что позволяет лучше организовывать данные и управлять ими.

Безопасность
Firebase предоставляет чек-лист безопасности. В нем объясняется, где можно хранить данные и какие инструменты нужно подключить для улучшения надежности приложения.
При использовании внешних БД удостоверьтесь, что вы соблюдаете правила безопасности:
- Не оставляйте секретные ключи в открытом коде!
- Проверьте, что файлы конфигурации не находятся в открытом доступе.
В рамках знакомства с платформой предлагаю подключить Firebase и Authentication. В итоге получится маленький pet-проект на Android со входом в систему.
Инструкция: подключение к Firebase
Шаг 1.
Создаю приложение с готовым пустым шаблоном (empty activity). Проверяю, что все версии зависимостей приложения соответствуют актуальным. После чего удостоверяюсь, что на эмуляторе/устройстве есть сервисы Google Play, иначе ничего не заработает. Перехожу в консоль Firebase.
Шаг 2.
Начинаю процесс подключения Firebase к разрабатываемому Android-приложению . Документация предлагает два варианта подключения, выбираю быстрый и понятный. Для этого жму иконку соответствующей платформы.

Шаг 3.
Открывается меню регистрации. Находим название пакета приложения (com.example.myappnamehere). Достаю ключ SHA-1, например, через Gradle Console в Android Studio с помощью команды gradle signingReport:

Шаг 4.
Для привязки Firebase скачиваю google-services.json. Перемещаю файл конфигурации в корневой каталог модуля (уровень <project>/build.gradle) приложения.
Для того, чтобы файл и приложение увидели друг друга, устанавливаю зависимости:
buildscript {
repositories {
// Обязательно должны быть эти репозитории
google() //Репозиторий Google's Maven
mavenCentral() // Репозиторий Maven Central
dependencies {
...
// Google services Gradle plugin
classpath 'com.google.gms:google-services:4.3.15'
}
}
// buildscript должен быть выше plugins
Переходим в <project>/<app-module>:
plugins {
id 'com.android.application'
// Добавим Google services Gradle plugin
id 'com.google.gms.google-services'
...
}
Шаг 5.
Добавляю нужные зависимости в файл Gradle (обычно <project>/<app-module>/build.gradle, там же где только что добавили плагины):
dependencies {
// Импортируем Firebase BoM (https://firebase.google.com/docs/android/learn-more?hl=ru#bom)
implementation platform('com.google.firebase:firebase-bom:31.5.0')
// Добавим зависимости к нужным нам сервисам Firebase
// (в данном случае Authentication и Firestore)
implementation 'com.google.firebase:firebase-auth'
implementation 'com.google.firebase:firebase-firestore'
}
Шаг 6.
Нажимаю кнопку Build. Если приложение не удалось забилдить, то стоит проверить:
- Установлены ли правильно зависимости на всех уровнях?
- В нужном ли месте лежит файл google-services.json?
- Что говорит терминал?

Итак, после установки основы, перейду к реализации аутентификации в проекте.
Инструкция: Настройка Firebase Authentication для авторизации пользователей
Пойду самым простым путем, воспользуюсь библиотекой FirebaseUI. Там уже все приготовлено для старта:
- Элементы и переходы между экранами входа (e-mail, google-аккаунт, социальные сети).
- Кастомизируемые элементы для приведения приложения в общий стиль.
- Экраны кастомизации профиля юзера.
- Экраны привязки аккаунтов к соц. сетям.
Шаг 1.
Подключаю нужные библиотеки. Без этого никак.
dependencies {
implementation 'com.firebaseui:firebase-ui-auth:7.2.0'
// Для логина через Facebook
// Новейшие релизы Facebook SDK тут: https://goo.gl/Ce5L94
implementation 'com.facebook.android:facebook-android-sdk:8.x'
}
Шаг 2.
Включаю опции входа в консоли. Для каждого способа придется включать отдельно.

Важно знать: для подключения входа через соц. сети, придется получить App Id и API Key. Их можно получить на странице для разработчиков нужной платформы.
Шаг 3.
Для опций входа в приложение через Twitter и/или Facebook добавляем строки в strings.xml, обратите внимание на то, что нужно указать YOUR_APP_ID.
<resources>
<!-- Facebook application ID и custom URL scheme ('fb'+app ID). -->
<string name="facebook_application_id" translatable="false">YOUR_APP_ID</string>
<string name="facebook_login_protocol_scheme" translatable="false">fbYOUR_APP_ID</string>
</resources>
Как найти свой App ID?
Переходим на главную страницу консоли -> в настройки проекта -> в основных скроллим вниз -> ищем поле App ID.

После чего заново скачаю и заменю файл google-services.json.
Шаг 4.
Создаю отдельную активность LoginActivity.java для входа пользователя. Добавляем функцию ActivityResultLauncher, которая ловит ответ для FirebaseUI.
Создаю createSignInIntent, в котором указываю методы входа. Их будем создавать и запускать через signInIntent. После чего создаю функцию, в которой описываю сценарий удачного/неудачного входа в аккаунт. Если юзер зашел, то получаем объект типа FirebaseUser. При обращении к нему можно получить информацию о юзере, например, user.displayName и т.д. Если юзер не смог зайти, то ловим ошибки или возвращаемся обратно, тут уже дело за разработчиком. По умолчанию выкинет обратно на экран входа.
public class LoginActivity extends AppCompatActivity {
FirebaseAuth mAuth;
// [START auth_fui_create_launcher]
private final ActivityResultLauncher<Intent> signInLauncher = registerForActivityResult(
new FirebaseAuthUIActivityResultContract(),
new ActivityResultCallback<FirebaseAuthUIAuthenticationResult>() {
@Override
public void onActivityResult(FirebaseAuthUIAuthenticationResult result) {
onSignInResult(result);
}
}
);
// [END auth_fui_create_launcher]
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
createSignInIntent(); // вызываем функцию, создающую намерение входа
}
public void createSignInIntent() {
// [START auth_fui_create_intent]
// Перечислим способы входа
List<AuthUI.IdpConfig> providers = Arrays.asList(
new AuthUI.IdpConfig.EmailBuilder().build(),
new AuthUI.IdpConfig.PhoneBuilder().build(),
new AuthUI.IdpConfig.GoogleBuilder().build(),
new AuthUI.IdpConfig.TwitterBuilder().build());
// Создадим и запустим намерение входа
Intent signInIntent = AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(providers)
.build();
signInLauncher.launch(signInIntent);
// [END auth_fui_create_intent]
}
// [START auth_fui_result]
private void onSignInResult(FirebaseAuthUIAuthenticationResult result) {
IdpResponse response = result.getIdpResponse();
if (result.getResultCode() == RESULT_OK) {
// Вход успешен
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent); // Так как вход успешен, переходим на основную активность
} else {
// Обработка ошибки входа
assert response != null;
Log.e("LOGIN ERROR", response.getError().toString());
}
}
// [END auth_fui_result]
Шаг 5.
Не забываю создать файл лэйаута activity_login.xml для отображения активности.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoginActivity">
</androidx.constraintlayout.widget.ConstraintLayout>
Шаг 6.
Реализую MainActivity.java
public class MainActivity extends AppCompatActivity {
FirebaseAuth mAuth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView txt = findViewById(R.id.txt);
Button btn = findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
signOut();
} //Кнопка выхода из системы
});
}
@Override
public void onStart() {
super.onStart();
// Проверка, вошел ли пользователь и соответствующее обновление UI.
mAuth = FirebaseAuth.getInstance();
FirebaseUser currentUser = mAuth.getCurrentUser();
if(currentUser == null){
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
}
}
private void signOut() {
mAuth = FirebaseAuth.getInstance();
if (mAuth.getCurrentUser() != null) {
mAuth.signOut();
}
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
}
}
И лэйаут для него:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:id="@+id/txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="You are logged in!" />
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="log out" />
</LinearLayout>
В итоге, я научилась подключать Firebase к приложению, реализовала вход в приложение с помощью Firebase Authentication.

Заключение
Firebase – это разносторонний инструмент для работы с данными, анализ которого и подробный разбор процесса подключения и аутентификации позволил найти простое решение типовой задачи при разработке Android-приложений, а именно добавление аутентификации пользователей с помощью облачного сервиса.
Удачи в разработке!