Android
Native Android SDK - Kotlin-first with full Java interop, covering JVM crashes, NDK native crashes, ANRs, sessions, breadcrumbs and logs.
Requirementslink
- minSdk 24 (Android 7.0) · compiled against SDK 35 · Java/Kotlin toolchain 17
- No required runtime dependencies; OkHttp 4.x is compileOnly (only needed if you use the network-breadcrumb interceptor)
1 - Installlink
// settings.gradle.kts - mavenCentral() must be in repositories
// app/build.gradle.kts
dependencies {
implementation("cloud.newinstance:bugwatch:0.1.1")
}2 - Initialise (Application.onCreate)link
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
BugWatch.initialize(application = this, options = BugWatchOptions(
projectId = BuildConfig.BUGWATCH_PROJECT_ID,
appSecret = BuildConfig.BUGWATCH_APP_SECRET,
environment = if (BuildConfig.DEBUG) "development" else "production",
release = BuildConfig.VERSION_NAME,
))
}
}Keep the credentials in local.properties/CI variables and inject via buildConfigField - never hard-code them in source.
3 - Configuration optionslink
| Option | Default | What it does |
|---|---|---|
environment | production | Event environment label |
release | - | Version string; must match your symbol uploads |
sampleRate | 1.0 | Client-side sampling (0–1) |
autoSessionTracking | true | Release-health sessions |
enableAnrTracking / anrThresholdMs | true / 5000 | ANR watchdog |
enableAutoBreadcrumbs | true | Activity/lifecycle breadcrumbs |
enableNetworkBreadcrumbs + allow/deny host lists | true | OkHttp request breadcrumbs |
sensitiveFields | built-in list | Extra keys to redact on device |
batchSize / flushIntervalMs | 50 / 5000 | Upload batching |
maxQueueSize | 1000 | Offline queue cap |
debug | false | SDK diagnostic logging |
4 - Capture APIlink
BugWatch.captureException(e)
BugWatch.captureMessage("Sync finished", level = "info")
BugWatch.setUser(User(id = "u_123", email = "ada@example.com"))
BugWatch.setTag("tenant", "acme")
BugWatch.setContext("payment", mapOf("provider" to "paystack"))
BugWatch.addBreadcrumb("Tapped checkout")
BugWatch.okHttpInterceptor() // add to your OkHttpClient for network breadcrumbs
BugWatch.crashedLastRun // true if the previous run died
BugWatch.flushBlocking(timeoutMs = 2000) // before process exit in workersAutomatic capturelink
- JVM crashes - default uncaught-exception handler (existing handlers are chained, not replaced).
- NDK native crashes - a C++ signal handler (
libbugwatch-native.so, all four ABIs) writes a crash sidecar; the SDK ships it on next launch (processPendingCrash). Frames carryinstruction_addr+ the module's GNU build-id so the backend symbolicates against your uploaded.sosymbols. - ANRs - a watchdog reports main-thread stalls past the threshold.
5 - Symbolication (CI)link
npx @newinstance/bugwatch-cli artifacts upload app/build/outputs/mapping/release/mapping.txt \
--release "$VERSION_NAME" --platform android --type r8 --token "$BUGWATCH_CI_KEY"
npx @newinstance/bugwatch-cli symbols upload app/build/intermediates/merged_native_libs/release \
--platform android --release "$VERSION_NAME" --token "$BUGWATCH_CI_KEY"The R8 mapping matches on release + platform - the string must equal options.release exactly. Native symbols match by build-id, so any machine's upload resolves any device's crash of that binary.
Troubleshootinglink
- No events at all → check
debug = truelogcat output; verify device clock (tokens reject >60 s skew) and that the credentials belong to this project. - Events but unreadable stacks → mapping not uploaded for this exact
release, or minification renamed classes after upload - upload in the same CI job that builds the bundle. - ANRs flooding → raise
anrThresholdMsor sample withbeforeSend-style filtering at the dashboard alert level.
The request below is the exact wire call the SDK makes; the token is signed on device from projectId + mobileAppSecret.
/api/v1/bugwatch/ingest/mobileWire example – Android JVM crash
Android JVM (Kotlin/Java) uncaught exception from the native cloud.newinstance:bugwatch SDK.
exception.stacktrace is an array of obfuscated frames; BugWatch de-obfuscates them server-side using the uploaded R8/ProGuard mapping (see Source Maps & Symbols → Artifact upload · step 1 – presign with artifactType: r8, or bugwatch-cli artifacts upload --type r8).
Auth + token: the same on-device x-bugwatch-token signing as every mobile request.
Headers
x-bugwatch-tokenRequest body
application/json{
"eventId": "bw_e_{{$guid}}",
"time": {{nowMs}},
"level": 60,
"platform": "android",
"release": "1.0.0",
"environment": "production",
"sdk": {
"name": "bugwatch-android",
"version": "0.1.1"
},
"device": {
"model": "SM-S901B",
"family": "Phone",
"osName": "Android",
"osVersion": "13",
"bundleId": "com.example.myapp"
},
"exception": {
"type": "java.lang.NullPointerException",
"value": "Attempt to invoke virtual method 'void com.example.app.Cart.checkout()' on a null object reference",
"stacktrace": [
{
"filename": "PaymentService.kt",
"function": "processPayment",
"lineno": 87,
"in_app": true
},
{
"filename": "CheckoutActivity.kt",
"function": "onConfirmClick",
"lineno": 142,
"in_app": true
}
]
},
"tags": {
"device_brand": "Samsung",
"android_api": "33"
},
"user": {
"id": "usr_android_001"
}
}Responses
202 – Mobile event ingested
{
"ingested": 1,
"skipped": 0,
"deduped": 0
}https://api.newinstance.cloud/api/v1/bugwatch/ingest/mobileHeaders
x-bugwatch-tokenRequest body
Code samples
curl -X POST 'https://api.newinstance.cloud/api/v1/bugwatch/ingest/mobile' \
-H 'Content-Type: application/json' \
--data-raw '{
"eventId": "bw_e_{{$guid}}",
"time": {{nowMs}},
"level": 60,
"platform": "android",
"release": "1.0.0",
"environment": "production",
"sdk": {
"name": "bugwatch-android",
"version": "0.1.1"
},
"device": {
"model": "SM-S901B",
"family": "Phone",
"osName": "Android",
"osVersion": "13",
"bundleId": "com.example.myapp"
},
"exception": {
"type": "java.lang.NullPointerException",
"value": "Attempt to invoke virtual method '\''void com.example.app.Cart.checkout()'\'' on a null object reference",
"stacktrace": [
{
"filename": "PaymentService.kt",
"function": "processPayment",
"lineno": 87,
"in_app": true
},
{
"filename": "CheckoutActivity.kt",
"function": "onConfirmClick",
"lineno": 142,
"in_app": true
}
]
},
"tags": {
"device_brand": "Samsung",
"android_api": "33"
},
"user": {
"id": "usr_android_001"
}
}'