From 6e495c68b3c78620c09f134852038097b0fa3a0a Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Thu, 13 Feb 2025 02:02:41 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[PC-588]=20Firebase=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 1 + app/google-services.json | 29 +++++++++++++++++++ .../com/puzzle/build/logic/KotlinAndroid.kt | 14 ++++++++- build.gradle.kts | 2 ++ gradle/libs.versions.toml | 7 ++--- 5 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 app/google-services.json diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a6c05d6d..aca40292 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,6 +3,7 @@ import java.util.Properties plugins { id("piece.android.application") id("piece.android.compose") + id("com.google.firebase.crashlytics") } android { diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 00000000..dfca723b --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "226421567171", + "project_id": "piece-android", + "storage_bucket": "piece-android.firebasestorage.app" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:226421567171:android:b32a573b96c7625af3bc76", + "android_client_info": { + "package_name": "com.puzzle.piece" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyAoANdCZFkJ_WgeFDGXG_s_7iHnZuKNeno" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/build-logic/src/main/java/com/puzzle/build/logic/KotlinAndroid.kt b/build-logic/src/main/java/com/puzzle/build/logic/KotlinAndroid.kt index 3048ba41..bb2b278f 100644 --- a/build-logic/src/main/java/com/puzzle/build/logic/KotlinAndroid.kt +++ b/build-logic/src/main/java/com/puzzle/build/logic/KotlinAndroid.kt @@ -2,13 +2,17 @@ package com.puzzle.build.logic import org.gradle.api.JavaVersion import org.gradle.api.Project +import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.provideDelegate import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinCompile internal fun Project.configureKotlinAndroid() { - pluginManager.apply("org.jetbrains.kotlin.android") + with(plugins) { + apply("org.jetbrains.kotlin.android") + apply("com.google.gms.google-services") + } androidExtension.apply { compileSdk = 35 @@ -40,6 +44,14 @@ internal fun Project.configureKotlinAndroid() { } } + val libs = extensions.libs + dependencies { + val bom = libs.findLibrary("firebase-bom").get() + add("implementation", platform(bom)) + add("implementation", libs.findLibrary("firebase-analytics").get()) + add("implementation", libs.findLibrary("firebase-crashlytics").get()) + } + configureKotlin() } diff --git a/build.gradle.kts b/build.gradle.kts index 3a172601..dba92a4f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,4 +9,6 @@ plugins { alias(libs.plugins.android.test) apply false alias(libs.plugins.ktlint) alias(libs.plugins.android.library) apply false + alias(libs.plugins.google.services) apply false + alias(libs.plugins.firebase.crashlytics) apply false } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7ce48b87..04f3bff1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -74,9 +74,8 @@ androidxEspresso = "3.6.1" ## firebase googleServices = "4.4.2" -firebaseBom = "33.7.0" -crashlytics = "3.0.2" -messaging = "24.1.0" +firebaseBom = "33.9.0" +crashlytics = "3.0.3" ## OAuth # https://developer.android.com/jetpack/androidx/releases/credentials @@ -185,7 +184,7 @@ firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.r firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" } firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics" } firebase-config = { group = "com.google.firebase", name = "firebase-config-ktx" } -firebase-messaging = { module = "com.google.firebase:firebase-messaging", version.ref = "messaging" } +firebase-messaging = { module = "com.google.firebase:firebase-messaging" } [bundles] From bdd7a014a65c84f2c1ad9b85890b88cd65c7addb Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Thu, 13 Feb 2025 02:24:03 +0900 Subject: [PATCH 2/4] =?UTF-8?q?[PC-588]=20Crashlytics=20=EC=97=B0=EA=B2=B0?= =?UTF-8?q?=20=EB=B0=8F=20ErrorHelper=EB=A1=9C=20send=EB=90=9C=20Error?= =?UTF-8?q?=EB=A5=BC=20=EB=A1=9C=EA=B9=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/puzzle/data/di/DataModule.kt | 8 +++ .../data/repository/ErrorRepositoryImpl.kt | 11 ++++ .../puzzle/domain/model/error/ErrorHelper.kt | 10 ++-- .../domain/repository/ErrorRepository.kt | 5 ++ .../com/puzzle/network/di/NetworkModule.kt | 50 ++++++++++++++++++- .../source/error/DebugErrorDataSourceImpl.kt | 10 ++++ .../network/source/error/ErrorDataSource.kt | 5 ++ .../source/error/ErrorDataSourceImpl.kt | 12 +++++ .../puzzle/auth/graph/login/LoginViewModel.kt | 2 +- 9 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 core/data/src/main/java/com/puzzle/data/repository/ErrorRepositoryImpl.kt create mode 100644 core/domain/src/main/java/com/puzzle/domain/repository/ErrorRepository.kt create mode 100644 core/network/src/main/java/com/puzzle/network/source/error/DebugErrorDataSourceImpl.kt create mode 100644 core/network/src/main/java/com/puzzle/network/source/error/ErrorDataSource.kt create mode 100644 core/network/src/main/java/com/puzzle/network/source/error/ErrorDataSourceImpl.kt diff --git a/core/data/src/main/java/com/puzzle/data/di/DataModule.kt b/core/data/src/main/java/com/puzzle/data/di/DataModule.kt index c3d8b130..17fe3fed 100644 --- a/core/data/src/main/java/com/puzzle/data/di/DataModule.kt +++ b/core/data/src/main/java/com/puzzle/data/di/DataModule.kt @@ -4,11 +4,13 @@ import com.puzzle.data.TokenManagerImpl import com.puzzle.data.image.ImageResizer import com.puzzle.data.image.ImageResizerImpl import com.puzzle.data.repository.AuthRepositoryImpl +import com.puzzle.data.repository.ErrorRepositoryImpl import com.puzzle.data.repository.MatchingRepositoryImpl import com.puzzle.data.repository.ProfileRepositoryImpl import com.puzzle.data.repository.TermsRepositoryImpl import com.puzzle.data.repository.UserRepositoryImpl import com.puzzle.domain.repository.AuthRepository +import com.puzzle.domain.repository.ErrorRepository import com.puzzle.domain.repository.MatchingRepository import com.puzzle.domain.repository.ProfileRepository import com.puzzle.domain.repository.TermsRepository @@ -54,6 +56,12 @@ abstract class DataModule { matchingRepositoryImpl: MatchingRepositoryImpl, ): MatchingRepository + @Binds + @Singleton + abstract fun bindsErrorRepository( + errorRepositoryImpl: ErrorRepositoryImpl, + ): ErrorRepository + @Binds @Singleton abstract fun bindsTokenManager( diff --git a/core/data/src/main/java/com/puzzle/data/repository/ErrorRepositoryImpl.kt b/core/data/src/main/java/com/puzzle/data/repository/ErrorRepositoryImpl.kt new file mode 100644 index 00000000..1c31f48f --- /dev/null +++ b/core/data/src/main/java/com/puzzle/data/repository/ErrorRepositoryImpl.kt @@ -0,0 +1,11 @@ +package com.puzzle.data.repository + +import com.puzzle.domain.repository.ErrorRepository +import com.puzzle.network.source.error.ErrorDataSource +import javax.inject.Inject + +class ErrorRepositoryImpl @Inject constructor( + private val errorDataSource: ErrorDataSource, +) : ErrorRepository { + override suspend fun logError(exception: Throwable) = errorDataSource.logError(exception) +} diff --git a/core/domain/src/main/java/com/puzzle/domain/model/error/ErrorHelper.kt b/core/domain/src/main/java/com/puzzle/domain/model/error/ErrorHelper.kt index ede40122..1bf9b645 100644 --- a/core/domain/src/main/java/com/puzzle/domain/model/error/ErrorHelper.kt +++ b/core/domain/src/main/java/com/puzzle/domain/model/error/ErrorHelper.kt @@ -1,16 +1,20 @@ package com.puzzle.domain.model.error +import com.puzzle.domain.repository.ErrorRepository import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.receiveAsFlow import javax.inject.Inject import javax.inject.Singleton @Singleton -class ErrorHelper @Inject constructor() { +class ErrorHelper @Inject constructor( + private val errorRepository: ErrorRepository, +) { private val _errorEvent = Channel(DEFAULT_BUFFER_SIZE) val errorEvent = _errorEvent.receiveAsFlow() - fun sendError(error: Throwable) { - _errorEvent.trySend(error) + suspend fun sendError(error: Throwable) { + _errorEvent.send(error) + errorRepository.logError(error) } } diff --git a/core/domain/src/main/java/com/puzzle/domain/repository/ErrorRepository.kt b/core/domain/src/main/java/com/puzzle/domain/repository/ErrorRepository.kt new file mode 100644 index 00000000..7a10ac05 --- /dev/null +++ b/core/domain/src/main/java/com/puzzle/domain/repository/ErrorRepository.kt @@ -0,0 +1,5 @@ +package com.puzzle.domain.repository + +interface ErrorRepository { + suspend fun logError(exception: Throwable) +} diff --git a/core/network/src/main/java/com/puzzle/network/di/NetworkModule.kt b/core/network/src/main/java/com/puzzle/network/di/NetworkModule.kt index ecb840b6..d40abc07 100644 --- a/core/network/src/main/java/com/puzzle/network/di/NetworkModule.kt +++ b/core/network/src/main/java/com/puzzle/network/di/NetworkModule.kt @@ -1,7 +1,12 @@ package com.puzzle.network.di +import com.google.firebase.crashlytics.FirebaseCrashlytics +import com.puzzle.network.BuildConfig.BUILD_TYPE import com.puzzle.network.source.auth.AuthDataSource import com.puzzle.network.source.auth.AuthDataSourceImpl +import com.puzzle.network.source.error.DebugErrorDataSourceImpl +import com.puzzle.network.source.error.ErrorDataSource +import com.puzzle.network.source.error.ErrorDataSourceImpl import com.puzzle.network.source.matching.MatchingDataSource import com.puzzle.network.source.matching.MatchingDataSourceImpl import com.puzzle.network.source.profile.ProfileDataSource @@ -10,13 +15,15 @@ import com.puzzle.network.source.term.TermDataSource import com.puzzle.network.source.term.TermDataSourceImpl import dagger.Binds import dagger.Module +import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import javax.inject.Qualifier import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -abstract class NetworkModule { +abstract class NetworkBindsModule { @Binds @Singleton @@ -42,3 +49,44 @@ abstract class NetworkModule { matchingDataSourceImpl: MatchingDataSourceImpl, ): MatchingDataSource } + +@Module +@InstallIn(SingletonComponent::class) +object NetworkProvidesModule { + @Provides + @Singleton + fun provideFirebaseCrashlytics(): FirebaseCrashlytics = + FirebaseCrashlytics.getInstance() + + @Provides + @Singleton + @Debug + fun provideDebugErrorDataSource( + debugErrorDataSourceImpl: DebugErrorDataSourceImpl + ): ErrorDataSource = debugErrorDataSourceImpl + + @Provides + @Singleton + @Release + fun provideReleaseErrorDataSource( + errorDataSourceImpl: ErrorDataSourceImpl + ): ErrorDataSource = errorDataSourceImpl + + @Provides + @Singleton + fun provideErrorDataSource( + @Debug debugErrorDataSource: ErrorDataSource, + @Release releaseErrorDataSource: ErrorDataSource, + ): ErrorDataSource { + return if (BUILD_TYPE == "RELEASE") releaseErrorDataSource + else debugErrorDataSource + } +} + +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class Debug + +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class Release diff --git a/core/network/src/main/java/com/puzzle/network/source/error/DebugErrorDataSourceImpl.kt b/core/network/src/main/java/com/puzzle/network/source/error/DebugErrorDataSourceImpl.kt new file mode 100644 index 00000000..1de0f7ec --- /dev/null +++ b/core/network/src/main/java/com/puzzle/network/source/error/DebugErrorDataSourceImpl.kt @@ -0,0 +1,10 @@ +package com.puzzle.network.source.error + +import android.util.Log +import javax.inject.Inject + +class DebugErrorDataSourceImpl @Inject constructor() : ErrorDataSource { + override suspend fun logError(exception: Throwable) { + Log.e("DebugErrorDataSource", exception.stackTraceToString()) + } +} diff --git a/core/network/src/main/java/com/puzzle/network/source/error/ErrorDataSource.kt b/core/network/src/main/java/com/puzzle/network/source/error/ErrorDataSource.kt new file mode 100644 index 00000000..17c77f05 --- /dev/null +++ b/core/network/src/main/java/com/puzzle/network/source/error/ErrorDataSource.kt @@ -0,0 +1,5 @@ +package com.puzzle.network.source.error + +interface ErrorDataSource { + suspend fun logError(exception: Throwable) +} diff --git a/core/network/src/main/java/com/puzzle/network/source/error/ErrorDataSourceImpl.kt b/core/network/src/main/java/com/puzzle/network/source/error/ErrorDataSourceImpl.kt new file mode 100644 index 00000000..f322174d --- /dev/null +++ b/core/network/src/main/java/com/puzzle/network/source/error/ErrorDataSourceImpl.kt @@ -0,0 +1,12 @@ +package com.puzzle.network.source.error + +import com.google.firebase.crashlytics.FirebaseCrashlytics +import javax.inject.Inject + +class ErrorDataSourceImpl @Inject constructor( + private val firebaseCrashlytics: FirebaseCrashlytics, +) : ErrorDataSource { + override suspend fun logError(exception: Throwable) { + firebaseCrashlytics.recordException(exception) + } +} diff --git a/feature/auth/src/main/java/com/puzzle/auth/graph/login/LoginViewModel.kt b/feature/auth/src/main/java/com/puzzle/auth/graph/login/LoginViewModel.kt index 2a883847..ec40b828 100644 --- a/feature/auth/src/main/java/com/puzzle/auth/graph/login/LoginViewModel.kt +++ b/feature/auth/src/main/java/com/puzzle/auth/graph/login/LoginViewModel.kt @@ -72,7 +72,7 @@ class LoginViewModel @AssistedInject constructor( .also { setState { copy(isLoading = false) } } } - internal fun loginFailure(throwable: Throwable) { + internal fun loginFailure(throwable: Throwable) = viewModelScope.launch { setState { copy(isLoading = false) } errorHelper.sendError(throwable) } From 81d04a9d509e681547da19f86df82ac85e374da7 Mon Sep 17 00:00:00 2001 From: tgyuuAn Date: Thu, 13 Feb 2025 02:25:52 +0900 Subject: [PATCH 3/4] =?UTF-8?q?[PC-588]=20GitIgnore=EC=97=90=20GoogleServi?= =?UTF-8?q?ceJson=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/.DS_Store | Bin 6148 -> 0 bytes app/.gitignore | 3 ++- app/google-services.json | 29 ----------------------------- 3 files changed, 2 insertions(+), 30 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/.DS_Store delete mode 100644 app/google-services.json diff --git a/.github/ISSUE_TEMPLATE/.DS_Store b/.github/ISSUE_TEMPLATE/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Thu, 13 Feb 2025 02:35:42 +0900 Subject: [PATCH 4/4] =?UTF-8?q?[PC-588]=20CI/CD=EC=97=90=20GoogleServicesJ?= =?UTF-8?q?son=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/android_cd.yml | 3 +++ .github/workflows/android_ci.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/android_cd.yml b/.github/workflows/android_cd.yml index e1269f47..93b11e90 100644 --- a/.github/workflows/android_cd.yml +++ b/.github/workflows/android_cd.yml @@ -37,6 +37,9 @@ jobs: echo "PIECE_PROD_BASE_URL=${{ secrets.PIECE_PROD_BASE_URL }}" >> local.properties echo "GOOGLE_WEB_CLIENT_ID=${{ secrets.GOOGLE_WEB_CLIENT_ID }}" >> local.properties + - name: Create google-services.json + run: echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > ./app/google-services.json + - name: Build with Gradle run: ./gradlew assembleDebug --build-cache --stacktrace diff --git a/.github/workflows/android_ci.yml b/.github/workflows/android_ci.yml index 6077ce6d..ccca1733 100644 --- a/.github/workflows/android_ci.yml +++ b/.github/workflows/android_ci.yml @@ -40,6 +40,9 @@ jobs: echo "PIECE_PROD_BASE_URL=${{ secrets.PIECE_PROD_BASE_URL }}" >> local.properties echo "GOOGLE_WEB_CLIENT_ID=${{ secrets.GOOGLE_WEB_CLIENT_ID }}" >> local.properties + - name: Create google-services.json + run: echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > ./app/google-services.json + - name: Build with Gradle run: ./gradlew assembleDebug --build-cache --stacktrace