android: add core common module logging crashlytics and feature flags
This commit is contained in:
@@ -6,6 +6,7 @@ plugins {
|
|||||||
id("org.jetbrains.kotlin.plugin.serialization")
|
id("org.jetbrains.kotlin.plugin.serialization")
|
||||||
id("com.google.dagger.hilt.android")
|
id("com.google.dagger.hilt.android")
|
||||||
id("com.google.gms.google-services")
|
id("com.google.gms.google-services")
|
||||||
|
id("com.google.firebase.crashlytics")
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@@ -19,6 +20,10 @@ android {
|
|||||||
versionCode = 1
|
versionCode = 1
|
||||||
versionName = "0.1.0"
|
versionName = "0.1.0"
|
||||||
buildConfigField("String", "API_BASE_URL", "\"https://chat.daemonlord.ru/\"")
|
buildConfigField("String", "API_BASE_URL", "\"https://chat.daemonlord.ru/\"")
|
||||||
|
buildConfigField("String", "API_VERSION_HEADER", "\"2026-03\"")
|
||||||
|
buildConfigField("boolean", "FEATURE_ACCOUNT_MANAGEMENT", "true")
|
||||||
|
buildConfigField("boolean", "FEATURE_TWO_FACTOR", "true")
|
||||||
|
buildConfigField("boolean", "FEATURE_MEDIA_GALLERY", "true")
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables {
|
vectorDrawables {
|
||||||
@@ -62,6 +67,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(":core:common"))
|
||||||
implementation(platform("com.google.firebase:firebase-bom:34.10.0"))
|
implementation(platform("com.google.firebase:firebase-bom:34.10.0"))
|
||||||
|
|
||||||
implementation("androidx.core:core-ktx:1.15.0")
|
implementation("androidx.core:core-ktx:1.15.0")
|
||||||
@@ -98,6 +104,8 @@ dependencies {
|
|||||||
kapt("com.google.dagger:hilt-compiler:2.52")
|
kapt("com.google.dagger:hilt-compiler:2.52")
|
||||||
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
|
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
|
||||||
implementation("com.google.firebase:firebase-messaging")
|
implementation("com.google.firebase:firebase-messaging")
|
||||||
|
implementation("com.google.firebase:firebase-crashlytics")
|
||||||
|
implementation("com.jakewharton.timber:timber:5.0.1")
|
||||||
|
|
||||||
testImplementation("junit:junit:4.13.2")
|
testImplementation("junit:junit:4.13.2")
|
||||||
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")
|
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")
|
||||||
|
|||||||
@@ -5,14 +5,20 @@ import coil.ImageLoader
|
|||||||
import coil.ImageLoaderFactory
|
import coil.ImageLoaderFactory
|
||||||
import coil.disk.DiskCache
|
import coil.disk.DiskCache
|
||||||
import coil.memory.MemoryCache
|
import coil.memory.MemoryCache
|
||||||
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
import dagger.hilt.android.HiltAndroidApp
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
import ru.daemonlord.messenger.core.notifications.NotificationChannels
|
import ru.daemonlord.messenger.core.notifications.NotificationChannels
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
@HiltAndroidApp
|
@HiltAndroidApp
|
||||||
class MessengerApplication : Application(), ImageLoaderFactory {
|
class MessengerApplication : Application(), ImageLoaderFactory {
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Timber.plant(Timber.DebugTree())
|
||||||
|
}
|
||||||
|
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(!BuildConfig.DEBUG)
|
||||||
NotificationChannels.ensureCreated(this)
|
NotificationChannels.ensureCreated(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package ru.daemonlord.messenger.core.logging
|
||||||
|
|
||||||
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class TimberAppLogger @Inject constructor(
|
||||||
|
private val crashlytics: FirebaseCrashlytics,
|
||||||
|
) : AppLogger {
|
||||||
|
|
||||||
|
override fun d(tag: String, message: String) {
|
||||||
|
Timber.tag(tag).d(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun i(tag: String, message: String) {
|
||||||
|
Timber.tag(tag).i(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun w(tag: String, message: String, throwable: Throwable?) {
|
||||||
|
if (throwable != null) {
|
||||||
|
Timber.tag(tag).w(throwable, message)
|
||||||
|
crashlytics.recordException(throwable)
|
||||||
|
} else {
|
||||||
|
Timber.tag(tag).w(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun e(tag: String, message: String, throwable: Throwable?) {
|
||||||
|
if (throwable != null) {
|
||||||
|
Timber.tag(tag).e(throwable, message)
|
||||||
|
crashlytics.recordException(throwable)
|
||||||
|
} else {
|
||||||
|
Timber.tag(tag).e(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package ru.daemonlord.messenger.core.network
|
||||||
|
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Response
|
||||||
|
import ru.daemonlord.messenger.BuildConfig
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class ApiVersionInterceptor @Inject constructor() : Interceptor {
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val request = chain.request().newBuilder()
|
||||||
|
.header("X-Api-Version", BuildConfig.API_VERSION_HEADER)
|
||||||
|
.build()
|
||||||
|
return chain.proceed(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package ru.daemonlord.messenger.di
|
||||||
|
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import ru.daemonlord.messenger.BuildConfig
|
||||||
|
import ru.daemonlord.messenger.core.feature.FeatureFlags
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
object FeatureFlagsModule {
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideFeatureFlags(): FeatureFlags {
|
||||||
|
return FeatureFlags(
|
||||||
|
accountManagementEnabled = BuildConfig.FEATURE_ACCOUNT_MANAGEMENT,
|
||||||
|
twoFactorEnabled = BuildConfig.FEATURE_TWO_FACTOR,
|
||||||
|
mediaGalleryEnabled = BuildConfig.FEATURE_MEDIA_GALLERY,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package ru.daemonlord.messenger.di
|
||||||
|
|
||||||
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
|
import dagger.Binds
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import ru.daemonlord.messenger.core.logging.AppLogger
|
||||||
|
import ru.daemonlord.messenger.core.logging.TimberAppLogger
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
abstract class LoggingModule {
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
abstract fun bindAppLogger(logger: TimberAppLogger): AppLogger
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideCrashlytics(): FirebaseCrashlytics = FirebaseCrashlytics.getInstance()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,11 +13,13 @@ import okhttp3.logging.HttpLoggingInterceptor
|
|||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import ru.daemonlord.messenger.BuildConfig
|
import ru.daemonlord.messenger.BuildConfig
|
||||||
import ru.daemonlord.messenger.core.network.AuthHeaderInterceptor
|
import ru.daemonlord.messenger.core.network.AuthHeaderInterceptor
|
||||||
|
import ru.daemonlord.messenger.core.network.ApiVersionInterceptor
|
||||||
import ru.daemonlord.messenger.core.network.TokenRefreshAuthenticator
|
import ru.daemonlord.messenger.core.network.TokenRefreshAuthenticator
|
||||||
import ru.daemonlord.messenger.data.auth.api.AuthApiService
|
import ru.daemonlord.messenger.data.auth.api.AuthApiService
|
||||||
import ru.daemonlord.messenger.data.chat.api.ChatApiService
|
import ru.daemonlord.messenger.data.chat.api.ChatApiService
|
||||||
import ru.daemonlord.messenger.data.media.api.MediaApiService
|
import ru.daemonlord.messenger.data.media.api.MediaApiService
|
||||||
import ru.daemonlord.messenger.data.message.api.MessageApiService
|
import ru.daemonlord.messenger.data.message.api.MessageApiService
|
||||||
|
import ru.daemonlord.messenger.data.user.api.UserApiService
|
||||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@@ -87,11 +89,13 @@ object NetworkModule {
|
|||||||
@Singleton
|
@Singleton
|
||||||
fun provideApiClient(
|
fun provideApiClient(
|
||||||
loggingInterceptor: HttpLoggingInterceptor,
|
loggingInterceptor: HttpLoggingInterceptor,
|
||||||
|
apiVersionInterceptor: ApiVersionInterceptor,
|
||||||
authHeaderInterceptor: AuthHeaderInterceptor,
|
authHeaderInterceptor: AuthHeaderInterceptor,
|
||||||
tokenRefreshAuthenticator: TokenRefreshAuthenticator,
|
tokenRefreshAuthenticator: TokenRefreshAuthenticator,
|
||||||
): OkHttpClient {
|
): OkHttpClient {
|
||||||
return OkHttpClient.Builder()
|
return OkHttpClient.Builder()
|
||||||
.addInterceptor(loggingInterceptor)
|
.addInterceptor(loggingInterceptor)
|
||||||
|
.addInterceptor(apiVersionInterceptor)
|
||||||
.addInterceptor(authHeaderInterceptor)
|
.addInterceptor(authHeaderInterceptor)
|
||||||
.authenticator(tokenRefreshAuthenticator)
|
.authenticator(tokenRefreshAuthenticator)
|
||||||
.connectTimeout(20, TimeUnit.SECONDS)
|
.connectTimeout(20, TimeUnit.SECONDS)
|
||||||
@@ -137,4 +141,10 @@ object NetworkModule {
|
|||||||
fun provideMediaApiService(retrofit: Retrofit): MediaApiService {
|
fun provideMediaApiService(retrofit: Retrofit): MediaApiService {
|
||||||
return retrofit.create(MediaApiService::class.java)
|
return retrofit.create(MediaApiService::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideUserApiService(retrofit: Retrofit): UserApiService {
|
||||||
|
return retrofit.create(UserApiService::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("com.android.application") version "8.7.2" apply false
|
id("com.android.application") version "8.7.2" apply false
|
||||||
|
id("com.android.library") version "8.7.2" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "2.0.21" apply false
|
id("org.jetbrains.kotlin.android") version "2.0.21" apply false
|
||||||
|
id("org.jetbrains.kotlin.jvm") version "2.0.21" apply false
|
||||||
id("org.jetbrains.kotlin.plugin.compose") version "2.0.21" apply false
|
id("org.jetbrains.kotlin.plugin.compose") version "2.0.21" apply false
|
||||||
id("com.google.dagger.hilt.android") version "2.52" apply false
|
id("com.google.dagger.hilt.android") version "2.52" apply false
|
||||||
id("org.jetbrains.kotlin.plugin.serialization") version "2.0.21" apply false
|
id("org.jetbrains.kotlin.plugin.serialization") version "2.0.21" apply false
|
||||||
id("org.jetbrains.kotlin.kapt") version "2.0.21" apply false
|
id("org.jetbrains.kotlin.kapt") version "2.0.21" apply false
|
||||||
id("com.google.gms.google-services") version "4.4.4" apply false
|
id("com.google.gms.google-services") version "4.4.4" apply false
|
||||||
|
id("com.google.firebase.crashlytics") version "3.0.3" apply false
|
||||||
}
|
}
|
||||||
|
|||||||
7
android/core/common/build.gradle.kts
Normal file
7
android/core/common/build.gradle.kts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
plugins {
|
||||||
|
id("org.jetbrains.kotlin.jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain(17)
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package ru.daemonlord.messenger.core.feature
|
||||||
|
|
||||||
|
data class FeatureFlags(
|
||||||
|
val accountManagementEnabled: Boolean,
|
||||||
|
val twoFactorEnabled: Boolean,
|
||||||
|
val mediaGalleryEnabled: Boolean,
|
||||||
|
)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package ru.daemonlord.messenger.core.logging
|
||||||
|
|
||||||
|
interface AppLogger {
|
||||||
|
fun d(tag: String, message: String)
|
||||||
|
fun i(tag: String, message: String)
|
||||||
|
fun w(tag: String, message: String, throwable: Throwable? = null)
|
||||||
|
fun e(tag: String, message: String, throwable: Throwable? = null)
|
||||||
|
}
|
||||||
@@ -16,3 +16,4 @@ dependencyResolutionManagement {
|
|||||||
|
|
||||||
rootProject.name = "MessengerAndroid"
|
rootProject.name = "MessengerAndroid"
|
||||||
include(":app")
|
include(":app")
|
||||||
|
include(":core:common")
|
||||||
|
|||||||
Reference in New Issue
Block a user