From 25f14226df40d8289756b9e8caaeea237847db4e Mon Sep 17 00:00:00 2001 From: Kirill Kamakin Date: Sun, 28 Nov 2021 21:55:29 +0300 Subject: [PATCH] Replace Stetho with Flipper, add LeakCanary --- app/build.gradle | 17 +++- app/proguard-rules-debug.pro | 25 ++++++ .../debug/java/gq/kirmanak/mealient/App.kt | 33 ++++++++ .../gq/kirmanak/mealient/di/DebugModule.kt | 78 +++++++++++++++++++ app/src/main/java/gq/kirmanak/mealient/App.kt | 14 ---- .../mealient/data/impl/OkHttpBuilder.kt | 26 +++---- .../gq/kirmanak/mealient/di/AuthModule.kt | 21 +++-- .../release/java/gq/kirmanak/mealient/App.kt | 7 ++ 8 files changed, 182 insertions(+), 39 deletions(-) create mode 100644 app/proguard-rules-debug.pro create mode 100644 app/src/debug/java/gq/kirmanak/mealient/App.kt create mode 100644 app/src/debug/java/gq/kirmanak/mealient/di/DebugModule.kt delete mode 100644 app/src/main/java/gq/kirmanak/mealient/App.kt create mode 100644 app/src/release/java/gq/kirmanak/mealient/App.kt diff --git a/app/build.gradle b/app/build.gradle index cc8f742..4d5d32c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,7 +40,7 @@ android { debug { minifyEnabled true shrinkResources true - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro', 'proguard-rules-debug.pro' } release { minifyEnabled true @@ -109,7 +109,7 @@ dependencies { // https://github.com/square/okhttp/tags implementation platform("com.squareup.okhttp3:okhttp-bom:4.9.3") implementation "com.squareup.okhttp3:okhttp" - implementation "com.squareup.okhttp3:logging-interceptor" + debugImplementation "com.squareup.okhttp3:logging-interceptor" testImplementation "com.squareup.okhttp3:mockwebserver" // https://github.com/Kotlin/kotlinx.serialization/releases @@ -157,4 +157,17 @@ dependencies { // https://github.com/androidbroadcast/ViewBindingPropertyDelegate/releases implementation "com.github.kirich1409:viewbindingpropertydelegate-noreflection:1.5.3" + + // https://github.com/facebook/flipper/releases + def flipper_version = "0.127.0" + debugImplementation "com.facebook.flipper:flipper:$flipper_version" + debugImplementation "com.facebook.flipper:flipper-leakcanary2-plugin:$flipper_version" + debugImplementation "com.facebook.flipper:flipper-network-plugin:$flipper_version" + + // https://github.com/facebook/SoLoader/releases + debugImplementation "com.facebook.soloader:soloader:0.10.3" + + // https://github.com/square/leakcanary/releases + debugImplementation "com.squareup.leakcanary:leakcanary-android:2.7" + } \ No newline at end of file diff --git a/app/proguard-rules-debug.pro b/app/proguard-rules-debug.pro new file mode 100644 index 0000000..793bcb0 --- /dev/null +++ b/app/proguard-rules-debug.pro @@ -0,0 +1,25 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile +### Flipper https://github.com/facebook/flipper/issues/314#issuecomment-940828336 ### +-keep class com.facebook.jni.** { *; } +-keep class com.facebook.flipper.** { *; } +### Flipper https://github.com/facebook/flipper/issues/314#issuecomment-940828336 ### diff --git a/app/src/debug/java/gq/kirmanak/mealient/App.kt b/app/src/debug/java/gq/kirmanak/mealient/App.kt new file mode 100644 index 0000000..072de6f --- /dev/null +++ b/app/src/debug/java/gq/kirmanak/mealient/App.kt @@ -0,0 +1,33 @@ +package gq.kirmanak.mealient + +import android.app.Application +import com.facebook.flipper.android.AndroidFlipperClient +import com.facebook.flipper.android.utils.FlipperUtils +import com.facebook.flipper.core.FlipperPlugin +import com.facebook.soloader.SoLoader +import dagger.hilt.android.HiltAndroidApp +import timber.log.Timber +import javax.inject.Inject + +@HiltAndroidApp +class App : Application() { + // Use @JvmSuppressWildcards because otherwise dagger can't inject it (https://stackoverflow.com/a/43149382) + @Inject + lateinit var flipperPlugins: Set<@JvmSuppressWildcards FlipperPlugin> + + override fun onCreate() { + super.onCreate() + Timber.plant(Timber.DebugTree()) + Timber.v("onCreate() called") + setupFlipper() + } + + private fun setupFlipper() { + if (FlipperUtils.shouldEnableFlipper(this)) { + SoLoader.init(this, false) + val flipperClient = AndroidFlipperClient.getInstance(this) + for (flipperPlugin in flipperPlugins) flipperClient.addPlugin(flipperPlugin) + flipperClient.start() + } + } +} diff --git a/app/src/debug/java/gq/kirmanak/mealient/di/DebugModule.kt b/app/src/debug/java/gq/kirmanak/mealient/di/DebugModule.kt new file mode 100644 index 0000000..12b6d63 --- /dev/null +++ b/app/src/debug/java/gq/kirmanak/mealient/di/DebugModule.kt @@ -0,0 +1,78 @@ +package gq.kirmanak.mealient.di + +import android.content.Context +import com.facebook.flipper.core.FlipperPlugin +import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin +import com.facebook.flipper.plugins.inspector.DescriptorMapping +import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin +import com.facebook.flipper.plugins.leakcanary2.FlipperLeakListener +import com.facebook.flipper.plugins.leakcanary2.LeakCanary2FlipperPlugin +import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor +import com.facebook.flipper.plugins.network.NetworkFlipperPlugin +import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import dagger.multibindings.IntoSet +import leakcanary.LeakCanary +import okhttp3.Interceptor +import okhttp3.logging.HttpLoggingInterceptor +import timber.log.Timber +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object DebugModule { + @Provides + @Singleton + @IntoSet + fun provideLoggingInterceptor(): Interceptor { + val interceptor = HttpLoggingInterceptor { message -> Timber.tag("OkHttp").v(message) } + interceptor.level = HttpLoggingInterceptor.Level.BODY + return interceptor + } + + @Provides + @Singleton + @IntoSet + fun provideFlipperInterceptor(networkFlipperPlugin: NetworkFlipperPlugin): Interceptor { + return FlipperOkhttpInterceptor(networkFlipperPlugin) + } + + @Provides + @Singleton + fun networkFlipperPlugin() = NetworkFlipperPlugin() + + @Provides + @Singleton + @IntoSet + fun bindNetworkFlipperPlugin(plugin: NetworkFlipperPlugin): FlipperPlugin = plugin + + @Provides + @Singleton + @IntoSet + fun sharedPreferencesPlugin(@ApplicationContext context: Context): FlipperPlugin = + SharedPreferencesFlipperPlugin(context) + + @Provides + @Singleton + @IntoSet + fun leakCanaryPlugin(): FlipperPlugin { + LeakCanary.config = LeakCanary.config.copy(onHeapAnalyzedListener = FlipperLeakListener()) + return LeakCanary2FlipperPlugin() + } + + @Provides + @Singleton + @IntoSet + fun databasesPlugin(@ApplicationContext context: Context): FlipperPlugin = + DatabasesFlipperPlugin(context) + + @Provides + @Singleton + @IntoSet + fun inspectorPlugin(@ApplicationContext context: Context): FlipperPlugin = + InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()) +} diff --git a/app/src/main/java/gq/kirmanak/mealient/App.kt b/app/src/main/java/gq/kirmanak/mealient/App.kt deleted file mode 100644 index 7a28e6f..0000000 --- a/app/src/main/java/gq/kirmanak/mealient/App.kt +++ /dev/null @@ -1,14 +0,0 @@ -package gq.kirmanak.mealient - -import android.app.Application -import dagger.hilt.android.HiltAndroidApp -import timber.log.Timber - -@HiltAndroidApp -class App : Application() { - override fun onCreate() { - super.onCreate() - if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree()) - Timber.v("onCreate() called") - } -} \ No newline at end of file diff --git a/app/src/main/java/gq/kirmanak/mealient/data/impl/OkHttpBuilder.kt b/app/src/main/java/gq/kirmanak/mealient/data/impl/OkHttpBuilder.kt index 5e05065..df5d1bf 100644 --- a/app/src/main/java/gq/kirmanak/mealient/data/impl/OkHttpBuilder.kt +++ b/app/src/main/java/gq/kirmanak/mealient/data/impl/OkHttpBuilder.kt @@ -1,27 +1,21 @@ package gq.kirmanak.mealient.data.impl -import gq.kirmanak.mealient.BuildConfig -import gq.kirmanak.mealient.data.auth.impl.AuthOkHttpInterceptor import okhttp3.Interceptor import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor import timber.log.Timber import javax.inject.Inject -class OkHttpBuilder @Inject constructor( - private val authOkHttpInterceptor: AuthOkHttpInterceptor +class OkHttpBuilder +@Inject +constructor( + // Use @JvmSuppressWildcards because otherwise dagger can't inject it (https://stackoverflow.com/a/43149382) + private val interceptors: Set<@JvmSuppressWildcards Interceptor> ) { + fun buildOkHttp(): OkHttpClient { Timber.v("buildOkHttp() called") - val builder = OkHttpClient.Builder() - if (BuildConfig.DEBUG) builder.addNetworkInterceptor(buildLoggingInterceptor()) - builder.addNetworkInterceptor(authOkHttpInterceptor) - return builder.build() + return OkHttpClient.Builder() + .apply { for (interceptor in interceptors) addNetworkInterceptor(interceptor) } + .build() } - - private fun buildLoggingInterceptor(): Interceptor { - val interceptor = HttpLoggingInterceptor { message -> Timber.tag("OkHttp").v(message) } - interceptor.level = HttpLoggingInterceptor.Level.BODY - return interceptor - } -} \ No newline at end of file +} diff --git a/app/src/main/java/gq/kirmanak/mealient/di/AuthModule.kt b/app/src/main/java/gq/kirmanak/mealient/di/AuthModule.kt index b90d3f4..d401112 100644 --- a/app/src/main/java/gq/kirmanak/mealient/di/AuthModule.kt +++ b/app/src/main/java/gq/kirmanak/mealient/di/AuthModule.kt @@ -4,26 +4,33 @@ import dagger.Binds import dagger.Module import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import dagger.multibindings.IntoSet import gq.kirmanak.mealient.data.auth.AuthDataSource import gq.kirmanak.mealient.data.auth.AuthRepo import gq.kirmanak.mealient.data.auth.AuthStorage import gq.kirmanak.mealient.data.auth.impl.AuthDataSourceImpl +import gq.kirmanak.mealient.data.auth.impl.AuthOkHttpInterceptor import gq.kirmanak.mealient.data.auth.impl.AuthRepoImpl import gq.kirmanak.mealient.data.auth.impl.AuthStorageImpl import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.serialization.ExperimentalSerializationApi +import okhttp3.Interceptor @ExperimentalCoroutinesApi @ExperimentalSerializationApi @Module @InstallIn(SingletonComponent::class) interface AuthModule { - @Binds - fun bindAuthDataSource(authDataSourceImpl: AuthDataSourceImpl): AuthDataSource + @Binds + fun bindAuthDataSource(authDataSourceImpl: AuthDataSourceImpl): AuthDataSource - @Binds - fun bindAuthStorage(authStorageImpl: AuthStorageImpl): AuthStorage + @Binds + fun bindAuthStorage(authStorageImpl: AuthStorageImpl): AuthStorage - @Binds - fun bindAuthRepo(authRepo: AuthRepoImpl): AuthRepo -} \ No newline at end of file + @Binds + fun bindAuthRepo(authRepo: AuthRepoImpl): AuthRepo + + @Binds + @IntoSet + fun bindAuthInterceptor(authOkHttpInterceptor: AuthOkHttpInterceptor): Interceptor +} diff --git a/app/src/release/java/gq/kirmanak/mealient/App.kt b/app/src/release/java/gq/kirmanak/mealient/App.kt new file mode 100644 index 0000000..d929ce5 --- /dev/null +++ b/app/src/release/java/gq/kirmanak/mealient/App.kt @@ -0,0 +1,7 @@ +package gq.kirmanak.mealient + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + +@HiltAndroidApp +class App : Application()