Использование Firebase для создания простого мессенджера...

Preview:

Citation preview

Использование Firebase для создания простого

мессенджера

Автор: Ахбулатов Алидибир

Исходники на GitHub: https://github.com/akhbulatov/messengeralda

Базовые требования к мессенджеру

Основные функции:

1. Аутентификация пользователя через аккаунты Google или Facebook2. Отображение списка контактов3. Отправка сообщений пользователям4. Отображение уведомлений при получении нового сообщения5. Отображение списка чатов

Какие инструменты Firebase нам потребуются?1. Аутентификация (Authentication)2. База данных реального времени (Realtime Database)3. Облачная отправка сообщений (Cloud Messaging)4. Уведомления (Notifications)

Библиотека Firebase UI

Firebase UI - это библиотека, которая упрощает реализацию аутентификации, базы данных реального времени и файлового хранилища в приложении.

Firebase UI опубликована как коллекция библиотек. Каждая библиотека имеет зависимость от соответствующей библиотеки из Firebase SDK.

В приложении достаточно включить только соответствующую библиотеку Firebase UI.

Совместимость с библиотеками Firebase / Play Services

Firebase UI библиотеки имеют зависимости с соответствующими библиотеками Firebase SDK:

firebase-ui-auth

|--- com.google.firebase:firebase-auth

|--- com.google.android.gms:play-services-auth

firebase-ui-database

|--- com.google.firebase:firebase-database

firebase-ui-storage

|--- com.google.firebase:firebase-storage

Соответствие версий:

Firebase UI Firebase/Play Services

1.0.0 9.8.0

0.6.2 9.8.0

0.6.1 9.6.1

0.6.0 9.6.0

0.5.3 9.4.0

0.4.4 9.4.0

0.4.3 9.2.1

Подключение библиотек Firebase UIВ app/build.gradle

dependencies {

// FirebaseUI Database только

compile 'com.firebaseui:firebase-ui-database:0.6.1'

// FirebaseUI Auth только

compile 'com.firebaseui:firebase-ui-auth:0.6.1'

// FirebaseUI Storage только

compile 'com.firebaseui:firebase-ui-storage:0.6.1'

// Включает все FirebaseUI библиотеки выше

compile 'com.firebaseui:firebase-ui:0.6.1'

}

Аутентификация1. Добавьте зависимость Gradle:

dependencies {

// Используется библиотека Firebase UI compile 'com.firebaseui:firebase-ui-auth:0.6.1'

}

2. Включите в консоли Firebase вход в приложение через аккаунты Google и Facebook (рис. 1).

Рис. 1.

Вход через GoogleДля приложений Android необходимо перейти в “настройках проекта” и добавить “контрольную сумму SHA1”.

Получить контрольную сумму SHA1:

1. Перейти в консоли в папку jdk1.x.x_xx/bin. Например, C:\Java\jdk1.8.0_51\bin

2. Ввести команду keytool -list -v -keystore c:\users\user_name\.android\debug.keystore -alias androiddebugkey -storepass android -keypass android

3. Скопировать SHA1 из консоли (рис. 2) и вставить его в поле “Контрольные суммы сертификатов SHA-1” в настройках проекта (рис. 3).

Рис. 2. Рис. 3.

Вход через Facebook1. Создать аккаунт разработчика на https://developers.facebook.com 2. Перейти в “Мои приложения”, затем нажать “Добавить новое

приложение” и ввести данные, как показано на рис. 4.

Рис. 4

Вход через FacebookПосле создания приложения, необходимо добавить продукт. Выбираем “Вход через Facebook” (рис. 5).

Рис. 5

Идентификатор и секретный ключ (рис. 6) с панели приложения вставляем в поля входа через Facebook в Firebase консоли (рис. 7).

Рис 6. Рис 7.

Вход через FacebookВ настройках приложения нажимаем “Добавить платформу” и в появившемся окне выбираем Android. Далее заполняем поля (рис. 8)

Рис. 8

Вход через FacebookТакже нужно добавить ключевой хэш-адрес, но для начала необходимо его получить:

1. Загрузить и установить openssl-0.9.8e.zip (X64 для 64-битных Windows)2. Создать папку OpenSSL по пути C:\ и извлечь содержимое архива в нее3. Перейти по пути jdk1.xx_x\bin и ввести следующую команду: keytool -exportcert -alias

