Skip to content

Repository files navigation

Finch

Finch offers a customizable debug menu for Android app development. It does not affect production code. Developers can easily add their own custom debugging features with simple steps.

Gradle Dependency

Add it in your root build.gradle at the end of repositories:

dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url'https://jitpack.io' }
}
}

Pick a UI implementation and add the dependency:

  • ui-activity - The debug menu as a new screen.
  • ui-bottom-sheet - The debug menu as a modal bottom sheet.
  • ui-dialog - The debug menu as a modal dialog.
  • ui-drawer - The debug menu as a side navigation drawer.
  • ui-view - The debug menu as a view.
  • noop - For release build.
dependencies {
debugImplementation'com.github.kernel0x.finch:ui-drawer:2.3.9'releaseImplementation'com.github.kernel0x.finch:noop:2.3.9'// optional only for logsdebugImplementation'com.github.kernel0x.finch:log:2.3.9'releaseImplementation'com.github.kernel0x.finch:log-noop:2.3.9'// optional only for OkHttpdebugImplementation'com.github.kernel0x.finch:log-okhttp:2.3.9'releaseImplementation'com.github.kernel0x.finch:log-okhttp-noop:2.3.9'// optional only for GRPCdebugImplementation'com.github.kernel0x.finch:log-grpc:2.3.9'releaseImplementation'com.github.kernel0x.finch:log-grpc-noop:2.3.9' }

How to works

Initialize an instance of Finch (preferably in the Application's onCreate() method)

Finch.initialize(this)

Various customizations are set through the Configuration object.

Next, you need to add which components you want to display in the debug menu. Optionally, you can additionally configure logging and interception network events (with OkHttp).

Logging

To add log messages in Debug Menu simple calling Finch.log() and add FinchLogger to Configuration object.

Finch.log("message")
Finch.initialize(
application = this,
configuration = Configuration(
logger = FinchLogger,
...
),
)

OkHttp

Add FinchOkHttpLogger.logger to the method addInterceptor in building OkHttp Client and add FinchOkHttpLogger to Configuration object.

OkHttpClient.Builder()
.addInterceptor(FinchOkHttpLogger.loggeras? Interceptor ?: Interceptor { it.proceed(it.request()) })
.build()
Finch.initialize(
application = this,
configuration = Configuration(
networkLoggers = listOf(FinchOkHttpLogger),
...
),
)

Grpc

Add FinchGrpcLogger.logger to the method intercept in building ManagedChannel and add FinchGrpcLogger to Configuration object.

ManagedChannelBuilder.forAddress(networkConfig.hostname, networkConfig.port)
.intercept(FinchGrpcLogger.loggeras? ClientInterceptor ?: object : ClientInterceptor {
overridefun <ReqT : Any?, RespT : Any?> interceptCall(
method: MethodDescriptor<ReqT, RespT>?,
callOptions: CallOptions?,
next: Channel?
): ClientCall<ReqT, RespT> {
returnobject : ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
next?.newCall(
method,
callOptions
)
) {}
}
})
.build()
Finch.initialize(
application = this,
configuration = Configuration(
networkLoggers = listOf(FinchGrpcLogger),
...
),
)

Example initialize

Here is a minimal example that should work for most projects

Finch.initialize(
application = this,
configuration = Configuration(
logger = FinchLogger,
networkLoggers = listOf(FinchOkHttpLogger)
),
components = arrayOf(
Header(
title = getString(R.string.app_name),
subtitle = BuildConfig.APPLICATION_ID,
text = "${BuildConfig.BUILD_TYPE} v${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})"
),
Padding(),
Label("Tools", Label.Type.HEADER),
DesignOverlay(),
AnimationSpeed(),
ScreenCaptureToolbox(),
Divider(),
Label("Logs", Label.Type.HEADER),
LifecycleLogs(),
NetworkLogs(),
Logs(),
Divider(),
Label("Other", Label.Type.HEADER),
DeviceInfo(),
AppInfo(),
DeveloperOptions(),
ForceCrash()
)
)

Common cases

Backend environment

dataclassEnvironment(
valtype: Type,
overridevaltitle: Text = Text.CharSequence(type.name)
) : FinchListItemenumclassType {
TEST,
PROD
}
SingleSelectionList(
title = "Backend environment",
items = listOf(Environment(Type.TEST), Environment(Type.PROD)),
initiallySelectedItemId = Type.TEST.name,
isValuePersisted = true,
onSelectionChanged = {
when (it?.type) {
Type.TEST -> {
...
}
Type.PROD -> {
...
}
else -> {
// nothing
}
}
}
),

Feature Toggles

funApplication.initializeDebugMenu(
featureManager: FeatureManager
) {
valtoggles = featureManager.getAll().map {
Switch(
text = it.description,
initialValue = it.isEnabled(),
isEnabled = true,
onValueChanged = { value ->
featureManager.save(it.key, value)
if (!it.canChangedInRuntime) {
Toast.makeText(this, "Restart app to apply changes!", Toast.LENGTH_LONG).show()
}
}
)
}
Finch.initialize(
...
components = arrayOf(
...
Divider(),
Label("Feature Toggles", Label.Type.HEADER),
Switch(
text = "Show",
initialValue = false,
isEnabled = true,
id = "feature_toggles",
onValueChanged = {
if (it) {
Finch.add(
components = toggles.toTypedArray(),
position = Position.Below("feature_toggles")
)
} else {
toggles.forEach { item ->
Finch.remove(item.id)
}
}
}
),
...
)
)
}

Logs

classLogTree : Timber.Tree() {
overridefunlog(priority: Int, tag: String?, message: String, t: Throwable?) {
FinchLogger.log(message)
}
}
funApplication.initializeDebugMenu() {
...
Timber.plant(LogTree())
Finch.initialize(
application = this,
configuration = Configuration(
logger = FinchLogger,
),
...
)
}

Components

CheckBoxDividerItemListKeyValueListLabelLongTextMultipleSelectionListPaddingProgressBarSingleSelectionListSliderSwitchTextInputAnimationSpeedAppInfoDesignOverlayDeveloperOptionsDeviceInfoForceCrashHeaderLifecycleLogsLogsLoremIpsumGeneratorNetworkLogs

Proguard

-keep,allowobfuscation,allowshrinkingclasscom.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinkingclass * extendscom.google.gson.reflect.TypeToken

Releases

Checkout the Releases tab for all release info.

About

🖥 Debug menu library for Android apps with supports network activity logging and many other useful features.

Topics

Resources

Stars

135 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages