이번엔 Firebase를 이용하여 Serverless 하게 데이터를 저장하는 방법을 알아보려고 한다.
내 프로젝트와 Firebase를 연동하는 방법을 담은 글들은 많으니 바로 코드로 넘어가려고 한다.
시작하기 전에 Firebase에서 제공하는 서비스 중 Authentication과 Firestore Database를 사용할 예정이다.
내 버스 도착 정보를 저장하기 위해선 User를 구분해야 하기 때문에 Authentication을 통해 회원가입과 로그인을 진행하고, 데이터를 저장하기 위해 Firestore Database를 사용한다.
이 프로젝트에선 Hilt와 Repository Pattern을 사용하니 관련 코드를 먼저 작성한다.
@Module
@InstallIn(SingletonComponent::class)
object FirebaseModule {
@Provides
@Singleton
fun provideFirebaseAuthInstance(): FirebaseAuth {
return FirebaseAuth.getInstance()
}
@Provides
@Singleton
fun provideFireStoreInstance(): FirebaseFirestore {
return FirebaseFirestore.getInstance()
}
}
interface FirebaseRepository {
suspend fun signIn(email: String, passwd: String): Boolean
suspend fun createAccount(email: String, passwd: String): Boolean
suspend fun insertMyBookmark(stationID: String, routeID: String, routeNm: String): Boolean
suspend fun getMyBookmark(): QuerySnapshot
suspend fun deleteBookmark(busNm: String): Boolean
}
class FirebaseRepositoryImpl @Inject constructor(
private val auth: FirebaseAuth,
private val db: FirebaseFirestore,
private val imageStorage: FirebaseStorage
) : FirebaseRepository {
private val currentTime: Long = System.currentTimeMillis()
private val dateFormat = SimpleDateFormat("yy-MM-dd_HH:mm:ss")
override suspend fun signIn(email: String, passwd: String): Boolean {
return try {
val authResult = auth.signInWithEmailAndPassword(email, passwd).await()
(authResult.user != null)
} catch (e: Exception) {
false
}
}
override suspend fun createAccount(email: String, passwd: String): Boolean {
return try {
val authResult = auth.createUserWithEmailAndPassword(email, passwd).await()
(authResult.user != null)
} catch (e: Exception) {
false
}
}
override suspend fun insertMyBookmark(
stationID: String,
routeID: String,
routeNm: String
): Boolean {
return try {
val bookmarkEntity = BookmarkEntity(
stationID = stationID,
routeID = routeID,
routeNm = routeNm
)
auth.currentUser?.let {
db.collection(it.uid)
.document(dateFormat.format(currentTime))
.set(bookmarkEntity).await()
}
true
} catch (e: Exception) {
false
}
}
override suspend fun getMyBookmark(): QuerySnapshot {
val dbResult = auth.currentUser?.let {
db.collection(it.uid)
.get()
.await()
}
return dbResult!!
}
override suspend fun deleteBookmark(busNm: String): Boolean {
return try {
val dbResult = auth.currentUser?.let {
db.collection(it.uid)
.whereEqualTo("routeNm", busNm)
.get()
.await()
}
if (dbResult != null) {
for (result in dbResult) {
result.reference.delete()
}
}
true
} catch (e: Exception) {
false
}
}
}
ViewModel의 목적에 따라 Repository에 작성한 함수를 사용하면 된다.
위에서 작성한 fireBaseRepositoryImpl를 주입해주면 된다.
@HiltViewModel
class BusArrivalViewModel @Inject constructor(
private val firebaseRepository: FirebaseRepositoryImpl
) : ViewModel(){
private val _insertResult = MutableLiveData<Boolean>()
val insertResult: LiveData<Boolean>
get() = _insertResult
fun insertMyBookmark(stationID: String, routeID: String, routeNm: String) {
viewModelScope.launch {
try {
_insertResult.value = firebaseRepository.insertMyBookmark(stationID, routeID, routeNm)
} catch (e: Exception) {
Log.e("InsertBookmarkErr", e.toString())
}
}
}
}
이렇게 미리 Repository에 사용할 함수만 작성해 놓으면 원하는 ViewModel에서 아주 간단하게 Firebase가 제공하는 서비스들을 사용할 수가 있다.
갤럭시 워치에 버스 도착 정보를 띄우자! 시리즈를 처음부터 지금까지 따라왔다면 일단 스마트폰 용 앱은 완성이 됐다.(사실 아직 불안정하고 UI도 보기 좋지 않아서 많은 보완을 해야한다...)
버스언제와 Git
다음은 이 앱을 통해 즐겨찾기에 추가한 내 버스 도착 정보를 갤럭시 워치에서 확인할 수 있는 갤럭시 워치 앱을 만드는 법을 포스팅할 예정이다.
덕분에 좋은 정보 얻어갑니다, 감사합니다.