Skip to content
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
8 changes: 8 additions & 0 deletions .github/workflows/develop_branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ jobs:
RELEASE_KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }}
RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }}
RELEASE_STORE_PASSWORD: ${{ secrets.RELEASE_STORE_PASSWORD }}
FACEBOOK_APP_ID: ${{ secrets.FACEBOOK_APP_ID }}
FACEBOOK_CLIENT_TOKEN: ${{ secrets.FACEBOOK_CLIENT_TOKEN }}
FACEBOOK_DEBUG_APP_ID: ${{ secrets.FACEBOOK_DEBUG_APP_ID }}
FACEBOOK_DEBUG_CLIENT_TOKEN: ${{ secrets.FACEBOOK_DEBUG_CLIENT_TOKEN }}
run: |
# Keystore Decoding
echo $RELEASE_STORE_BASE_64 > encoded_keystore.txt
Expand All @@ -38,6 +42,10 @@ jobs:
echo "release.key.password=$RELEASE_KEY_PASSWORD" >> local.properties
echo "release.keystore.password=$RELEASE_STORE_PASSWORD" >> local.properties
echo "release.keystore.path=../release.jks" >> local.properties
echo "facebook.app.id=$FACEBOOK_APP_ID" >> local.properties
echo "facebook.client.token=$FACEBOOK_CLIENT_TOKEN" >> local.properties
echo "facebook.debug.app.id=$FACEBOOK_DEBUG_APP_ID" >> local.properties
echo "facebook.debug.client.token=$FACEBOOK_DEBUG_CLIENT_TOKEN" >> local.properties

- name: set up JDK 17
uses: actions/setup-java@v4
Expand Down
45 changes: 12 additions & 33 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import java.util.Properties
import com.threegap.bitnagil.convention.extension.propertyOrNull
import com.threegap.bitnagil.convention.extension.requireProperty

