> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flashcat.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Android

> 掌握 Android RUM SDK 的异常捕获机制，包括 Java/Kotlin 崩溃、NDK 崩溃、ANR 报告、手动上报和符号化配置

本文档介绍 Android RUM SDK 的异常捕获机制，帮助您监控和诊断 Android 应用中的崩溃和错误问题。

<Info>
  SDK 支持自动捕获 Java/Kotlin 崩溃、NDK 原生崩溃、ANR（应用无响应），同时提供手动错误上报和符号化堆栈跟踪功能。
</Info>

## 异常类型

Android RUM 可以监控以下类型的异常：

### Java/Kotlin 崩溃

SDK 自动捕获未处理的 Java/Kotlin 异常，包括：

* 运行时异常（如 `NullPointerException`、`IndexOutOfBoundsException`）
* 未捕获的异常
* 应用崩溃

### NDK 崩溃（Native Crash）

若您的应用使用了原生代码（C/C++），SDK 支持捕获 NDK 崩溃并将其纳入异常追踪。

### ANR（应用无响应）

SDK 可以检测并报告 ANR 问题，帮助您发现主线程阻塞导致的用户体验问题。

### 自定义错误

除了自动捕获的异常外，您还可以使用 RUM SDK 手动上报自定义异常，用于跟踪业务逻辑错误等特定问题。

## 配置崩溃报告

### 基础配置