androiddebugkey -keystore "C:\Users\user_name\.android\debug.keystore"|"C:\OpenSSL\bin\openssl" sha1 -binary|"C:\OpenSSL\bin\openssl" base64

4. Будет спрошен пароль. Вводим “android” без кавычек5. Сгенерированный хэш-код (рис. 9) вставляем в поле “Ключевой хэш-адрес” (рис. 8)

Рис. 9

Вход через FacebookНажимаем на левой панели “Вход через Facebook” под разделом “Продукты” и вставляем URL-адрес (рис. 12) в последнее поле с рис. 7.

Рис. 12

И последнее: добавьте строку facebook_application_id в ресурсы приложения:

<resources> <!-- ... --> <string name="facebook_application_id" translatable="false">APP_ID</string></resources>

Аутентификация в приложенииПроверить при запуске приложения был ли выполнен вход пользователем:

FirebaseAuth auth = FirebaseAuth.getInstance();

if (auth.getCurrentUser() != null) {

// Вход уже выполнен

showMain();

finish();

} else {

// Вход еще не выполнен

showSignInUI();

}

Реализация входаРеализация метода showSignInUI, отображающий варианты входа через Google или Facebook:

private void showSignInUI() {

startActivityForResult(AuthUI.getInstance()

.createSignInIntentBuilder()

.setProviders(AuthUI.FACEBOOK_PROVIDER,

AuthUI.GOOGLE_PROVIDER)

.setTheme(R.style.AppTheme_SignIn)

.build(), RC_SIGN_IN);

}

Реализация метода onActivityResult, который проверяет был ли выполне вход:

protected void onActivityResult(int requestCode, int

resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (requestCode == RC_SIGN_IN) {

if (resultCode == RESULT_OK) {

// Пользователь выполнил вход

showMain();

finish();

} else {

// Пользователь не выполнил вход

finish();

}

}

}

Выход пользователя из аккаунтаРеализация выхода при клике:

public void onClick(View v) {

if (v.getId() == R.id.sign_out) {

AuthUI.getInstance()

.signOut(this)

.addOnCompleteListener(new OnCompleteListener<Void>() {

public void onComplete(@NonNull Task<Void> task) {

// Пользователь вышел из своего аккаунта

startActivity(new Intent(MainActivity.this, SignInActivity.class));

finish();

}

});

}

}

Кастомизация UIДобавить фоновый рисунок на экран входа:

<style name="AppTheme.SignIn" parent="AppTheme">

<item name="android:gravity">bottom</item>

<item name="android:windowBackground">

@drawable/img_bg_sign_in</item>

<item name="android:windowTranslucentStatus"

tools:targetApi="kitkat">true</item>

</style>

Перевод текста на кнопках входа:

<string name="sign_in_with_google">Войти через

Google</string>

<string name="sign_in_with_facebook">Войти через

Facebook</string>

Подключение к базе данных

Добавьте зависимость в app/build.gradle:

// Если используется библиотека Firebase UI

compile 'com.firebaseui:firebase-ui-database:0.6.1'

// Если используется Firebase SDK

compile 'com.google.firebase:firebase-database:9.6.1'

Сохранение авторизованных пользователей в БДРеализация:

private void storeUserData() {

DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference();

FirebaseUser fbUser = FirebaseAuth.getInstance().getCurrentUser();

User user = new User(

fbUser.getUid(),

fbUser.getDisplayName(),

fbUser.getEmail(),

fbUser.getPhotoUrl().toString());

// Записать пользовательские данные по узлу users/uid

dbRef.child("users").child(fbUser.getUid()).setValue(user);

}

Отображение списка контактовДля отображения контактов с помощью Firebase UI необходимо:

1. Java класс User, представляющий объекты пользователя в БД2. Адаптер (ContactAdapter), считывающий список объектов пользователей из БД

Так будет выглядеть список авторизованных пользователей в БД (рис. 13) :

Рис.13

Класс Userpublic class User { private String mUid; private String mName; private String mEmail; private String mPhotoUrl; // Firebase требует наличие пустого конструктора public User() { }

public User(String uid, String name, String email, String photoUrl) { mUid = uid; mName = name; mEmail = email; mPhotoUrl = photoUrl; }

public String getUid() { return mUid; } ….}

