All but React Native are in beta.
All but React Native are in beta.

minSdk 23 or higher and compileSdk 35 or higher. Debug builds need minSdk 24.Buoy works in Compose apps and in apps built with plain views.
It brings in Jetpack Compose and OkHttp for its own screens.
It also adds two permissions to builds that use it.
INTERNET lets it reach Desktop and check your account.
POST_NOTIFICATIONS lets the Notifications tool send test alerts.
The no-op adds no permissions.
Is your app's minSdk 23?
Then raise it to 24 in each build that uses Buoy.
This keeps release at 23:
androidComponents {
beforeVariants(selector().all()) { if (it.buildType != "release") it.minSdk = 24 }
}
androidComponents {
beforeVariants(selector().all()) { if (it.buildType != "release") it.minSdk = 24 }
}
In a Groovy build.gradle, the same lines work as they are.
Your release build can stay at 23.
The no-op works on 23.
Java code on 23 can't use the Supplier form of BuoyBench.configure.
That type needs API 24.
Use the other form, or turn on core library desugaring.
Buoy is on Maven Central.
Make sure mavenCentral() is in your repositories.
Then add Buoy to your app module:
dependencies {
debugImplementation("gg.buoy:buoy-android:0.1.0")
releaseImplementation("gg.buoy:buoy-android-noop:0.1.0")
}
dependencies {
debugImplementation("gg.buoy:buoy-android:0.1.0")
releaseImplementation("gg.buoy:buoy-android-noop:0.1.0")
}
buoy-android holds every tool.
buoy-android-noop has the same setup calls, and they do nothing.
See Release Builds.
While Buoy is 0.x, a new minor version can break things. Pin the version you test with.
Some apps check the license of every package they use. One common tool for this is Licensee. Buoy is not open source, so its license is a link to our terms. Add that link to your allowed list:
licensee {
allowUrl("https://buoy.gg/terms")
}
licensee {
allowUrl("https://buoy.gg/terms")
}
Some apps list a hash for every package they trust. Gradle calls this dependency verification. Add Buoy's packages to that list when you add Buoy.
Buoy uses AndroidX. Some apps bundle their own copy of AndroidX parts under the same names. Then the build fails with "Duplicate class androidx...". Leave out your copy in debug builds, where Buoy runs.
The Quick Start reads the key from local.properties into a BuildConfig field.
Any way your app gets config is fine.
Keep the key out of git.
Buoy.start(this, BuoyConfig(licenseKey = BuildConfig.BUOY_LICENSE_KEY.ifEmpty { null }))
Buoy.start(this, BuoyConfig(licenseKey = BuildConfig.BUOY_LICENSE_KEY.ifEmpty { null }))
A free account works in debug builds. A build that is not debuggable needs a Pro plan.
To skip the key, let people sign in with a code instead:
Buoy.start(this, BuoyConfig(signIn = BuoySignInConfig()))
Buoy.start(this, BuoyConfig(signIn = BuoySignInConfig()))
Call Buoy.start in Application.onCreate.
It runs on the main thread.
A call from another thread waits for the main thread.
Buoy starts every tool and draws its button over each screen. You don't add a view or call an install step.
Start Buoy before you build OkHttp clients and other app parts that make web calls.
Nothing changes between the two. Buoy draws its own layer on top of each activity. Taps that miss Buoy go to your app.
Some tools need a line in your UI code, like BuoyAsyncImage or Modifier.buoyTrackRenders.
Tools lists them.
BuoyConfig takes these:
| Setting | What it does |
|---|---|
enabled | Turns Buoy off when false. |
deviceName | The name Desktop shows. |
deviceId | Leave it unset. Buoy makes one id per install. A custom id must be different on each device. |
socketUrl | Where Buoy Desktop is. See Physical Devices. |
licenseKey | Your account key. |
signIn | Lets people sign in with a code. |
telemetry | One anonymous ping a day, in debug builds only. |
enableLogs | Prints Buoy's own log lines. |
extraDeviceInfo | Extra lines for the device card in Desktop. |
allProcesses | Starts Buoy in every process, not just the main one. |
Java code can call Buoy.start(context) or Buoy.start(context, config).
Open Buoy Desktop and sign in.
Buoy looks for it at http://localhost:42831.
On the emulator, run this once:
adb reverse tcp:42831 tcp:42831
adb reverse tcp:42831 tcp:42831
For a real phone, see Physical Devices.
Pick the Android device in Desktop. Then check a web call again. Being connected and seeing calls are two different checks.
A second Buoy.start gives back the running copy.
It can set a new account key.
It does not change the Desktop address or the device id.
Buoy.stop() takes Buoy out of the app.
The button goes away and the link to Desktop closes.
Each tool stops changing what the app sees.
The network hook stays in your client, but it lets every call pass.
Saved tool settings stay, so a later Buoy.start picks them up.