Статьи

Как создать приложение для Android-чата с помощью Firebase

Конечный продукт
Что вы будете создавать

С Firebase создание социальных приложений в реальном времени — это прогулка по парку. И самое главное: вам не нужно писать ни одной строчки кода на стороне сервера.

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

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

Чтобы следовать этому пошаговому руководству, вам потребуется следующее:

Инструкции по настройке учетной записи Firebase и подготовке к разработке Firebase в Android Studio см. В моем учебном руководстве Начало работы с Firebase для Android здесь, на Envato Tuts +.

  • Android SDK
    Начните с Firebase для Android

Запустите Android Studio и создайте новый проект с пустым действием MainActivity .

Добавить пустую активность

Чтобы настроить проект для использования платформы Firebase, откройте окно Помощника Firebase, щелкнув Инструменты> Firebase .

При использовании платформы Firebase обычно хорошей идеей является добавление Firebase Analytics в проект. Поэтому в окне Firebase Assistant перейдите в раздел « Аналитика » и нажмите «Записать событие аналитики» .

Firebase Assistant

Затем нажмите кнопку « Подключиться к Firebase» и убедитесь, что выбрана опция « Создать новый проект Firebase» . Как только соединение установлено, нажмите кнопку « Добавить аналитику в ваше приложение» .

Нажмите Добавить аналитику в свое приложение

На данный момент проект Android Studio не только интегрирован с Firebase Analytics, но и готов использовать все другие сервисы Firebase.

В этом проекте мы будем использовать две библиотеки: пользовательский интерфейс Firebase и библиотеку поддержки дизайна Android. Поэтому откройте файл build.gradle модуля app и добавьте в него следующие зависимости compile :

1
2
compile ‘com.android.support:design:23.4.0’
compile ‘com.firebaseui:firebase-ui:0.6.0’

Нажмите кнопку « Синхронизировать сейчас» , чтобы обновить проект.

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

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

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

Следовательно, activity_main.xml должен иметь ListView , EditText и FloatingActionButton . Поместив их все в виджет RelativeLayout , ваш макет XML должен выглядеть следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?xml version=»1.0″ encoding=»utf-8″?>
<RelativeLayout xmlns:android=»https://schemas.android.com/apk/res/android»
    xmlns:app=»http://schemas.android.com/apk/res-auto»
    xmlns:tools=»http://schemas.android.com/tools»
    android:id=»@+id/activity_main»
    android:layout_width=»match_parent»
    android:layout_height=»match_parent»
    android:paddingBottom=»@dimen/activity_vertical_margin»
    android:paddingLeft=»@dimen/activity_horizontal_margin»
    android:paddingRight=»@dimen/activity_horizontal_margin»
    android:paddingTop=»@dimen/activity_vertical_margin»
    tools:context=»com.tutsplus.mychatapp.MainActivity»>
 
    <android.support.design.widget.FloatingActionButton
        android:layout_width=»wrap_content»
        android:layout_height=»wrap_content»
        android:clickable=»true»
        android:src=»@drawable/ic_send_black_24dp»
        android:id=»@+id/fab»
        android:tint=»@android:color/white»
        android:layout_alignParentBottom=»true»
        android:layout_alignParentEnd=»true»
        app:fabSize=»mini» />
 
    <android.support.design.widget.TextInputLayout
        android:layout_width=»match_parent»
        android:layout_height=»wrap_content»
        android:layout_toLeftOf=»@id/fab»
        android:layout_alignParentBottom=»true»
        android:layout_alignParentStart=»true»>
 
        <EditText
            android:layout_width=»match_parent»
            android:layout_height=»wrap_content»
            android:hint=»Input»
            android:id=»@+id/input»
            />
    </android.support.design.widget.TextInputLayout>
 
    <ListView
        android:layout_width=»match_parent»
        android:layout_height=»match_parent»
        android:layout_alignParentTop=»true»
        android:layout_alignParentStart=»true»
        android:layout_above=»@id/fab»
        android:dividerHeight=»16dp»
        android:divider=»@android:color/transparent»
        android:id=»@+id/list_of_messages»
        android:layout_marginBottom=»16dp»/>
