Merge pull request #84 from kirmanak/separate-firebase-project

Disable Firebase analytics in debug builds
This commit is contained in:
Kirill Kamakin
2022-11-05 13:03:07 +01:00
committed by GitHub
14 changed files with 161 additions and 13 deletions

View File

@@ -65,6 +65,7 @@ android {
dependencies { dependencies {
implementation(project(":architecture"))
implementation(project(":database")) implementation(project(":database"))
implementation(project(":datastore")) implementation(project(":datastore"))
implementation(project(":datasource")) implementation(project(":datasource"))

View File

@@ -2,6 +2,8 @@ package gq.kirmanak.mealient
import android.app.Application import android.app.Application
import dagger.hilt.android.HiltAndroidApp import dagger.hilt.android.HiltAndroidApp
import gq.kirmanak.mealient.architecture.configuration.BuildConfiguration
import gq.kirmanak.mealient.data.analytics.Analytics
import gq.kirmanak.mealient.logging.Logger import gq.kirmanak.mealient.logging.Logger
import javax.inject.Inject import javax.inject.Inject
@@ -11,8 +13,15 @@ class App : Application() {
@Inject @Inject
lateinit var logger: Logger lateinit var logger: Logger
@Inject
lateinit var buildConfiguration: BuildConfiguration
@Inject
lateinit var analytics: Analytics
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
logger.v { "onCreate() called" } logger.v { "onCreate() called" }
analytics.setIsEnabled(!buildConfiguration.isDebug())
} }
} }

View File

@@ -0,0 +1,6 @@
package gq.kirmanak.mealient.data.analytics
interface Analytics {
fun setIsEnabled(enabled: Boolean)
}

View File

@@ -0,0 +1,21 @@
package gq.kirmanak.mealient.data.analytics
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.crashlytics.FirebaseCrashlytics
import gq.kirmanak.mealient.logging.Logger
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AnalyticsImpl @Inject constructor(
private val firebaseAnalytics: FirebaseAnalytics,
private val firebaseCrashlytics: FirebaseCrashlytics,
private val logger: Logger,
) : Analytics {
override fun setIsEnabled(enabled: Boolean) {
logger.v { "setIsEnabled() called with: enabled = $enabled" }
firebaseAnalytics.setAnalyticsCollectionEnabled(enabled)
firebaseCrashlytics.setCrashlyticsCollectionEnabled(enabled)
}
}

View File

@@ -5,12 +5,16 @@ import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.PreferenceDataStoreFactory import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStoreFile import androidx.datastore.preferences.preferencesDataStoreFile
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.crashlytics.FirebaseCrashlytics
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import gq.kirmanak.mealient.data.analytics.Analytics
import gq.kirmanak.mealient.data.analytics.AnalyticsImpl
import gq.kirmanak.mealient.data.storage.PreferencesStorage import gq.kirmanak.mealient.data.storage.PreferencesStorage
import gq.kirmanak.mealient.data.storage.PreferencesStorageImpl import gq.kirmanak.mealient.data.storage.PreferencesStorageImpl
import javax.inject.Singleton import javax.inject.Singleton
@@ -24,9 +28,23 @@ interface AppModule {
@Singleton @Singleton
fun provideDataStore(@ApplicationContext context: Context): DataStore<Preferences> = fun provideDataStore(@ApplicationContext context: Context): DataStore<Preferences> =
PreferenceDataStoreFactory.create { context.preferencesDataStoreFile("settings") } PreferenceDataStoreFactory.create { context.preferencesDataStoreFile("settings") }
@Provides
@Singleton
fun provideFirebaseAnalytics(@ApplicationContext context: Context): FirebaseAnalytics =
FirebaseAnalytics.getInstance(context)
@Provides
@Singleton
fun provideFirebaseCrashlytics(): FirebaseCrashlytics =
FirebaseCrashlytics.getInstance()
} }
@Binds @Binds
@Singleton @Singleton
fun bindPreferencesStorage(preferencesStorage: PreferencesStorageImpl): PreferencesStorage fun bindPreferencesStorage(preferencesStorage: PreferencesStorageImpl): PreferencesStorage
@Binds
@Singleton
fun bindAnalytics(analyticsImpl: AnalyticsImpl): Analytics
} }

View File

@@ -0,0 +1,42 @@
package gq.kirmanak.mealient.data.analytics
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.crashlytics.FirebaseCrashlytics
import gq.kirmanak.mealient.logging.Logger
import gq.kirmanak.mealient.test.FakeLogger
import io.mockk.MockKAnnotations
import io.mockk.impl.annotations.MockK
import io.mockk.verify
import org.junit.Before
import org.junit.Test
class AnalyticsImplTest {
@MockK(relaxUnitFun = true)
lateinit var firebaseAnalytics: FirebaseAnalytics
@MockK(relaxUnitFun = true)
lateinit var firebaseCrashlytics: FirebaseCrashlytics
lateinit var subject: Analytics
private val logger: Logger = FakeLogger()
@Before
fun setUp() {
MockKAnnotations.init(this)
subject = AnalyticsImpl(firebaseAnalytics, firebaseCrashlytics, logger)
}
@Test
fun `when setIsEnabled expect call to analytics`() {
subject.setIsEnabled(true)
verify { firebaseAnalytics.setAnalyticsCollectionEnabled(eq(true)) }
}
@Test
fun `when setIsEnabled expect call to crashlytics`() {
subject.setIsEnabled(true)
verify { firebaseCrashlytics.setCrashlyticsCollectionEnabled(eq(true)) }
}
}

