Beagle
A smart, reliable, and highly customizable debug menu library for Android apps that supports screen recording, network activity logging, and many other useful features.
Install / Use
/learn @pandulapeter/BeagleREADME
Beagle (Android library)
A smart, reliable, and highly customizable debug menu library for Android apps that supports screen recording, network activity logging, generating bug reports, and many other useful features.
<img src="metadata/logo.png" width="20%" />First steps
<details> <summary>See it in action</summary> <br/>Clone this repository, pick a build variant and run the app configuration. It should look something like this:
<img src="metadata/screenshot01.png" width="25%" /><img src="metadata/screenshot02.png" width="25%" /><img src="metadata/screenshot03.png" width="25%" /><img src="metadata/screenshot04.png" width="25%" />
This demo application also contains instructions on how to set up Beagle and how to implement the various features that are being showcased. You should definitely consider giving it a try if you're interested in using the library in your projects. If you don't feel like building it for yourself, you can also download it from the Play Store:
<img src="https://play.google.com/intl/en_us/badges/images/badge_new.png" />
The tutorials in the app cover everything from this readme, but in more detail. Another way to get an idea of what can be achieved with the library is this article, which presents various problems that can be solved with Beagle.
</details> <details> <summary>Use it in your project</summary> <br/>If the wall of text below is too long for your taste, check out this gist that contains all the code you need for a nice configuration. Otherwise, let's do it step by step:
Step 0: Check the requirements
- Minimum SDK level: 24+
- Target SDK level: 34+ (check older versions for target smaller SDK-s)
Step 1: Add the MavenCentral repository
Make sure that the following is part of your project-level build.gradle file:
allprojects {
repositories {
…
mavenCentral()
}
}
Step 2: Pick a UI implementation and configure the dependencies
The actual UI of the debug menu can be displayed in multiple ways, which is specified by the suffix of the dependency. The following versions exist:
- ui-activity - Displays the debug menu as a new screen (not recommended: modals are more useful).
- ui-bottom-sheet - Displays the debug menu as a modal bottom sheet (recommended).
- ui-dialog - Displays the debug menu as a modal dialog (recommended).
- ui-drawer - Displays the debug menu as a side navigation drawer (highly recommended).
- ui-view - Displaying the
DebugMenuViewis your responsibility (not recommended: shake to open,Beagle.show(),Beagle.hide(), the relatedVisibilityListeneras well as the inset handling logic won't work out of the box). - noop - No UI, no logic. It has the same public API as all other variants, but it does nothing (this is intended for production builds).
So, for example, if you prefer the Drawer UI, something like the following needs to be added to your app-level build.gradle file (check the widget below the code snippet for the latest version):
dependencies {
…
def beagleVersion = "2.9.11"
debugImplementation "io.github.pandulapeter.beagle:ui-drawer:$beagleVersion"
releaseImplementation "io.github.pandulapeter.beagle:noop:$beagleVersion"
}
The latest version is:
Note: In case of the drawer UI, if you have overwritten the Activity's onBackPressed() method, you might notice that the default back navigation handling does not always work as expected. To fix this, in every Activity's onBackPressed() you should check that Beagle.hide() returns false before doing any other checks or calling the super implementation.
Step 3: Initialize the library
Just one line of code, preferably in the Application's onCreate() method:
Beagle.initialize(this)
Optionally you can add the following parameters to this function:
- The appearance of the menu can be personalized by specifying an Appearance instance. For example, here you can specify a custom theme for the debug menu using the
themeResourceIdproperty, in case the one used by theApplication/Activityis not suitable. Note: It's recommended to extend a.NoActionBarMaterial theme. - The behavior of the menu can be personalized by specifying a Behavior instance. For example, adjusting the shake to open threshold or the strength of the haptic feedback is a frequent use case of this class.
By default you can fetch Beagle by shaking the device.
Step 4: Finish the setup by adding modules
After this a number of modules should be provided, but this configuration can be changed at any time (from any thread) and the UI will automatically be updated. The simplest way of doing this is by calling:
Beagle.set(module1, module2, …)
At this point you should be aware of two options:
- The list of built-in modules. Every file in this package is documented. These modules should cover most use cases and have the advantage of also providing a fake, noop implementation which means that no part of their logic is compiled into your release builds.
- The ability to write custom modules. For this a good starting point is looking at the built-in implementations from above, but this document also provides some guidance.
Check out the showcase app for some ideas on what is possible with the built-in modules or for an interactive tool that can be used to preview any module configuration and generate the code for it. A more visual guide to some of the possibilities is this article.
Here is a minimal example that should work for most projects:
<img align="right" width="30%" src="metadata/screenshot05.png">Beagle.set(
HeaderModule(
title = getString(R.string.app_name),
subtitle = BuildConfig.APPLICATION_ID,
text = "${BuildConfig.BUILD_TYPE} v${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})"
),
AppInfoButtonModule(),
DeveloperOptionsButtonModule(),
PaddingModule(),
TextModule("General", TextModule.Type.SECTION_HEADER),
KeylineOverlaySwitchModule(),
AnimationDurationSwitchModule(),
ScreenCaptureToolboxModule(),
DividerModule(),
TextModule("Logs", TextModule.Type.SECTION_HEADER),
NetworkLogListModule(), // Might require additional setup, see below
LogListModule(), // Might require additional setup, see below
LifecycleLogListModule(),
DividerModule(),
TextModule("Other", TextModule.Type.SECTION_HEADER),
DeviceInfoModule(),
BugReportButtonModule()
)
If you ever need to add temporary modules, Beagle.add() has an optional lifecycleOwner parameter that automatically removes the specified modules once the provided lifecycle is over. Manually calling Beagle.remove() with module ID-s is also an option.
Advanced features
<details> <summary>Logging</summary> <br/>While calling Beagle.log() is the simplest way to add items to LogListModule, a special workaround is needed to access this functionality from pure Kotlin modules. Another frequent use case is integration with Timber.
Logging from pure Kotlin modules
To access the same functionality that Beagle.log() provides from a pure Kotlin / Java module, first you need to add the following to the module in question:
dependencies {
…
api "io.github.pandulapeter.beagle:log:$beagleVersion"
// Alternative for Android modules:
// debugApi "io.github.pandulapeter.beagle:log:$beagleVersion"
// releaseApi "io.github.pandulapeter.beagle:log-noop:$beagleVersion"
}
These libraries provide the BeagleLogger object which needs to be connected to the main library when it is initialized in the Application class:
Beagle.initialize(
…
behavior = Behavior(
…
logBehavior = Behavior.LogBehavior(
loggers = listOf(BeagleLogger),
…
)
)
)
To add log messages, now you can call the following:
BeagleLogger.log(…)
The messages list will be merged with the ones logged using the regular Beagle.log() function (unless they are filtered by their tags) and can be displayed using a LogListModule. You can also use BeagleLogger.clearLogEntries() if you cannot access Beagle.clearLogEntries().
Logging with Timber
To automatically add events logged with Timber to the debug menu, planting a special tree is the simplest solution:
Timber.plant(
object : Timber.Tree() {
override fun log(priority: Int, tag: String?
Related Skills
openhue
339.3kControl Philips Hue lights and scenes via the OpenHue CLI.
sag
339.3kElevenLabs text-to-speech with mac-style say UX.
weather
339.3kGet current weather and forecasts via wttr.in or Open-Meteo
tweakcc
1.5kCustomize Claude Code's system prompts, create custom toolsets, input pattern highlighters, themes/thinking verbs/spinners, customize input box & user message styling, support AGENTS.md, unlock private/unreleased features, and much more. Supports both native/npm installs on all platforms.