Класс User. Некоторые моменты

На заметку:

● Необходим конструктор без параметров для сохранения объекта в БД Firebase с помощью метода setValue

● Firebase присваивает полям объекта (JSON) в БД те же названия, что имеются у параметров конструктора класса

● Желательно добавить методы-геттеры

Использование Firebase UI для заполнения RecyclerViewЧто необходимо:

1. Создать кастомный ViewHolder класс2. Создать кастомный подкласс FirebaseRecyclerAdapter

Код ContactViewHolder:

public static class ContactViewHolder extends RecyclerView.ViewHolder {

public ImageView imageContactAvatar;

public TextView textContactName;

public ContactViewHolder(View itemView) {

super(itemView);

imageContactAvatar = (ImageView) itemView.findViewById(R.id.image_user_avatar);

textContactName = (TextView) itemView.findViewById(R.id.text_user_name);

}

}

Использование Firebase UI для заполнения RecyclerView

Код ContactAdapter:

public class ContactAdapter extends FirebaseRecyclerAdapter<User, ContactAdapter.ContactViewHolder> {

public ContactAdapter(DatabaseReference ref) {

super(User.class, R.layout.item_contact, ContactViewHolder.class, ref);

}

@Override

protected void populateViewHolder(ContactViewHolder viewHolder, User model, int position) {

// Отобразить фото прафиля

Picasso.with(viewHolder.itemView.getContext())

.load(model.getPhotoUrl())

.into(viewHolder.imageContactAvatar);

// Отобразить имя профиля

viewHolder.textContactName.setText(model.getName());

}

}

Использование Firebase UI для заполнения RecyclerView

Код с экрана, отображающего список контактов:

DatabaseReference usersRef = FirebaseDatabase.getInstance().getReference().child("users");

RecyclerView contactList = (RecyclerView) findViewById(R.id.recycler_list);

contactList.setHasFixedSize(true);

contactList.setLayoutManager(new LinearLayoutManager(this));

contactAdapter = new ContactAdapter(usersRef);

contactList.setAdapter(contactAdapter);

Прерывание прослушивания изменений списка в БД

При уничтожении экрана (вызов метода onDestroy) необходимо прервать прослушивание изменений списка пользователей в БД Firebase.

Код:

@Override

protected void onDestroy() {

super.onDestroy();

contactAdapter.cleanup();

}

Отправка сообщенияКод, выполняющийся после нажатия на кнопку “Отправить”:

FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();DatabaseReference mMessagesRef = FirebaseDatabase.getInstance().getReference() .child("messages") .child(user.getUid()) .child(mListener.getReceiverUid());

String message = editMessage.getText().toString().trim();if (message.equals("")) {

Toast.makeText(getActivity(), R.string.error_empty_message, Toast.LENGTH_SHORT) .show();} else { // Отправка сообщения mMessagesRef.push().setValue(new Message(message)); editMessage.setText("");}

Класс Message

public class Message { private String mMessage;

// Firebase требует наличие пустого конструктора public Message() { }

public Message(String message) { mMessage = message; }

public String getMessage() { return mMessage; }

public void setMessage(String message) { mMessage = message; }}

Создание чата// Создание объекта чата с данными

Chat chat = new Chat();

chat.setUid(mListener.getReceiverUid());

chat.setName(mListener.getReceiverName());

chat.setPhotoUrl(mListener.getReceiverPhotoUrl());

chat.setLastMessage(message);

FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();

DatabaseReference chatRef = FirebaseDatabase.getInstance().getReference()

.child("chats")

.child(user.getUid())

.child(mListener.getReceiverUid());

// Создание чата

chatRef.setValue(chat);

Структура чата в БД Firebase

Рис 14.

Структура данных в БДОсновные рекомендации:

● Избегайте глубоких вложенных данных● Разделяйте данные по узлам

Рис. 15 Рис. 16

Дополнение

Метод push создает сгенерированное уникальное число для добавляемого дочернего элемента. Например: добавление сообщений

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

FirebaseDatabase.getInstance().setPersistenceEnabled(true);

Recommended