plugins {
alias(libs.plugins.bitnagil.android.application)
Expand All @@ -7,34 +8,17 @@ plugins {
}

android {
val properties =
Properties().apply {
val propFile = rootProject.file("local.properties")
if (propFile.exists()) {
load(propFile.inputStream())
}
}

signingConfigs {
create("release") {
keyAlias = properties["release.key.alias"] as? String
?: System.getenv("RELEASE_KEY_ALIAS")
?: throw GradleException("RELEASE_KEY_ALIAS 값이 없습니다.")
keyPassword = properties["release.key.password"] as? String
?: System.getenv("RELEASE_KEY_PASSWORD")
?: throw GradleException("RELEASE_KEY_PASSWORD 값이 없습니다.")
storePassword = properties["release.keystore.password"] as? String
?: System.getenv("RELEASE_KEYSTORE_PASSWORD")
?: throw GradleException("RELEASE_KEYSTORE_PASSWORD 값이 없습니다.")
storeFile = File("${properties["release.keystore.path"]}")
keyAlias = requireProperty("release.key.alias", "RELEASE_KEY_ALIAS")
keyPassword = requireProperty("release.key.password", "RELEASE_KEY_PASSWORD")
storePassword = requireProperty("release.keystore.password", "RELEASE_KEYSTORE_PASSWORD")
storeFile = File("${propertyOrNull("release.keystore.path", "RELEASE_KEYSTORE_PATH")}")
Comment thread
wjdrjs00 marked this conversation as resolved.
}
}

defaultConfig {
val kakaoNativeAppKey =
(properties["kakao.native.app.key"] as? String)
?: System.getenv("KAKAO_NATIVE_APP_KEY")
?: throw GradleException("KAKAO_NATIVE_APP_KEY 값이 없습니다.")
val kakaoNativeAppKey = requireProperty("kakao.native.app.key", "KAKAO_NATIVE_APP_KEY")

manifestPlaceholders["KAKAO_NATIVE_APP_KEY"] = kakaoNativeAppKey
buildConfigField(
Expand All @@ -43,10 +27,7 @@ android {
value = "\"$kakaoNativeAppKey\"",
)

val kakaoRestApiKey =
(properties["kakao.rest.api.key"] as? String)
?: System.getenv("KAKAO_REST_API_KEY")
?: throw GradleException("KAKAO_REST_API_KEY 값이 없습니다.")
val kakaoRestApiKey = requireProperty("kakao.rest.api.key", "KAKAO_REST_API_KEY")

buildConfigField(
type = "String",
Expand All @@ -61,17 +42,14 @@ android {
versionNameSuffix = "-DEBUG"
isDebuggable = true

val devUrl = properties["bitnagil.dev.url"] as? String
?: System.getenv("BITNAGIL_DEV_URL")
?: throw GradleException("bitnagil.dev.url 값이 없습니다.")
val devUrl = requireProperty("bitnagil.dev.url", "BITNAGIL_DEV_URL")
buildConfigField("String", "BASE_URL", "\"$devUrl\"")
}

release {
val prodUrl = properties["bitnagil.prod.url"] as? String
?: System.getenv("BITNAGIL_PROD_URL")
?: throw GradleException("bitnagil.prod.url 값이 없습니다.")
val prodUrl = requireProperty("bitnagil.prod.url", "BITNAGIL_PROD_URL")
buildConfigField("String", "BASE_URL", "\"$prodUrl\"")

isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
Expand All @@ -88,6 +66,7 @@ android {
}

dependencies {
implementation(projects.core.analytics)
implementation(projects.core.datastore)
implementation(projects.core.designsystem)
implementation(projects.core.network)
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,9 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>

<meta-data android:name="com.facebook.sdk.AutoInitEnabled" android:value="true" />
<meta-data android:name="com.facebook.sdk.AutoLogAppEventsEnabled" android:value="true" />
<meta-data android:name="com.facebook.sdk.AdvertiserIDCollectionEnabled" android:value="true" />
Comment thread
coderabbitai[bot] marked this conversation as resolved.
</application>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import coil3.network.okhttp.OkHttpNetworkFetcherFactory
import coil3.request.crossfade
import coil3.util.DebugLogger
import com.kakao.sdk.common.KakaoSdk
import com.threegap.bitnagil.analytics.meta.MetaAnalyticsInitializer
import com.threegap.bitnagil.di.core.CoilEntryPoint
import dagger.hilt.EntryPoints
import dagger.hilt.android.HiltAndroidApp
Expand All @@ -21,6 +22,7 @@ class BitnagilApplication : Application(), SingletonImageLoader.Factory {
override fun onCreate() {
super.onCreate()
initKakaoSdk()
configureMetaAppEvents()
}

override fun newImageLoader(context: PlatformContext): ImageLoader {
Expand Down Expand Up @@ -49,4 +51,8 @@ class BitnagilApplication : Application(), SingletonImageLoader.Factory {
private fun initKakaoSdk() {
KakaoSdk.init(this, BuildConfig.KAKAO_NATIVE_APP_KEY)
}

private fun configureMetaAppEvents() {
MetaAnalyticsInitializer.initialize(isDebugBuild = BuildConfig.DEBUG)
}
}
21 changes: 21 additions & 0 deletions app/src/main/java/com/threegap/bitnagil/di/core/AnalyticsModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.threegap.bitnagil.di.core

import android.content.Context
import com.threegap.bitnagil.analytics.AnalyticsLogger
import com.threegap.bitnagil.analytics.meta.MetaAnalyticsLogger
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 AnalyticsModule {

@Provides
@Singleton
fun provideAnalyticsLogger(@ApplicationContext context: Context): AnalyticsLogger =
MetaAnalyticsLogger(context)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import com.threegap.bitnagil.datastore.auth.serializer.AuthTokenSerializer
import com.threegap.bitnagil.datastore.auth.serializer.AuthTokenSerializerImpl
import com.threegap.bitnagil.datastore.auth.storage.AuthTokenDataStore
import com.threegap.bitnagil.datastore.auth.storage.AuthTokenStorageFactory
import com.threegap.bitnagil.datastore.routine.storage.RoutineAchievementDataStore
import com.threegap.bitnagil.datastore.routine.storage.RoutineAchievementStorageFactory
import com.threegap.bitnagil.security.crypto.Crypto
import dagger.Module
import dagger.Provides
Expand Down Expand Up @@ -38,4 +40,10 @@ object DataStoreModule {
@ApplicationContext context: Context,
serializer: AuthTokenSerializer,
): AuthTokenDataStore = AuthTokenStorageFactory.create(context, serializer)

@Provides
@Singleton
fun provideRoutineAchievementDataStore(
@ApplicationContext context: Context,
): RoutineAchievementDataStore = RoutineAchievementStorageFactory.create(context)
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ import com.threegap.bitnagil.data.recommendroutine.datasource.RecommendRoutineDa
import com.threegap.bitnagil.data.recommendroutine.datasourceImpl.RecommendRoutineDataSourceImpl
import com.threegap.bitnagil.data.report.datasource.ReportDataSource
import com.threegap.bitnagil.data.report.datasourceImpl.ReportDataSourceImpl
import com.threegap.bitnagil.data.routine.datasource.RoutineLocalDataSource
import com.threegap.bitnagil.data.routine.datasource.RoutineRemoteDataSource
import com.threegap.bitnagil.data.routine.datasourceImpl.RoutineLocalDataSourceImpl
import com.threegap.bitnagil.data.routine.datasourceImpl.RoutineRemoteDataSourceImpl
import com.threegap.bitnagil.data.user.datasource.UserLocalDataSource
import com.threegap.bitnagil.data.user.datasource.UserRemoteDataSource
Expand Down Expand Up @@ -58,6 +60,10 @@ abstract class DataSourceModule {
@Singleton
abstract fun bindRoutineDataSource(routineDataSourceImpl: RoutineRemoteDataSourceImpl): RoutineRemoteDataSource

@Binds
@Singleton
abstract fun bindRoutineLocalDataSource(routineLocalDataSourceImpl: RoutineLocalDataSourceImpl): RoutineLocalDataSource

@Binds
@Singleton
abstract fun bindEmotionLocalDataSource(emotionLocalDataSourceImpl: EmotionLocalDataSourceImpl): EmotionLocalDataSource
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.threegap.bitnagil.convention.extension

import java.util.Properties
import org.gradle.api.GradleException
import org.gradle.api.Project

private const val LOCAL_PROPERTIES_FILE_NAME = "local.properties"
private const val LOCAL_PROPERTIES_EXTRA_KEY = "bitnagilLocalProperties"

private fun Project.loadLocalProperties(): Properties =
Properties().apply {
val localPropertiesFile = rootProject.file(LOCAL_PROPERTIES_FILE_NAME)
if (localPropertiesFile.exists()) {
localPropertiesFile.inputStream().use(::load)
}
}

/**
* 모듈마다 한 번만 읽고 해당 프로젝트의 extra 에 담아둔다.
* 데몬이 아니라 빌드마다 새로 만들어지는 저장소이므로 local.properties 를 수정하면 다음 빌드에 반영된다.
*/
private val Project.localProperties: Properties
get() {
val extra = extensions.extraProperties
if (!extra.has(LOCAL_PROPERTIES_EXTRA_KEY)) {
extra.set(LOCAL_PROPERTIES_EXTRA_KEY, loadLocalProperties())
}
return extra.get(LOCAL_PROPERTIES_EXTRA_KEY) as Properties
}

/**
* local.properties 값을 읽고, 없으면 환경 변수를 사용한다. 둘 다 없으면 null 을 반환한다.
*/
fun Project.propertyOrNull(propertyKey: String, environmentKey: String): String? =
localProperties.getProperty(propertyKey) ?: System.getenv(environmentKey)

/**
* [propertyOrNull] 과 동일하되, 값이 없거나 비어 있으면 설정 단계에서 실패한다.
*/
fun Project.requireProperty(propertyKey: String, environmentKey: String): String =
propertyOrNull(propertyKey, environmentKey)?.takeIf(String::isNotBlank)
?: throw GradleException("$propertyKey 값이 없습니다.")
43 changes: 43 additions & 0 deletions core/analytics/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import com.threegap.bitnagil.convention.extension.requireProperty

plugins {
alias(libs.plugins.bitnagil.android.library)
}

android {
buildTypes {
debug {
resValue(
type = "string",
name = "facebook_app_id",
value = requireProperty("facebook.debug.app.id", "FACEBOOK_DEBUG_APP_ID"),
Comment thread
wjdrjs00 marked this conversation as resolved.
)
resValue(
type = "string",
name = "facebook_client_token",
value = requireProperty("facebook.debug.client.token", "FACEBOOK_DEBUG_CLIENT_TOKEN"),
)
}

release {
resValue(
type = "string",
name = "facebook_app_id",
value = requireProperty("facebook.app.id", "FACEBOOK_APP_ID"),
)
resValue(
type = "string",
name = "facebook_client_token",
value = requireProperty("facebook.client.token", "FACEBOOK_CLIENT_TOKEN"),
)
}
}

buildFeatures {
resValues = true
}
}

dependencies {
implementation(libs.facebook.core)
}
8 changes: 8 additions & 0 deletions core/analytics/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application>
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id" />
<meta-data android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token" />
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.threegap.bitnagil.analytics

interface AnalyticsLogger {
/**
* 회원가입 완료를 기록한다. 약관 동의가 서버에 확정된 시점에 호출된다.
*/
fun logSignUpCompleted()

/**
* 온보딩 완료를 기록한다. 추천 루틴을 등록했든 건너뛰었든 동일하게 기록한다.
*/
fun logOnBoardingCompleted()

/**
* 생애 최초 루틴 완료를 기록한다. 앱 설치 기준으로 1회만 호출된다.
*/
fun logFirstRoutineCompleted()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.threegap.bitnagil.analytics.meta

import com.facebook.FacebookSdk
import com.facebook.LoggingBehavior

object MetaAnalyticsInitializer {
fun initialize(isDebugBuild: Boolean) {
if (!isDebugBuild) return

FacebookSdk.setIsDebugEnabled(true)
FacebookSdk.addLoggingBehavior(LoggingBehavior.APP_EVENTS)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.threegap.bitnagil.analytics.meta

import android.content.Context
import android.os.Bundle
import com.facebook.appevents.AppEventsConstants
import com.facebook.appevents.AppEventsLogger
import com.threegap.bitnagil.analytics.AnalyticsLogger

class MetaAnalyticsLogger(private val context: Context) : AnalyticsLogger {

private val logger by lazy { AppEventsLogger.newLogger(context) }

override fun logSignUpCompleted() {
logger.logEvent(AppEventsConstants.EVENT_NAME_COMPLETED_REGISTRATION)
}

override fun logOnBoardingCompleted() {
logger.logEvent(AppEventsConstants.EVENT_NAME_COMPLETED_TUTORIAL)
}

override fun logFirstRoutineCompleted() {
val parameters = Bundle().apply {
putString(AppEventsConstants.EVENT_PARAM_LEVEL, LEVEL_FIRST_ROUTINE_COMPLETED)
}

logger.logEvent(AppEventsConstants.EVENT_NAME_ACHIEVED_LEVEL, parameters)
}

private companion object {
const val LEVEL_FIRST_ROUTINE_COMPLETED = "first_routine_completed"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.threegap.bitnagil.datastore.routine.model

import kotlinx.serialization.Serializable

@Serializable
data class RoutineAchievement(
val firstCompletionLogged: Boolean = false,
)
Loading
Loading