FireBase는 구글에서 제공하는 서버이다. 앱에서 발생한 특정 데이터들을 저장하기 위해선 서버가 필요한데, FireBase를 사용하지 않는다면 서버를 자체적으로 구입하여 사용해야 한다. 하지만 FireBase를 사용한다면 서버를 따로 구입하지 않아도 되며, 데이터를 읽고 쓰거나, 로그인 및 회원가입이 편하다는 장점이 있다.
FireBase 콘솔 사이트로 이동하여 프로젝트 추가 버튼을 클릭한다. 이후 프로젝트 이름을 입력하고, Google 애널리틱스 사용을 허용한 후 next 버튼을 누른다. 애널리틱스 구성 단계에서는 새로운 계정을 하나 만들고, 위치를 대한민국으로 설정한다. 마지막으로 프로젝트 만들기 버튼을 누르면 FireBase를 사용할 수 있는 프로젝트가 생성된다.
프로젝트를 생성하고 나서 앱과 연결하는 작업을 해줘야 한다. 앱 추가 > 안드로이드 버튼을 누르고, android 패키지 이름을 쓴다. android 패키지 이름으로는 사용자의 앱 이름(com.example.~~~)을 입력하면 된다. 디버그 서명 인증서의 경우, 아래 사진을 따라가면 된다. 3번 과정의 경우, signingReport를 입력하면 된다.
위의 과정대로 모두 진행한 후, 엔터를 누르면 sha-1키를 얻을 수 있다. 해당 sha-1키를 디버그 서명 인증서 부분에 넣으면 된다.
이후 google-services.json 파일을 다운받은 뒤, 아래 사진에 보이는 것처럼 Android를 Project로 바꾸고, 다운받은 파일을 app폴더에 들어가도록 드래그 앤 드롭한다.
다음으로 다시 Android로 바꾼 후, Gradle Scripts 폴더에서 프로젝트 수준의 build.gradle 파일을 찾아 아래의 코드를 plugin 안에 추가한다. 프로젝트 수준의 build.gradle 파일은 옆의 괄호에 (Project: 앱 이름)이 뜬다.
plugins {
...
id 'com.google.gms.google-services' version '4.4.1' apply false
}
다음으로 앱 수준의 build.gradle 파일을 찾아 plugin과 dependencies 부분에 아래의 코드를 추가한다. 앱 수준의 build.gradle 파일은 옆의 괄호에 (Module: app)이 뜬다.
plugins {
...
id 'com.google.gms.google-services'
}
dependencies {
...
implementation platform('com.google.firebase:firebase-bom:32.7.3')
implementation 'com.google.firebase:firebase-analytics'
}
마지막으로 Sync now 버튼을 누르면 기초 작업은 마무리된다.
FireBase를 사용한다는 것은 사용자 별로 구분지어 데이터를 저장해야 한다는 의미이므로, 로그인 및 회원가입 기능이 필수로 구현되어야 한다. 만약 자체 서버를 사용한다면 아이디-비밀번호를 저장한 table이 있어야 하는데, FireBase에서는 이 기능을 간편하게 제공해준다.
Login과 Register를 위해, 해당 화면의 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">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LOGIN"
android:textSize="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.22000003" />
<EditText
android:id="@+id/loginEmail"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:ems="15"
android:inputType="textEmailAddress"
android:hint="Email"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="0.13" />
<EditText
android:id="@+id/loginPassword"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:ems="15"
android:hint="Password"
android:inputType="textPassword"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/loginEmail"
app:layout_constraintVertical_bias="0.0" />
<Button
android:id="@+id/loginButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LOGIN"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/loginPassword"
app:layout_constraintVertical_bias="0.26" />
<TextView
android:id="@+id/goRegister"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:text="Create Account"
android:textColor="#2196F3"
app:layout_constraintBottom_toTopOf="@+id/loginButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.84"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/loginPassword"
app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?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=".RegisterActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="REGISTER"
android:textSize="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.22000003" />
<EditText
android:id="@+id/registerEmail"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:ems="15"
android:inputType="textEmailAddress"
android:hint="Email"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="0.13" />
<EditText
android:id="@+id/registerPassword"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:ems="15"
android:hint="Password"
android:inputType="textPassword"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/registerEmail"
app:layout_constraintVertical_bias="0.0" />
<Button
android:id="@+id/registerButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="REGISTER"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/registerPassword"
app:layout_constraintVertical_bias="0.26" />
</androidx.constraintlayout.widget.ConstraintLayout>
추가로, 로그인이 잘 되었는지 확인하기 위해 로그인 후 띄울 main 화면도 제작하였다.
<?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=".MainActivity">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Welcome, User!"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Register 페이지에서는 아이디와 비밀번호를 입력하면 FireBase Authentication에 요청을 보내 등록하는 과정을 진행해야 한다. 해당 기능을 위해 FireBase의 Authentication 시작하기 버튼을 눌러야 한다.
시작하기 버튼을 누르고 나서, 기본 제공업체 > 이메일/비밀번호만 클릭한다. 이후 아래 그림을 따라 체크한 후 저장 버튼을 누른다.
다음으로 Android Studio로 넘어와서, 앱 수준의 build.gradle 파일의 dependencies 부분에 아래의 코드를 추가하여 Android Studio에서도 FireBase Authentication을 사용할 수 있도록 한다.
dependencies {
...
implementation 'com.google.firebase:firebase-auth'
}
Sync now 버튼을 누르면 이제 사용자 계정을 관리할 준비가 된 것이다.
FireBase의 공식 문서를 보면, 회원가입 및 로그인에 대한 함수를 FireBase에서 지원한다는 것을 알 수 있다. 해당 포스트에서는 공식 문서의 내용에 조금 더 추가하여 회원가입 기능을 구현하였다.
우선, FireBase에서 구현한 Register 함수인 createUserWithEmailAndPassword
를 살펴보자.
firebaseAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(getApplicationContext(), "회원가입 성공", Toast.LENGTH_LONG).show();
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
} else {
Toast.makeText(getApplicationContext(), "회원가입 실패", Toast.LENGTH_LONG).show();
}
}
});
firebaseAuth는 FirebaseAuth Class인데, 해당 Class는 FireBase의 Authentication의 다양한 함수들을 사용할 수 있게 한다. 위의 코드를 보면, 유저 생성을 시도할 경우 onComplete
함수가 실행되고, 회원가입이 성공할 경우(task.isSuccessful()
) 로그인 성공 메세지를 띄움과 동시에 MainActivity 화면으로 이동하게 했다. 회원가입이 실패할 경우(else
) 회원가입 실패 메세지를 띄운다.
해당 코드를 보기 좋게 바꾸기 위해, 아래와 같이 register
함수를 만들었다. email과 password를 함수의 인자로 전달하여 회원가입이 되도록 하였다.
void register(String email, String password) {
firebaseAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(getApplicationContext(), "회원가입 성공", Toast.LENGTH_LONG).show();
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
} else {
Toast.makeText(getApplicationContext(), "회원가입 실패", Toast.LENGTH_LONG).show();
}
}
});
}
이제 위에서 만든 activity_register.xml에서 register 버튼을 누르면 앞서 만든 register 함수를 실행하는 코드를 만들면 된다. 이 때, 주의해야 할 점이 몇 가지 있다.
FireBase Authentication에서 이메일/비밀번호 회원가입의 경우, 아이디가 반드시 이메일 형식을 지켜야 하며, 비밀번호가 6자리 이상이어야 한다. 따라서 해당 조건을 만족하지 않을 경우 회원가입이 불가능하며, 안내 메세지를 띄우는 것이 바람직하다.
위의 설명들을 모두 구현해보면 아래와 같다.
import android.content.Intent;
import android.os.Bundle;
import android.util.Patterns;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import java.util.regex.Pattern;
public class RegisterActivity extends AppCompatActivity {
private FirebaseAuth firebaseAuth;
private EditText editTextEmail, editTextPassword;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
firebaseAuth = FirebaseAuth.getInstance();
editTextEmail = findViewById(R.id.registerEmail);
editTextPassword = findViewById(R.id.registerPassword);
button = findViewById(R.id.registerButton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String email = editTextEmail.getText().toString();
String password = editTextPassword.getText().toString();
Pattern pattern = Patterns.EMAIL_ADDRESS;
if (email.equals("") || password.equals("")) {
Toast.makeText(getApplicationContext(), "계정과 비밀번호를 입력하세요", Toast.LENGTH_LONG).show();
}
else if (!pattern.matcher(email).matches()) {
Toast.makeText(getApplicationContext(), "이메일 형식이 맞지 않습니다.", Toast.LENGTH_LONG).show();
}
else if (password.length() < 6) {
Toast.makeText(getApplicationContext(), "비밀번호는 6자리 이상 입력해주세요", Toast.LENGTH_LONG).show();
}
else {
register(email, password);
}
}
});
}
void register(String email, String password) {
firebaseAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(getApplicationContext(), "회원가입 성공", Toast.LENGTH_LONG).show();
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
} else {
Toast.makeText(getApplicationContext(), "회원가입 실패", Toast.LENGTH_LONG).show();
}
}
});
}
}
login도 register와 마찬가지로, FireBase에서 구현해놓은 함수 signInWithEmailAndPassword
가 있다. 공식 문서를 살펴보면, 해당 함수는 아래와 같이 구현되어 있다.
firebaseAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(getApplicationContext(), "로그인 성공", Toast.LENGTH_LONG).show();
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
} else {
Toast.makeText(getApplicationContext(), "로그인 실패", Toast.LENGTH_LONG).show();
}
}
});
signInWithEmailAndPassword
함수가 호출되면, onComplete
함수가 실행되고, 로그인이 성공할 경우(task.isSuccessful()
) 로그인 성공 메세지를 띄움과 동시에 MainActivity 화면으로 이동하게 했다. 로그인이 실패할 경우(else
) 로그인 실패 메세지를 띄운다.
해당 코드를 보기 좋게 바꾸기 위해, 아래와 같이 login
함수를 만들었다. email과 password를 함수의 인자로 전달하여 로그인이 되도록 하였다.
public void login(String email, String password) {
firebaseAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(getApplicationContext(), "로그인 성공", Toast.LENGTH_LONG).show();
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
}
else {
Toast.makeText(getApplicationContext(), "로그인 실패", Toast.LENGTH_LONG).show();
}
}
});
}
이제 위에서 만든 activity_login.xml에서 login 버튼을 누르면 앞서 만든 login 함수를 실행하는 코드를 만들면 된다. 이 때, login할 때 이메일과 비밀번호가 비어있는지 확인해주는 코드를 추가해주었다. 또한, create account 버튼을 눌렀을 때 register 페이지로 넘어갈 수 있도록 버튼 연결도 해주었다.
위의 설명들을 모두 구현해보면 아래와 같다.
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
public class LoginActivity extends AppCompatActivity {
private FirebaseAuth firebaseAuth;
private FirebaseAuth.AuthStateListener firebaseAuthListener;
private EditText editTextEmail, editTextPassword;
private Button button;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
firebaseAuth = FirebaseAuth.getInstance();
editTextEmail = findViewById(R.id.loginEmail);
editTextPassword = findViewById(R.id.loginPassword);
button = findViewById(R.id.loginButton);
textView = findViewById(R.id.goRegister);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), RegisterActivity.class);
startActivity(intent);
}
});
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String email = editTextEmail.getText().toString();
String password = editTextPassword.getText().toString();
if (email.equals("") || password.equals("")) {
Toast.makeText(getApplicationContext(), "계정과 비밀번호를 입력하세요", Toast.LENGTH_LONG).show();
}
else {
login(email, password);
}
}
});
}
public void login(String email, String password) {
firebaseAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(getApplicationContext(), "로그인 성공", Toast.LENGTH_LONG).show();
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
}
else {
Toast.makeText(getApplicationContext(), "로그인 실패", Toast.LENGTH_LONG).show();
}
}
});
}
}
모두 구현한 후, 회원가입 및 로그인을 해보면 정상적으로 로그인됨을 알 수 있다. 또한 FireBase Authentication을 보면 사용자가 추가되었음을 확인할 수 있다.
앱을 개발하다 보면, 매번 로그인하는 과정이 귀찮다. 따라서 이번 챕터에서는 로그인 버튼을 꾹 누르는 등 특정 조건을 만족하면 임의의 사용자 계정으로 로그인되도록 작업을 진행할 것이다.
임의의 사용자 계정은 "a@a.com"의 아이디를 가지는 계정으로 설정할 것이며, 따라서 해당 작업을 위해 "a@a.com" 사용자를 회원가입 시키는 작업이 먼저 수행되어야 한다.
버튼을 길게 클릭한 것을 확인할 수 있는 함수는 setOnLongClickListener
으로, Android Studio에서 기본적으로 제공해준다. 사용 방법에 대한 예시 코드는 아래와 같다.
button.setOnLongClickListener(new OnLongClickListener(){
@Override
public boolean onLongClick(View v){
return true;
}
}
우리는 로그인 버튼을 길게 눌렀을 때 "a@a.com"으로 자동 로그인되도록 해야 하므로, setOnLongClickListener
함수를 아래와 같이 바꿔주면 된다.
button.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
login("a@a.com", "a@a.com");
return true;
}
});
LoginActivity의 전체 코드는 아래와 같다.
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
public class LoginActivity extends AppCompatActivity {
private FirebaseAuth firebaseAuth;
private FirebaseAuth.AuthStateListener firebaseAuthListener;
private EditText editTextEmail, editTextPassword;
private Button button;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
firebaseAuth = FirebaseAuth.getInstance();
editTextEmail = findViewById(R.id.loginEmail);
editTextPassword = findViewById(R.id.loginPassword);
button = findViewById(R.id.loginButton);
textView = findViewById(R.id.goRegister);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), RegisterActivity.class);
startActivity(intent);
}
});
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String email = editTextEmail.getText().toString();
String password = editTextPassword.getText().toString();
if (email.equals("") || password.equals("")) {
Toast.makeText(getApplicationContext(), "계정과 비밀번호를 입력하세요", Toast.LENGTH_LONG).show();
}
else {
login(email, password);
}
}
});
button.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
login("a@a.com", "a@a.com");
return true;
}
});
}
public void login(String email, String password) {
firebaseAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Toast.makeText(getApplicationContext(), "로그인 성공", Toast.LENGTH_LONG).show();
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
}
else {
Toast.makeText(getApplicationContext(), "로그인 실패", Toast.LENGTH_LONG).show();
}
}
});
}
}
실행해보면 자동으로 잘 로그인 됨을 알 수 있다.