</RelativeLayout>

Обратите внимание, что я поместил виджет EditText внутри виджета TextInputLayout . Это добавляет плавающую метку в EditText , что важно, если вы хотите придерживаться принципов дизайна материалов.

Теперь, когда макет домашнего экрана готов, мы можем перейти к созданию макета для сообщений чата, которые будут элементами внутри ListView . Начните с создания нового XML-файла макета с именем message.xml , корневым элементом которого является RelativeLayout .

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<RelativeLayout xmlns:android=»http://schemas.android.com/apk/res/android»
    android:layout_width=»match_parent» android:layout_height=»match_parent»>
 
    <TextView
        android:layout_width=»wrap_content»
        android:layout_height=»wrap_content»
        android:layout_alignParentTop=»true»
        android:layout_alignParentStart=»true»
        android:id=»@+id/message_user»
        android:textStyle=»normal|bold» />
 
    <TextView
        android:layout_width=»wrap_content»
        android:layout_height=»wrap_content»
        android:layout_alignBottom=»@+id/message_user»
        android:layout_alignParentEnd=»true»
        android:id=»@+id/message_time» />
 
    <TextView
        android:layout_width=»wrap_content»
        android:layout_height=»wrap_content»
        android:layout_below=»@+id/message_user»
        android:layout_alignParentStart=»true»
        android:layout_marginTop=»5dp»
        android:id=»@+id/message_text»
        android:textAppearance=»@style/TextAppearance.AppCompat.Body1″
        android:textSize=»18sp» />
</RelativeLayout>

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

Начните с перехода в раздел Auth консоли Firebase и включения электронной почты / пароля в качестве поставщика входа.

Не стесняйтесь также включать провайдеров входа OAuth 2.0. Тем не менее, FirebaseUI v0.6.0 без проблем поддерживает только Google Sign-In и Facebook Login.

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

Внутри onCreate() метода MainActivity проверьте, MainActivity ли пользователь в систему, проверив, является ли текущий объект FirebaseUser не null . Если значение равно null , необходимо создать и настроить объект Intent который открывает действие входа. Для этого используйте класс SignInIntentBuilder . Как только намерение будет готово, вы должны запустить startActivityForResult() используя метод startActivityForResult() .

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

Добавьте следующий код в метод onCreate() :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
if(FirebaseAuth.getInstance().getCurrentUser() == null) {
    // Start sign in/sign up activity
    startActivityForResult(
            AuthUI.getInstance()
            .createSignInIntentBuilder()
            .build(),
            SIGN_IN_REQUEST_CODE
    );
} else {
    // User is already signed in. Therefore, display
    // a welcome Toast
    Toast.makeText(this,
            «Welcome » + FirebaseAuth.getInstance()
                    .getCurrentUser()
                    .getDisplayName(),
            Toast.LENGTH_LONG)
            .show();
 
    // Load chat room contents
    displayChatMessages();
}

Как видно из приведенного выше кода, если пользователь уже вошел в систему, мы сначала отображаем Toast приветствующий пользователя, а затем вызываем метод с именем displayChatMessages . А пока просто создайте заглушку для него. Мы будем добавлять код к нему позже.

1
2
3
private void displayChatMessages() {
 
}

Как только пользователь MainActivity в систему, MainActivity получит результат в форме Intent . Чтобы справиться с этим, вы должны переопределить метод onActivityResult() .

Если код результата RESULT_OK , это означает, что пользователь успешно RESULT_OK в систему. Если это так, вы должны снова вызвать метод displayChatMessages() . В противном случае вызовите finish() чтобы закрыть приложение.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
protected void onActivityResult(int requestCode, int resultCode,
                                            Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
 
    if(requestCode == SIGN_IN_REQUEST_CODE) {
        if(resultCode == RESULT_OK) {
            Toast.makeText(this,
                    «Successfully signed in. Welcome!»,
                    Toast.LENGTH_LONG)
                    .show();
            displayChatMessages();
        } else {
            Toast.makeText(this,
                    «We couldn’t sign you in. Please try again later.»,
                    Toast.LENGTH_LONG)
                    .show();
 
            // Close the app
            finish();
        }
    }
 
}

