Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] 앰플리튜드를 도입합니다. #140

Merged
merged 13 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />


<application
android:name=".app.HongikYeolgong2Application"
android:allowBackup="true"
Expand Down
1 change: 1 addition & 0 deletions core/designsystem/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ android {

dependencies {
implementation(libs.androidx.appcompat)
implementation(projects.core.tracker)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.teamhy2.designsystem.util.compositionlocal

import androidx.compose.runtime.compositionLocalOf
import com.teamhy2.tracker.Tracker

val LocalTracker =
compositionLocalOf<Tracker> {
object : Tracker {
override fun trackEvent(
eventName: String,
properties: Map<String, Any?>,
) {
}
}
}
1 change: 1 addition & 0 deletions core/tracker/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
25 changes: 25 additions & 0 deletions core/tracker/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties

plugins {
id("hongikyeolgong2.android.library")
}

android {
namespace = "com.teamhy2.hongikyeolgong2.tracker"

defaultConfig {
buildConfigField("String", "AMPLITUDE_KEY", getApiKey("AMPLITUDE_KEY"))
}

buildFeatures {
buildConfig = true
}
}

dependencies {
implementation(libs.amplitude)
}

fun getApiKey(propertyKey: String): String {
return gradleLocalProperties(rootDir, providers).getProperty(propertyKey)
}
Empty file added core/tracker/consumer-rules.pro
Empty file.
2 changes: 2 additions & 0 deletions core/tracker/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />
8 changes: 8 additions & 0 deletions core/tracker/src/main/java/com/teamhy2/tracker/Tracker.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.teamhy2.tracker

interface Tracker {
fun trackEvent(
eventName: String,
properties: Map<String, Any?> = emptyMap(),
)
}
Comment on lines +3 to +8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추상화 좋습니다.
하지만 properties가 다른 tracker를 연결할 때 걸림돌이 되진 않을까여?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기본값을 명시해서 다른 tracker들은 선택적으로 사용할 수 있도록 설계하였는데 다른 tracker들이 어떤 형태를 가지는지 모르겠어서 예상이 잘 가지 않네요 일단 이 부분은 knownIssue로 가져가는 것을 제안드립니다!

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.teamhy2.tracker.amplitude

import android.content.Context
import com.amplitude.android.Amplitude
import com.amplitude.android.Configuration
import com.amplitude.android.autocaptureOptions
import com.teamhy2.tracker.Tracker

class AmplitudeTracker(context: Context, apiKey: String) : Tracker {
private val amplitude =
Amplitude(
Configuration(
apiKey = apiKey,
context = context,
autocapture =
autocaptureOptions {
+sessions
+appLifecycles
+screenViews
},
),
)

override fun trackEvent(
eventName: String,
properties: Map<String, Any?>,
) {
amplitude.track(eventName, properties)
}
}
24 changes: 24 additions & 0 deletions core/tracker/src/main/java/com/teamhy2/tracker/di/TrackerModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.teamhy2.tracker.di

import android.content.Context
import com.teamhy2.hongikyeolgong2.tracker.BuildConfig
import com.teamhy2.tracker.Tracker
import com.teamhy2.tracker.amplitude.AmplitudeTracker
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object TrackerModule {
@Provides
@Singleton
fun provideTracker(
@ApplicationContext context: Context,
): Tracker {
return AmplitudeTracker(context, BuildConfig.AMPLITUDE_KEY)
}
}
4 changes: 4 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ googleFirebaseCrashlytics = "3.0.2"
datastore = "1.0.0"
firebaseFirestoreKtx = "25.0.0"
coil = "2.3.0"
amplitude = "1.+"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+는 뭔가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앰플리튜드 공식문서에 이렇게 적혀있어서 그대로 사용했는데 알아서 최신버전을 찾는거 같아요

Copy link
Contributor Author

@librarywon librarywon Nov 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+가 *동적 버전 지정이라고 해서 최신 버전을 받아오는 것이 맞습니다.


# HTTP
okhttp = "4.11.0"
Expand Down Expand Up @@ -136,6 +137,9 @@ androidx-credentials = { module = "androidx.credentials:credentials", version.re
androidx-credentials-play-services-auth = { module = "androidx.credentials:credentials-play-services-auth", version.ref = "credentials" }
googleid = { module = "com.google.android.libraries.identity.googleid:googleid", version.ref = "googleid" }

# Amplitude
amplitude = { module = "com.amplitude:analytics-android", version.ref = "amplitude" }

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
Expand Down
1 change: 1 addition & 0 deletions main-presentation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dependencies {

implementation(projects.core.notification)
implementation(projects.core.remote)
implementation(projects.core.tracker)

implementation(projects.calendarPresentation)
implementation(projects.calendarDomain)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.teamhy2.designsystem.common.HY2Dialog
import com.teamhy2.designsystem.common.HY2TimePicker
import com.teamhy2.designsystem.ui.theme.HY2Theme
import com.teamhy2.designsystem.util.compositionlocal.LocalShowSnackBar
import com.teamhy2.designsystem.util.compositionlocal.LocalTracker
import com.teamhy2.feature.home.component.InitTimerComponent
import com.teamhy2.feature.home.component.RunningTimerComponent
import com.teamhy2.feature.home.component.WeeklyStudyCalendar
Expand Down Expand Up @@ -59,6 +60,7 @@ fun HomeRoute(
val timerState by timerViewModel.timerState.collectAsStateWithLifecycle()
val duration by timerViewModel.durationHour.collectAsStateWithLifecycle()
val localShowSnackBar = LocalShowSnackBar.current
val tracker = LocalTracker.current

homeViewModel.updateTimerStateFromTimerViewModel(timerState)

Expand All @@ -76,6 +78,7 @@ fun HomeRoute(
}

LaunchedEffect(true) {
tracker.trackEvent("Home")
homeViewModel.errorFlow.collectLatest { throwable ->
localShowSnackBar.showSnackBar(throwable.message)
}
Expand Down Expand Up @@ -110,6 +113,7 @@ fun HomeRoute(
startTime = updatedSelectedTime,
duration = timerViewModel.durationHour.value,
)
tracker.trackEvent("StudyStartButton")
},
onCancelled = {
homeViewModel.updateTimePickerVisibility(false)
Expand Down Expand Up @@ -145,6 +149,7 @@ fun HomeRoute(
startTime = LocalDateTime.now(),
duration = timerViewModel.durationHour.value,
)
tracker.trackEvent("StudyExtendButton")
},
onDismiss = {
homeViewModel.updateStudyRoomExtendDialogVisibility(false)
Expand All @@ -165,6 +170,7 @@ fun HomeRoute(
homeViewModel.updateTimerRunning(false)
homeViewModel.saveStudyDay(false)
homeViewModel.stopTimerService()
tracker.trackEvent("StudyEndButton")
},
onDismiss = {
homeViewModel.updateStudyRoomEndDialogVisibility(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class MainNotificationHandler
override fun buildServiceNotification(): Notification {
return NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
.setContentTitle("홍익열공이 열공중")
.setContentText("열람실을 이용중이에요!")
.setContentText("지금 열람실을 이용중이에요!")
.setSmallIcon(R.drawable.ic_status_bar_logo)
.setOngoing(true)
.setContentIntent(pendingIntent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,24 @@ import com.google.accompanist.permissions.rememberPermissionState
import com.teamhy2.designsystem.common.HY2LoadingScreen
import com.teamhy2.designsystem.ui.theme.HY2Theme
import com.teamhy2.designsystem.util.compositionlocal.LocalShowSnackBar
import com.teamhy2.designsystem.util.compositionlocal.LocalTracker
import com.teamhy2.designsystem.util.compositionlocal.ShowSnackBar
import com.teamhy2.feature.home.navigation.Home
import com.teamhy2.feature.main.component.MainBottomBar
import com.teamhy2.hongikyeolgong2.main.presentation.R
import com.teamhy2.tracker.Tracker
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject

private const val DEFAULT_BACKGROUND_OPACITY = 0.7f

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var tracker: Tracker

private val initialViewModel: InitialViewModel by viewModels()

@OptIn(ExperimentalPermissionsApi::class)
Expand Down Expand Up @@ -132,6 +138,7 @@ class MainActivity : AppCompatActivity() {

is InitialUiState.Success -> {
CompositionLocalProvider(
LocalTracker provides tracker,
LocalShowSnackBar provides showSnackBar,
) {
LaunchedEffect(true) {
Expand Down
1 change: 1 addition & 0 deletions ranking-presentation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ dependencies {

implementation(projects.core.designsystem)
implementation(projects.rankingDomain)
implementation(projects.core.tracker)
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.teamhy2.designsystem.ui.theme.BackgroundBlack
import com.teamhy2.designsystem.ui.theme.Gray100
import com.teamhy2.designsystem.ui.theme.HY2Typography
import com.teamhy2.designsystem.util.compositionlocal.LocalShowSnackBar
import com.teamhy2.designsystem.util.compositionlocal.LocalTracker
import com.teamhy2.hongikyeolgong2.ranking.presentation.R
import com.teamhy2.ranking.components.RankingItem
import com.teamhy2.ranking.model.DepartmentRanking
Expand All @@ -42,7 +43,10 @@ fun RankingRoute(
val rankingUiState by rankingViewModel.rankingUiState.collectAsStateWithLifecycle()

val localShowSnackBar = LocalShowSnackBar.current
val tracker = LocalTracker.current

LaunchedEffect(true) {
tracker.trackEvent("Ranking")
rankingViewModel.errorFlow.collectLatest { throwable ->
localShowSnackBar.showSnackBar(throwable.message)
}
Expand Down
1 change: 1 addition & 0 deletions record-presentation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ dependencies {

implementation(projects.calendarPresentation)
implementation(projects.calendarDomain)
implementation(projects.core.tracker)
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.hongikyeolgong2.calendar.model.Calendar
import com.hongikyeolgong2.calendar.presentation.Hy2Calendar
import com.teamhy2.designsystem.common.HY2CircularLoading
import com.teamhy2.designsystem.util.compositionlocal.LocalShowSnackBar
import com.teamhy2.designsystem.util.compositionlocal.LocalTracker
import com.teamhy2.record.components.StudyDurationCard
import com.teamhy2.record.domain.model.StudyDuration
import com.teamhy2.record.model.RecordUiState
Expand All @@ -35,7 +36,10 @@ fun RecordRoute(
val recordUiState by recordViewModel.recordUiState.collectAsStateWithLifecycle()

val localShowSnackBar = LocalShowSnackBar.current
val tracker = LocalTracker.current

LaunchedEffect(true) {
tracker.trackEvent("Record")
recordViewModel.errorFlow.collectLatest { throwable ->
localShowSnackBar.showSnackBar(throwable.message)
}
Expand Down
1 change: 1 addition & 0 deletions setting-presentation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ dependencies {
implementation(projects.settingDomain)
implementation(projects.userDomain)
implementation(libs.coil)
implementation(projects.core.tracker)
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import com.teamhy2.designsystem.ui.theme.Gray300
import com.teamhy2.designsystem.ui.theme.HY2Theme
import com.teamhy2.designsystem.ui.theme.HY2Typography
import com.teamhy2.designsystem.util.compositionlocal.LocalShowSnackBar
import com.teamhy2.designsystem.util.compositionlocal.LocalTracker
import com.teamhy2.feature.setting.presentation.components.SettingButton
import com.teamhy2.feature.setting.presentation.components.SettingButtonWithSwitch
import com.teamhy2.feature.setting.presentation.components.SettingUserProfile
Expand All @@ -55,18 +56,26 @@ fun SettingRoute(
) {
val settingUiState by viewModel.settingUiState.collectAsStateWithLifecycle()
val context = LocalContext.current
val tracker = LocalTracker.current

val localShowSnackBar = LocalShowSnackBar.current
LaunchedEffect(true) {
tracker.trackEvent("Setting")
viewModel.errorFlow.collectLatest { throwable ->
localShowSnackBar.showSnackBar(throwable.message)
}
}

SettingScreen(
settingUiState = settingUiState,
onLogoutClick = viewModel::signOut,
onWithdrawClick = viewModel::withdraw,
onLogoutClick = {
viewModel.signOut()
tracker.trackEvent("LogoutButton")
},
onWithdrawClick = {
viewModel.withdraw()
tracker.trackEvent("WithdrawButton")
},
onNotificationSwitchClick = { isChecked ->
viewModel.updateNotificationSwitchState(isChecked)
},
Expand Down
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ include(":core:designsystem")
include(":core:remote")
include(":core:auth")
include(":core:notification")
include(":core:tracker")

include(":calendar-domain")
include(":calendar-presentation")
Expand Down