<Note>
  崩溃报告功能默认启用。确保您已按照 [SDK 接入指南](https://docs.flashcat.cloud/zh/flashduty/rum/android-sdk-integration) 完成基础 SDK 集成后，SDK 会自动捕获应用中的未处理异常。
</Note>

### 添加 NDK 崩溃报告

若您的应用包含原生代码（C/C++），需要添加 NDK 崩溃报告模块来捕获原生崩溃。

<Steps>
  <Step title="添加依赖">
    在您的应用模块的 `build.gradle` 文件中添加 NDK 崩溃报告依赖：

    ```groovy build.gradle theme={null}
    dependencies {
        implementation "cloud.flashcat:fc-sdk-android-ndk:0.1.0"
    }
    ```
  </Step>

  <Step title="启用 NDK 崩溃报告">
    在 SDK 初始化后启用 NDK 崩溃报告：

    ```kotlin theme={null}
    import cloud.flashcat.android.ndk.NdkCrashReports

    // 在 Flashcat.initialize() 之后调用
    NdkCrashReports.enable()
    ```
  </Step>
</Steps>

### 添加 ANR 报告

ANR（Application Not Responding）是指应用主线程被阻塞超过一定时间，导致应用无法响应用户输入的情况。

#### 启用 ANR 检测

在 RUM 配置中启用 ANR 检测：

```kotlin theme={null}
import cloud.flashcat.android.rum.RumConfiguration

val rumConfig = RumConfiguration.Builder(applicationId)
    .trackNonFatalAnrs(true) // 追踪非致命 ANR
    .build()
```

<Tip>
  ANR 检测会监控主线程的响应性。当检测到主线程阻塞超过阈值时，SDK 会自动记录 ANR 事件。
</Tip>

## 手动错误上报

通过 `addError` API，您可以手动上报已处理的异常、自定义错误或其他未被自动捕获的错误。

### 上报错误示例

```kotlin theme={null}
import cloud.flashcat.android.rum.GlobalRum
import cloud.flashcat.android.rum.RumErrorSource

// 上报带有上下文的错误
try {
    riskyOperation()
} catch (e: Exception) {
    GlobalRum.get().addError(
        message = "操作失败",
        source = RumErrorSource.SOURCE,
        throwable = e,
        attributes = mapOf(
            "operation" to "riskyOperation",
            "userId" to "12345"
        )
    )
}
```

### 错误来源类型

`RumErrorSource` 可选值：

| 值                        | 描述         |
| ------------------------ | ---------- |
| `RumErrorSource.NETWORK` | 网络错误       |
| `RumErrorSource.SOURCE`  | 源码错误       |
| `RumErrorSource.CONSOLE` | 控制台错误      |
| `RumErrorSource.LOGGER`  | 日志错误       |
| `RumErrorSource.AGENT`   | Agent 错误   |
| `RumErrorSource.WEBVIEW` | WebView 错误 |
| `RumErrorSource.CUSTOM`  | 自定义错误      |

### 上报网络错误示例

```kotlin theme={null}
import cloud.flashcat.android.rum.GlobalRum
import cloud.flashcat.android.rum.RumErrorSource

fun onNetworkError(url: String, statusCode: Int, error: Throwable) {
    GlobalRum.get().addError(
        message = "网络请求失败: $url",
        source = RumErrorSource.NETWORK,
        throwable = error,
        attributes = mapOf(
            "url" to url,
            "status_code" to statusCode,
            "method" to "GET"
        )
    )
}
```

## 获取脱混淆的堆栈跟踪

如果您的应用启用了代码混淆（ProGuard/R8），上报的崩溃堆栈将被混淆。通过上传 mapping 文件，可以将混淆后的堆栈还原为原始的类名、方法名和行号。

### 配置 Gradle 插件

<Steps>
  <Step title="添加插件依赖">
    在项目根目录的 `build.gradle` 文件中添加 Flashcat Gradle 插件：

    ```groovy build.gradle theme={null}
    buildscript {
        dependencies {
            classpath "cloud.flashcat:fc-gradle-plugin:0.1.0"
        }
    }
    ```
  </Step>

  <Step title="应用插件">
    在应用模块的 `build.gradle` 文件中应用插件：

    ```groovy build.gradle theme={null}
    plugins {
        id 'cloud.flashcat.android'
    }
    ```
  </Step>

  <Step title="配置插件">
    在 `build.gradle` 文件中配置 Flashcat 插件：

    ```groovy build.gradle theme={null}
    flashcat {
        site = "FLASHCAT_SITE"         // 数据上报站点
        clientToken = "<CLIENT_TOKEN>" // 客户端令牌
        serviceName = "<SERVICE_NAME>" // 服务名称(可选)
        versionName = "1.0.0"          // 应用版本(可选，默认取 android.defaultConfig.versionName)
    }
    ```
  </Step>
</Steps>

### 上传 Mapping 文件

配置完成后，插件会在构建过程中自动上传 mapping 文件。您也可以手动运行上传任务：

```bash theme={null}
./gradlew uploadMapping<Variant>
```

例如，对于 `release` 变体：

```bash theme={null}
./gradlew uploadMappingRelease
```

### 上传 NDK 符号文件

如果您使用了 NDK 崩溃报告，还需要上传 NDK 符号文件以获取可读的原生堆栈：

```bash theme={null}
./gradlew uploadNdkSymbolFiles<Variant>
```

### 插件配置选项

| 属性名                        | 描述                                                               |
| -------------------------- | ---------------------------------------------------------------- |
| `versionName`              | 应用版本名称（默认取 `android` 块中声明的版本）                                    |
| `serviceName`              | 服务名称（默认取应用包名）                                                    |
| `site`                     | 数据上报站点                                                           |
| `checkProjectDependencies` | 控制插件是否检查 Flashcat SDK 依赖。可选值：`none`（忽略）、`warn`（警告）、`fail`（失败，默认） |

### Mapping 文件大小限制

Mapping 文件大小限制为 **500 MB**。如果文件过大，可以使用以下选项减小文件大小：

```groovy build.gradle theme={null}
flashcat {
    mappingFileTrimIndents = true  // 移除缩进，平均减少约 5% 的文件大小

    mappingFilePackageAliases = [
        "kotlinx.coroutines": "kx.cor",
        "com.google.android.material": "material",
        "com.google.gson": "gson"
    ]
}
```

<Tip>
  使用 `mappingFilePackageAliases` 时，Flashcat 异常追踪中的堆栈将使用别名替代原始包名。建议仅对第三方依赖使用此选项。
</Tip>

## 追踪后台事件

默认情况下，只有在视图处于活动状态时发生的崩溃才会被追踪。如果您希望追踪应用在后台时发生的崩溃，可以启用后台事件追踪：

```kotlin theme={null}
import cloud.flashcat.android.rum.RumConfiguration

val rumConfig = RumConfiguration.Builder(applicationId)
    .trackBackgroundEvents(true)
    .build()
```

<Warning>
  追踪后台事件可能会产生额外的会话，这可能会影响计费。如有疑问，请联系 Flashcat 支持团队。
</Warning>

## 限制与注意事项

### 崩溃检测限制

* **SDK 初始化时机**：崩溃只有在 SDK 初始化之后才能被检测到。建议在 `Application.onCreate()` 中尽早初始化 SDK。
* **视图关联**：崩溃必须与一个 RUM 视图关联。若在视图显示前或应用被置于后台后发生崩溃，该崩溃可能不会被报告。可通过 `trackBackgroundEvents(true)` 缓解这一问题。
* **采样率影响**：只有被采样的会话中的崩溃才会被保留。如果会话采样率不是 100%，部分崩溃可能不会被报告。

### 符号化限制

* 确保 mapping 文件在每次发布新版本时都正确上传。
* 不同构建变体（如 debug/release）需要分别上传对应的 mapping 文件。
* NDK 符号文件需要包含调试信息才能正确符号化。

## 测试验证

### 验证 Java/Kotlin 崩溃

1. 在应用中添加测试代码触发崩溃：

```kotlin theme={null}
fun onEvent() {
    throw RuntimeException("测试崩溃")
}
```

2. 运行应用并触发崩溃
3. 重启应用，等待 SDK 上传崩溃报告
4. 在 Flashcat 控制台的异常追踪模块中查看崩溃报告

### 验证 NDK 崩溃

1. 在原生代码中添加测试崩溃：

```cpp theme={null}
void crash() {
    int* ptr = nullptr;
    *ptr = 42;  // 触发空指针崩溃
}
```

2. 从 Java/Kotlin 代码调用该原生方法
3. 重启应用，等待 SDK 上传崩溃报告
4. 确认堆栈是否已被正确符号化（显示函数名、文件名和行号）

### 验证 ANR

1. 在主线程执行耗时操作：

```kotlin theme={null}
fun blockMainThread() {
    Thread.sleep(10000)  // 阻塞主线程 10 秒
}
```

2. 触发该操作后尝试与应用交互
3. 检查 Flashcat 控制台是否收到 ANR 报告

## 错误数据结构

每条错误数据包含以下属性：

| 属性               | 类型      | 描述                                       |
| ---------------- | ------- | ---------------------------------------- |
| `error.source`   | string  | 错误来源（如 `source`、`network`、`custom`）      |
| `error.type`     | string  | 错误类型或错误码（如 `NullPointerException`）       |
| `error.message`  | string  | 错误消息                                     |
| `error.stack`    | string  | 错误堆栈跟踪                                   |
| `error.is_crash` | boolean | 是否为崩溃                                    |
| `context`        | Object  | 自定义上下文信息，通过 `addError` 的 `attributes` 传入 |

## 最佳实践

1. **尽早初始化 SDK**：在 `Application.onCreate()` 中初始化 SDK，确保能捕获尽可能多的崩溃。

2. **启用后台事件追踪**：如果您的应用有大量后台操作，建议启用 `trackBackgroundEvents`。

3. **正确上传符号文件**：

   * 为每个发布版本上传对应的 mapping 文件
   * 如果使用 NDK，同时上传 NDK 符号文件
   * 在 CI/CD 流程中集成符号文件上传

4. **丰富错误上下文**：在手动上报错误时，附加业务相关的上下文信息（如用户 ID、操作类型）。

5. **过滤无关错误**：使用 `setErrorEventMapper` 过滤第三方 SDK 或无关的错误，减少噪音。

## 下一步

<CardGroup cols={2}>
  <Card title="查看异常" icon="eye" href="/zh/rum/error-tracking/error-viewing">
    了解如何在异常追踪模块查看和分析 Issue
  </Card>

  <Card title="高级配置" icon="sliders" href="/zh/rum/sdk/android/advanced-config">
    配置 Android SDK 的高级功能
  </Card>
</CardGroup>