На этом этапе вы можете запустить приложение и взглянуть на экраны входа и регистрации.

Экран регистрации для новых пользователей

По умолчанию FirebaseUI использует Smart Lock для паролей . Поэтому, как только пользователи войдут в систему, они останутся в системе, даже если приложение будет перезапущено. Чтобы разрешить пользователям выходить из системы, теперь мы добавим параметр выхода в меню переполнения MainActivity .

Создайте новый файл ресурсов меню с именем main_menu.xml и добавьте в него отдельный item , атрибут title которого установлен на Выход . Содержимое файла должно выглядеть так:

1
2
3
4
5
6
7
<menu xmlns:android=»http://schemas.android.com/apk/res/android»
    xmlns:app=»http://schemas.android.com/apk/res-auto»>
 
    <item android:title=»Sign out» app:showAsAction=»never»
        android:id=»@+id/menu_sign_out»/>
 
</menu>

Чтобы создать экземпляр ресурса меню внутри MainActivity , переопределите метод onCreateOptionsMenu() и вызовите метод onCreateOptionsMenu() объекта MenuInflater .

1
2
3
4
5
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main_menu, menu);
    return true;
}

Затем переопределите метод onOptionsItemSelected() для обработки событий щелчка в пункте меню. Внутри метода вы можете вызвать метод signOut() класса AuthUI для выхода из системы. Поскольку операция выхода выполняется асинхронно, мы также добавим к ней OnCompleteListener .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if(item.getItemId() == R.id.menu_sign_out) {
        AuthUI.getInstance().signOut(this)
            .addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    Toast.makeText(MainActivity.this,
                            «You have been signed out.»,
                            Toast.LENGTH_LONG)
                            .show();
 
                    // Close activity
                    finish();
                }
            });
    }
    return true;
}

Как только пользователь вышел, приложение должно автоматически закрыться. Вот почему вы видите вызов метода finish() в приведенном выше коде.

Чтобы сохранять сообщения чата в базе данных Firebase в реальном времени, вы должны создать модель для них. Макет сообщения чата, который мы создали ранее в этом уроке, имеет три вида. Чтобы иметь возможность заполнять эти представления, модель также должна иметь как минимум три поля.

Создайте новый класс Java с именем ChatMessage.java и добавьте в него три переменные-члена: messageText , messageUser и messageTime . Также добавьте конструктор для инициализации этих переменных.

Чтобы сделать модель совместимой с FirebaseUI, вы также должны добавить к ней конструктор по умолчанию, а также методы получения и установки для всех переменных-членов.

На этом этапе класс ChatMessage должен выглядеть следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class ChatMessage {
 
    private String messageText;
    private String messageUser;
    private long messageTime;
 
    public ChatMessage(String messageText, String messageUser) {
        this.messageText = messageText;
        this.messageUser = messageUser;
 
        // Initialize to current time
        messageTime = new Date().getTime();
    }
 
    public ChatMessage(){
 
    }
 
    public String getMessageText() {
        return messageText;
    }
 
    public void setMessageText(String messageText) {
        this.messageText = messageText;
    }
 
    public String getMessageUser() {
        return messageUser;
    }
 
    public void setMessageUser(String messageUser) {
        this.messageUser = messageUser;
    }
 
    public long getMessageTime() {
        return messageTime;
    }
 
    public void setMessageTime(long messageTime) {
        this.messageTime = messageTime;
    }
}

Теперь, когда модель готова, мы можем легко добавить новые сообщения чата в базу данных Firebase в реальном времени.

Чтобы опубликовать новое сообщение, пользователь нажмет кнопку FloatingActionButton . Поэтому вы должны добавить к нему OnClickListener .

Внутри слушателя вы должны сначала получить объект DatabaseReference с помощью getReference() класса FirebaseDatabase . Затем вы можете вызвать методы push() и setValue() чтобы добавить новые экземпляры класса ChatMessage в базу данных реального времени.

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

Соответственно добавьте следующий код в метод onCreate() :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
FloatingActionButton fab =
        (FloatingActionButton)findViewById(R.id.fab);
 
fab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        EditText input = (EditText)findViewById(R.id.input);
 
        // Read the input field and push a new instance
        // of ChatMessage to the Firebase database
        FirebaseDatabase.getInstance()
                .getReference()
                .push()
                .setValue(new ChatMessage(input.getText().toString(),
                        FirebaseAuth.getInstance()
                                .getCurrentUser()
                                .getDisplayName())
                );
 
        // Clear the input
        input.setText(«»);
    }
});

Данные в базе данных реального времени Firebase всегда хранятся в виде пар ключ-значение. Однако, если вы посмотрите на приведенный выше код, вы увидите, что мы вызываем setValue() без указания какого-либо ключа. Это разрешено только потому, что вызову setValue() предшествует вызов метода push() , который автоматически генерирует новый ключ.

FirebaseUI имеет очень удобный класс, называемый FirebaseListAdapter , который значительно сокращает усилия, необходимые для заполнения ListView используя данные, присутствующие в базе данных Firebase в реальном времени. Теперь мы будем использовать его для извлечения и отображения всех объектов ChatMessage , которые присутствуют в базе данных.

Добавьте объект FirebaseListAdapter в качестве новой переменной- MainActivity класса MainActivity .

1
private FirebaseListAdapter<ChatMessage> adapter;

Внутри displayChatMessages() инициализируйте адаптер, используя его конструктор, который ожидает следующие аргументы:

  • Ссылка на Activity
  • class интересующего вас объекта
  • Расположение элементов списка
  • Объект DatabaseReference

FirebaseListAdapter является абстрактным классом и имеет абстрактный метод populateView() , который необходимо переопределить.

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

Внутри метода вы должны сначала использовать findViewById() чтобы получить ссылки на каждый TextView , присутствующий в файле макета message.xml . Затем вы можете вызвать их методы setText() и заполнить их, используя методы получения класса ChatMessage .

На этом этапе содержимое метода displayChatMessages() должно displayChatMessages() так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
ListView listOfMessages = (ListView)findViewById(R.id.list_of_messages);
 
adapter = new FirebaseListAdapter<ChatMessage>(this, ChatMessage.class,
        R.layout.message, FirebaseDatabase.getInstance().getReference()) {
    @Override
    protected void populateView(View v, ChatMessage model, int position) {
        // Get references to the views of message.xml
        TextView messageText = (TextView)v.findViewById(R.id.message_text);
        TextView messageUser = (TextView)v.findViewById(R.id.message_user);
        TextView messageTime = (TextView)v.findViewById(R.id.message_time);
 
        // Set their text
        messageText.setText(model.getMessageText());
        messageUser.setText(model.getMessageUser());
 
        // Format the date before showing it
        messageTime.setText(DateFormat.format(«dd-MM-yyyy (HH:mm:ss)»,
                model.getMessageTime()));
    }
};
 
listOfMessages.setAdapter(adapter);

Приложение группового чата готово. Запустите его и отправьте новые сообщения, чтобы увидеть их сразу же в ListView . Если вы поделитесь приложением с друзьями, вы также сможете увидеть их сообщения, как только они отправят их.

Из этого руководства вы узнали, как использовать Firebase и FirebaseUI для создания очень простого приложения для группового чата. Вы также увидели, как легко работать с классами, доступными в FirebaseUI, чтобы быстро создавать новые экраны и реализовывать сложные функции.

Чтобы узнать больше о Firebase и FirebaseUI, обратитесь к официальной документации . Или посмотрите некоторые другие наши учебники по Firebase здесь на Envato Tuts +!

  • Android SDK
    Начните с Firebase для Android
  • Android SDK
    Android From Scratch: отчеты о сбоях Firebase
  • JavaScript
    Используйте Firebase в качестве Back-End
    Реджинальд Доусон