1
architecture/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,14 @@
plugins {
id("gq.kirmanak.mealient.library")
id("dagger.hilt.android.plugin")
id("kotlin-kapt")
}
android {
namespace = "gq.kirmanak.mealient.architecture"
}
dependencies {
implementation(libs.google.dagger.hiltAndroid)
kapt(libs.google.dagger.hiltCompiler)
}

View File

@@ -0,0 +1,18 @@
package gq.kirmanak.mealient.architecture
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import gq.kirmanak.mealient.architecture.configuration.BuildConfiguration
import gq.kirmanak.mealient.architecture.configuration.BuildConfigurationImpl
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
interface ArchitectureModule {
@Binds
@Singleton
fun bindBuildConfiguration(buildConfigurationImpl: BuildConfigurationImpl): BuildConfiguration
}

View File

@@ -0,0 +1,6 @@
package gq.kirmanak.mealient.architecture.configuration
interface BuildConfiguration {
fun isDebug(): Boolean
}

View File

@@ -0,0 +1,14 @@
package gq.kirmanak.mealient.architecture.configuration
import androidx.viewbinding.BuildConfig
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class BuildConfigurationImpl @Inject constructor() : BuildConfiguration {
@get:JvmName("_isDebug")
private val isDebug by lazy { BuildConfig.DEBUG }
override fun isDebug(): Boolean = isDebug
}

View File

@@ -9,6 +9,8 @@ android {
} }
dependencies { dependencies {
implementation(project(":architecture"))
implementation(libs.google.dagger.hiltAndroid) implementation(libs.google.dagger.hiltAndroid)
kapt(libs.google.dagger.hiltCompiler) kapt(libs.google.dagger.hiltCompiler)
} }

View File

@@ -1,29 +1,25 @@
package gq.kirmanak.mealient.logging package gq.kirmanak.mealient.logging
import android.os.Build
import android.util.Log import android.util.Log
import gq.kirmanak.mealient.architecture.configuration.BuildConfiguration
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class LogcatAppender @Inject constructor() : Appender { class LogcatAppender @Inject constructor(
private val buildConfiguration: BuildConfiguration,
) : Appender {
private val isLoggable: Boolean by lazy { BuildConfig.DEBUG } private val isLoggable: Boolean
get() = buildConfiguration.isDebug()
override fun isLoggable(logLevel: LogLevel): Boolean = isLoggable override fun isLoggable(logLevel: LogLevel): Boolean = isLoggable
override fun isLoggable(logLevel: LogLevel, tag: String): Boolean = isLoggable override fun isLoggable(logLevel: LogLevel, tag: String): Boolean = isLoggable
override fun log(logLevel: LogLevel, tag: String, message: String) { override fun log(logLevel: LogLevel, tag: String, message: String) {
// Tag length limit was removed in API 26.
val logTag = if (tag.length <= MAX_TAG_LENGTH || Build.VERSION.SDK_INT >= 26) {
tag
} else {
tag.substring(0, MAX_TAG_LENGTH)
}
if (message.length < MAX_LOG_LENGTH) { if (message.length < MAX_LOG_LENGTH) {
Log.println(logLevel.priority, logTag, message) Log.println(logLevel.priority, tag, message)
return return
} }
@@ -36,7 +32,7 @@ class LogcatAppender @Inject constructor() : Appender {
do { do {
val end = newline.coerceAtMost(i + MAX_LOG_LENGTH) val end = newline.coerceAtMost(i + MAX_LOG_LENGTH)
val part = message.substring(i, end) val part = message.substring(i, end)
Log.println(logLevel.priority, logTag, part) Log.println(logLevel.priority, tag, part)
i = end i = end
} while (i < newline) } while (i < newline)
i++ i++
@@ -45,7 +41,6 @@ class LogcatAppender @Inject constructor() : Appender {
companion object { companion object {
private const val MAX_LOG_LENGTH = 4000 private const val MAX_LOG_LENGTH = 4000
private const val MAX_TAG_LENGTH = 23
} }
} }

View File

@@ -20,6 +20,7 @@ dependencyResolutionManagement {
rootProject.name = "Mealient" rootProject.name = "Mealient"
include(":app") include(":app")
include(":architecture")
include(":database") include(":database")
include(":datastore") include(":datastore")
include(":logging") include(":logging")