Web Analytics

finch

⭐ 134 stars Simplified Chinese by kernel0x

Finch

Finch 提供了一个可定制的调试菜单,用于安卓应用开发。它不会影响生产代码。开发者可以通过简单的步骤轻松添加自定义调试功能。

Gradle 依赖

在根目录的 build.gradle 文件中,在 repositories 的末尾添加:

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

选择一个 UI 实现并添加依赖:

dependencies {
    debugImplementation 'com.github.kernel0x.finch:ui-drawer:2.3.6'
    releaseImplementation 'com.github.kernel0x.finch:noop:2.3.6'
    // optional only for OkHttp
    debugImplementation 'com.github.kernel0x.finch:log-okhttp:2.3.6'
    releaseImplementation 'com.github.kernel0x.finch:log-okhttp-noop:2.3.6'
    // optional only for GRPC
    debugImplementation 'com.github.kernel0x.finch:log-grpc:2.3.6'
    releaseImplementation 'com.github.kernel0x.finch:log-grpc-noop:2.3.6'
    // optional only for logs
    debugImplementation 'com.github.kernel0x.finch:log:2.3.6'
    releaseImplementation 'com.github.kernel0x.finch:log-noop:2.3.6'
}

工作原理

初始化 Finch 的一个实例(最好在应用程序的 onCreate() 方法中)

Finch.initialize(this)
各种自定义设置通过 Configuration 对象进行。

接下来,您需要添加希望在调试菜单中显示的组件。可选地,您还可以额外配置日志记录和拦截网络事件(使用 OkHttp)。

日志记录

要在调试菜单中添加日志消息,只需调用 Finch.log() 并将 FinchLogger 添加到 Configuration 对象中。

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

OkHttp

在构建 OkHttp 客户端时,将 FinchOkHttpLogger.logger 添加到 addInterceptor 方法中,并将 FinchOkHttpLogger 添加到 Configuration 对象中。

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

Grpc

在构建 ManagedChannel 时,将 FinchGrpcLogger.logger 添加到方法拦截器中,并将 FinchGrpcLogger 添加到 Configuration 对象中。

ManagedChannelBuilder.forAddress(networkConfig.hostname, networkConfig.port)
    .intercept(FinchGrpcLogger.logger as? ClientInterceptor ?: object : ClientInterceptor {
        override fun  interceptCall(
            method: MethodDescriptor?,
            callOptions: CallOptions?,
            next: Channel?
        ): ClientCall {
            return object : ForwardingClientCall.SimpleForwardingClientCall(
                next?.newCall(
                    method,
                    callOptions
                )
            ) {}
        }
    })
    .build()
Finch.initialize(
    application = this,
    configuration = Configuration(
        networkLoggers = listOf(FinchGrpcLogger),
        ...
    ),
)

示例初始化

这里是一个适用于大多数项目的最小示例

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

常见情况

#### 后端环境

data class Environment(
    val type: Type,
    override val title: Text = Text.CharSequence(type.name)
) : FinchListItem

enum class Type { 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 } } } ),

#### 功能开关

fun Application.initializeDebugMenu(
    featureManager: FeatureManager
) {
    val toggles = 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)
                        }
                    }
                }
            ),
            ...
        )
    )
}
#### 日志

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

Components

CheckBox Divider ItemList KeyValueList Label LongText MultipleSelectionList Padding ProgressBar SingleSelectionList Slider Switch TextInput AnimationSpeed AppInfo DesignOverlay DeveloperOptions DeviceInfo ForceCrash Header LifecycleLogs Logs LoremIpsumGenerator NetworkLogs

Proguard

-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken

版本发布

请查看版本发布标签获取所有发布信息。

--- Tranlated By Open Ai Tx | Last indexed: 2025-12-25 ---