Merge pull request #24 from kirmanak/flipper

Use Flipper instead of Stetho
This commit is contained in:
Kirill Kamakin
2021-12-27 14:40:22 +03:00
committed by GitHub
10 changed files with 199 additions and 52 deletions

View File

@@ -40,7 +40,7 @@ android {
debug { debug {
minifyEnabled true minifyEnabled true
shrinkResources 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 { release {
minifyEnabled true minifyEnabled true
@@ -109,7 +109,7 @@ dependencies {
// https://github.com/square/okhttp/tags // https://github.com/square/okhttp/tags
implementation platform("com.squareup.okhttp3:okhttp-bom:4.9.3") implementation platform("com.squareup.okhttp3:okhttp-bom:4.9.3")
implementation "com.squareup.okhttp3:okhttp" implementation "com.squareup.okhttp3:okhttp"
implementation "com.squareup.okhttp3:logging-interceptor" debugImplementation "com.squareup.okhttp3:logging-interceptor"
testImplementation "com.squareup.okhttp3:mockwebserver" testImplementation "com.squareup.okhttp3:mockwebserver"
// https://github.com/Kotlin/kotlinx.serialization/releases // https://github.com/Kotlin/kotlinx.serialization/releases
@@ -155,11 +155,19 @@ dependencies {
// https://mvnrepository.com/artifact/com.google.truth/truth // https://mvnrepository.com/artifact/com.google.truth/truth
testImplementation "com.google.truth:truth:1.1.3" testImplementation "com.google.truth:truth:1.1.3"
// https://github.com/facebook/stetho/releases
def stetho_version = "1.6.0"
implementation "com.facebook.stetho:stetho:$stetho_version"
implementation "com.facebook.stetho:stetho-okhttp3:$stetho_version"
// https://github.com/androidbroadcast/ViewBindingPropertyDelegate/releases // https://github.com/androidbroadcast/ViewBindingPropertyDelegate/releases
implementation "com.github.kirich1409:viewbindingpropertydelegate-noreflection:1.5.3" 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"
} }

View File

@@ -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 ###

View File

@@ -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()
}
}
}

View File

@@ -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())
}

View File

@@ -1,18 +0,0 @@
package gq.kirmanak.mealient
import android.app.Application
import com.facebook.stetho.Stetho
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())
Stetho.initializeWithDefaults(this)
}
Timber.v("onCreate() called")
}
}

View File

@@ -1,31 +1,21 @@
package gq.kirmanak.mealient.data.impl package gq.kirmanak.mealient.data.impl
import com.facebook.stetho.okhttp3.StethoInterceptor
import gq.kirmanak.mealient.BuildConfig
import gq.kirmanak.mealient.data.auth.impl.AuthOkHttpInterceptor
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class OkHttpBuilder @Inject constructor( class OkHttpBuilder
private val authOkHttpInterceptor: AuthOkHttpInterceptor @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 { fun buildOkHttp(): OkHttpClient {
Timber.v("buildOkHttp() called") Timber.v("buildOkHttp() called")
val builder = OkHttpClient.Builder() return OkHttpClient.Builder()
builder.addNetworkInterceptor(authOkHttpInterceptor) .apply { for (interceptor in interceptors) addNetworkInterceptor(interceptor) }
if (BuildConfig.DEBUG) { .build()
builder.addNetworkInterceptor(buildLoggingInterceptor())
builder.addNetworkInterceptor(StethoInterceptor())
}
return builder.build()
} }
}
private fun buildLoggingInterceptor(): Interceptor {
val interceptor = HttpLoggingInterceptor { message -> Timber.tag("OkHttp").v(message) }
interceptor.level = HttpLoggingInterceptor.Level.BODY
return interceptor
}
}

View File

@@ -4,26 +4,33 @@ import dagger.Binds
import dagger.Module import dagger.Module
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import dagger.multibindings.IntoSet
import gq.kirmanak.mealient.data.auth.AuthDataSource import gq.kirmanak.mealient.data.auth.AuthDataSource
import gq.kirmanak.mealient.data.auth.AuthRepo import gq.kirmanak.mealient.data.auth.AuthRepo
import gq.kirmanak.mealient.data.auth.AuthStorage import gq.kirmanak.mealient.data.auth.AuthStorage
import gq.kirmanak.mealient.data.auth.impl.AuthDataSourceImpl 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.AuthRepoImpl
import gq.kirmanak.mealient.data.auth.impl.AuthStorageImpl import gq.kirmanak.mealient.data.auth.impl.AuthStorageImpl
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.ExperimentalSerializationApi
import okhttp3.Interceptor
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
@ExperimentalSerializationApi @ExperimentalSerializationApi
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
interface AuthModule { interface AuthModule {
@Binds @Binds
fun bindAuthDataSource(authDataSourceImpl: AuthDataSourceImpl): AuthDataSource fun bindAuthDataSource(authDataSourceImpl: AuthDataSourceImpl): AuthDataSource
@Binds @Binds
fun bindAuthStorage(authStorageImpl: AuthStorageImpl): AuthStorage fun bindAuthStorage(authStorageImpl: AuthStorageImpl): AuthStorage
@Binds @Binds
fun bindAuthRepo(authRepo: AuthRepoImpl): AuthRepo fun bindAuthRepo(authRepo: AuthRepoImpl): AuthRepo
}
@Binds
@IntoSet
fun bindAuthInterceptor(authOkHttpInterceptor: AuthOkHttpInterceptor): Interceptor
}

View File

@@ -77,4 +77,11 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) {
} }
} }
} }
override fun onDestroyView() {
super.onDestroyView()
Timber.v("onDestroyView() called")
// Prevent RV leaking through mObservers list in adapter
binding.recipes.adapter = null
}
} }

View File

@@ -51,4 +51,14 @@ class RecipeInfoFragment : BottomSheetDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
BottomSheetDialog(requireContext(), R.style.NoShapeBottomSheetDialog) BottomSheetDialog(requireContext(), R.style.NoShapeBottomSheetDialog)
override fun onDestroyView() {
super.onDestroyView()
Timber.v("onDestroyView() called")
// Prevent RV leaking through mObservers list in adapter
with(binding) {
ingredientsList.adapter = null
instructionsList.adapter = null
}
}
} }

View File

@@ -0,0 +1,7 @@
package gq.kirmanak.mealient
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class App : Application()