You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -102,43 +102,102 @@ After completing these steps, you can start using BugSplat in your Android appli
102
102
103
103
### Configuration
104
104
105
-
To configure BugSplat to handle native crashes, simply call `initBugSplat` with the desired arguments. Be sure that the value you provide for `database` matches the value in the BugSplat web app.
105
+
To configure BugSplat to handle native crashes, simply call `BugSplat.init` with the desired arguments. Be sure that the value you provide for `database` matches the value in the BugSplat web app.
You can also add file attributes, and/or file attachments to your crash reports.
111
+
### Loading config from local.properties (recommended)
112
112
113
-
Kotlin
113
+
Keeping your database name, app name, and version in one place avoids drift between runtime (`BugSplat.init`) and symbol upload. The pattern most BugSplat users adopt:
114
+
115
+
1. Add the database name to the gitignored `local.properties`:
116
+
117
+
```properties
118
+
bugsplat.database=your_database
119
+
```
120
+
121
+
2. In your app module's `build.gradle`, load it and expose it (plus `applicationId` and `versionName`) as `BuildConfig` fields:
3. Initialize BugSplat from the generated `BuildConfig`:
147
+
148
+
```java
149
+
BugSplat.init(
150
+
this,
151
+
BuildConfig.BUGSPLAT_DATABASE,
152
+
BuildConfig.BUGSPLAT_APP_NAME,
153
+
BuildConfig.BUGSPLAT_APP_VERSION
154
+
);
155
+
```
156
+
157
+
See [`example/build.gradle`](example/build.gradle) for the complete working setup. This same `bugsplat.database` value is also picked up by the symbol upload task, so there's a single source of truth across the whole build.
158
+
159
+
### Attributes and attachments
160
+
161
+
You can also add custom attributes and/or file attachments to your crash reports.
162
+
163
+
**Kotlin**
114
164
```kotlin
115
165
val attributes =mapOf(
116
166
"key1" to "value1",
117
167
"key2" to "value2",
118
168
"environment" to "development"
119
169
)
120
170
121
-
val attachmentFileName ="log.txt"
122
-
createAttachmentFile(attachmentFileName)
123
-
val attachmentPath = applicationContext.getFileStreamPath(attachmentFileName).absolutePath
171
+
val attachmentPath = applicationContext.getFileStreamPath("log.txt").absolutePath
@@ -173,68 +232,56 @@ This approach requires the `symbol-upload` executable to be included in your app
173
232
174
233
#### 2. Using Gradle Build Tasks
175
234
176
-
You can also add a Gradle task to your build process to automatically upload symbols when you build your app. Here's an example of how to set this up:
235
+
You can wire symbol upload into your Gradle build so it runs automatically after `assembleDebug` / `assembleRelease`. The recommended pattern is to keep credentials out of `build.gradle` by loading them from the gitignored `local.properties`.
236
+
237
+
**Step 1 — Add credentials to `local.properties` (do not commit):**
238
+
239
+
```properties
240
+
bugsplat.database=your_database
241
+
bugsplat.clientId=your_client_id
242
+
bugsplat.clientSecret=your_client_secret
243
+
```
244
+
245
+
**Step 2 — Load them in `build.gradle` and register per-ABI upload tasks:**
177
246
178
247
```gradle
179
-
// BugSplat configuration
248
+
// Load BugSplat credentials from local.properties
See the [Example App README](example/README.md) for a complete implementation of this approach.
280
+
See [`example/build.gradle`](example/build.gradle) for the complete, working implementation. Key details:
281
+
282
+
-**Intermediate path** — AGP 8.6+ places merged native libs at `merged_native_libs/<buildType>/merge<BuildType>NativeLibs/out/lib/<abi>/`. Older AGPs used a flat `merged_native_libs/<buildType>/out/lib/<abi>/` layout.
283
+
-**Serial execution** — the `symbol-upload` binary uses a shared temp directory, so per-ABI uploads must be chained via `mustRunAfter` rather than running in parallel.
284
+
-**Missing ABIs** — when Android Studio runs on a single-ABI device (e.g. an arm64 emulator), only that ABI's libs get built. Per-ABI tasks for other ABIs will log a warning and skip cleanly.
238
285
239
286
#### 3. Using the Command-Line Tool
240
287
@@ -327,20 +374,54 @@ When integrating BugSplat into your Android application, it's crucial to ensure
327
374
328
375
These configurations ensure that the BugSplat native libraries are properly included in your app and can function correctly to capture and report native crashes.
329
376
377
+
## ANR Detection 🐌
378
+
379
+
The BugSplat Android SDK automatically detects and reports Application Not Responding (ANR) events on Android 11+ (API level 30+) using the [`ApplicationExitInfo`](https://developer.android.com/reference/android/app/ApplicationExitInfo) API.
380
+
381
+
### How It Works
382
+
383
+
When the system kills your app due to an ANR, the event is recorded by Android. On the next app launch, the SDK queries `ActivityManager.getHistoricalProcessExitReasons()` for new ANRs, reads the system-provided thread dump, and uploads it to BugSplat. ANR reports appear alongside crashes with the **"Android.ANR"** type.
384
+
385
+
The thread dump includes:
386
+
- Full Java stack traces for all threads in the process
387
+
- Native stack frames with BuildIds (symbolicated against uploaded `.sym` files)
388
+
- Lock contention information (which threads are holding/waiting for locks)
389
+
390
+
### Configuration
391
+
392
+
ANR detection is enabled automatically when you call `BugSplat.init()` — no additional configuration needed. The SDK persists the timestamp of the last reported ANR in `SharedPreferences` to avoid duplicate uploads across launches.
393
+
394
+
### Testing ANR Detection
395
+
396
+
To test ANR detection, use `BugSplat.hang()` to block the main thread in a native infinite loop:
397
+
398
+
```java
399
+
// Call this on the main thread to trigger an ANR
400
+
BugSplat.hang();
401
+
```
402
+
403
+
After calling `BugSplat.hang()`, tap the screen to generate a pending input event — the system will show an ANR dialog after ~5 seconds. Choose "Close app" to kill the process. On the next app launch, the SDK will upload the ANR report to BugSplat.
404
+
405
+
The resulting thread dump includes a native frame for `jniHang`, which demonstrates end-to-end symbolication when your `.sym` files have been uploaded.
406
+
407
+
### Supported Versions
408
+
409
+
ANR detection requires **Android 11+ (API 30+)**. On older Android versions, the `ApplicationExitInfo` API is unavailable and ANR detection is silently disabled.
410
+
330
411
## User Feedback 💬
331
412
332
413
BugSplat supports collecting non-crashing user feedback such as bug reports and feature requests. Feedback reports appear in BugSplat alongside crash reports with the "User Feedback" type.
333
414
334
415
### Posting Feedback
335
416
336
-
Use `BugSplat.postFeedback` to submit feedback asynchronously, or `BugSplat.postFeedbackBlocking` for synchronous submission:
417
+
Use `BugSplat.postFeedback` to submit feedback asynchronously, or `BugSplat.postFeedbackBlocking` for synchronous submission. The `database`, `application`, and `version` values are typically loaded from `BuildConfig` (see [Loading config from local.properties](#loading-config-from-localproperties-recommended)):
337
418
338
419
```java
339
420
// Async (returns immediately, runs on background thread)
Attach arbitrary key/value metadata to feedback reports:
464
+
465
+
```java
466
+
Map<String, String> attributes =newHashMap<>();
467
+
attributes.put("environment", "production");
468
+
attributes.put("user_tier", "premium");
469
+
470
+
BugSplat.postFeedback(
471
+
BuildConfig.BUGSPLAT_DATABASE,
472
+
BuildConfig.BUGSPLAT_APP_NAME,
473
+
BuildConfig.BUGSPLAT_APP_VERSION,
474
+
"Login button broken", "Nothing happens on tap",
475
+
"Jane", "jane@example.com", null,
476
+
null, // attachments
477
+
attributes
478
+
);
479
+
```
480
+
376
481
### Example Feedback Dialog
377
482
378
483
The example app includes a simple feedback dialog using Android's `AlertDialog`. See [`MainActivity.java`](example/src/main/java/com/bugsplat/example/MainActivity.java) for the implementation. The dialog collects a subject and optional description, then posts feedback using `BugSplat.postFeedbackBlocking` on a background thread.
@@ -392,7 +497,9 @@ To run the example app:
392
497
The example app demonstrates:
393
498
- Automatically initializing the BugSplat SDK at app startup
394
499
- Triggering a crash for testing purposes
500
+
- Triggering an ANR (via `BugSplat.hang()`) to test ANR detection and native frame symbolication
395
501
- Submitting user feedback via a dialog
502
+
- Setting custom attributes via a dialog
396
503
- Handling errors during initialization
397
504
398
505
For more information, see the [Example App README](example/README.md).
0 commit comments