# Android SDK · JNI 把 Java 接到 C++ 核心

> Android 上的 WebRTC 是一层 JNI 桥：Java 的 PeerConnection 对象背后握着一个 native 指针，方法调用经 JNI 转到 C++ 核心。这一章读 android/ 的 native_api，讲清 JNI 桥的机制、scoped_java_ref/jvm 这些工具，以及跨语言时线程和引用管理的坑。

- 作者：David（道雾轩）
- 专栏：音视频与 WebRTC 详解（https://daiw.org/manual/webrtc.md）
- 最后更新：2026-07-15
- 原文：https://daiw.org/manual/webrtc/android-sdk
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# Android SDK · JNI 把 Java 接到 C++ 核心

[上一章](https://daiw.org/manual/webrtc/platform-overview)说各平台在 [`api/` 核心](https://daiw.org/manual/webrtc/factory-and-context)上加一层[语言绑定](https://daiw.org/manual/webrtc/platform-overview)。Android 这层用的是 **JNI**（Java Native Interface）——让 Java/Kotlin 代码调到底层 C++。这一章看它怎么搭。

## Java 对象背后握着一个 native 指针

Android 开发者用的是 Java 类：`PeerConnectionFactory`、`PeerConnection`、`VideoTrack`……但它们只是**壳**：

<Callout type="info">
  **每个 Java 侧的 WebRTC 对象（如 `PeerConnection`）内部握着一个 **native 指针**（`long nativePeerConnection`），指向 C++ 侧真正的 [`PeerConnectionInterface`](https://daiw.org/manual/webrtc/peer-connection-object)。Java 方法调用经 **JNI** 转成对那个 C++ 对象的调用。** 于是：

  - Java 侧 `peerConnection.createOffer(...)` → JNI → C++ 侧 [`PeerConnectionInterface::CreateOffer`](https://daiw.org/manual/webrtc/offer-answer-handler)。
  - C++ 侧的[回调 / 事件](https://daiw.org/manual/webrtc/proxy-pattern)（如 `onIceCandidate`）→ JNI 反向调用 → Java 侧的 `Observer`。

  **Java 类是“遥控器”，真正干活的是 C++ 核心**——[协商、ICE、编解码、拥塞控制](https://daiw.org/manual/webrtc/call-recap)全在 native 层跑，和 [iOS](https://daiw.org/manual/webrtc/ios-sdk)、桌面共享同一份代码。Java 侧只负责“把 Android 应用的调用转下去、把核心的事件转上来”。这就是[上一章说的薄绑定](https://daiw.org/manual/webrtc/platform-overview)：Android SDK 的绝大部分工作，是**把 [`api/` 的 C++ 接口](https://daiw.org/manual/webrtc/factory-and-context)一对一映射成 Java 接口**。
</Callout>

## native_api：JNI 桥的工具箱

搭这座桥不简单——JNI 有一堆繁琐又易错的细节，WebRTC 在 `android/native_api/jni/` 封了一套工具：

| 工具（源码） | 解决什么 |
| --- | --- |
| `jvm.h` | 持有 `JavaVM*`，管理 [JVM 生命周期](https://daiw.org/manual/webrtc/android-sdk)，让 C++ 任意线程能找到 JVM |
| `scoped_java_ref.h` | [RAII 管理 JNI 引用](https://daiw.org/manual/webrtc/scoped-refptr)（local/global ref），防止[引用泄漏](https://daiw.org/manual/webrtc/scoped-refptr) |
| `class_loader.h` | 缓存 Java 类的加载（JNI 查类很贵） |
| `java_types.h` | Java ↔ C++ 类型转换（String、List、byte[] 的编组） |
| `application_context_provider.h` | 拿到 Android 的 `Context`（很多平台能力要它） |

<Callout type="info">
  **`scoped_java_ref` 值得单说——它是 [`scoped_refptr` 思想](https://daiw.org/manual/webrtc/scoped-refptr)在 JNI 上的翻版。** JNI 的引用分 local（方法返回自动失效）和 global（手动管理、忘了删就泄漏），裸用极易出错。`ScopedJavaLocalRef` / `ScopedJavaGlobalRef` 用 [RAII](https://daiw.org/manual/webrtc/scoped-refptr) 把“删引用”绑到析构上——出作用域自动清理，和 [C++ 侧的引用计数哲学](https://daiw.org/manual/webrtc/scoped-refptr)一脉相承。**跨语言边界的资源管理，和[核心里的对象生命周期管理](https://daiw.org/manual/webrtc/scoped-refptr)是同一套 RAII 思路**——这正是[第 10 部分地基](https://daiw.org/manual/webrtc/rtc-base-recap)的思想在平台层的延续。
</Callout>

## 跨语言的两个经典坑：线程与引用

JNI 桥最容易出问题的两处，恰好呼应[第 10 部分的主题](https://daiw.org/manual/webrtc/rtc-base-recap)：

- **线程附着** —— C++ 的[任意线程](https://daiw.org/manual/webrtc/threading-model)要调 Java，必须先 `AttachCurrentThread` 到 JVM（否则崩溃），用完 detach。WebRTC 的 [worker/network 线程](https://daiw.org/manual/webrtc/threading-model)是 native 创建的，回调 Java 前都要处理附着。这是“[native 线程模型](https://daiw.org/manual/webrtc/thread-and-taskqueue)”撞上“JVM 线程模型”的接缝。
- **引用生命周期** —— C++ 侧长期持有一个 Java 对象（如 `Observer`），必须用 **global ref**（local ref 出了 JNI 方法就失效），且用完要删——这又回到[引用管理](https://daiw.org/manual/webrtc/scoped-refptr)，`scoped_java_ref` 就是为此。

```mermaid
flowchart LR
    subgraph Java["Java / Kotlin 层"]
        JPC["PeerConnection(壳)<br/>long nativePeerConnection"]
        OBS["Observer(回调)"]
    end
    subgraph JNI["JNI 桥(android/)"]
        BR["jvm / scoped_java_ref / java_types"]
    end
    subgraph Native["C++ 核心(api/)"]
        CPC["PeerConnectionInterface"]
    end
    JPC -->|"调用向下"| BR --> CPC
    CPC -->|"事件向上(需附着线程)"| BR --> OBS
```

**Android SDK 的复杂度几乎全在这座桥上**，而非 WebRTC 逻辑本身——逻辑都在[共享的 C++ 核心](https://daiw.org/manual/webrtc/call-recap)里。理解这点，你调 Android WebRTC 的 bug 时就知道：多数“诡异问题”要么在 [JNI 边界](https://daiw.org/manual/webrtc/android-sdk)（线程 / 引用），要么在[下面的核心](https://daiw.org/manual/webrtc/call-recap)（那就和其他平台一样，回到[前十一部分](https://daiw.org/manual/webrtc/call-recap)）。

## 小结与下一章

Android 的 WebRTC 是一层 **JNI 桥**：每个 Java 对象（`PeerConnection` 等）握着 **native 指针**指向 C++ 侧的 [`api/` 对象](https://daiw.org/manual/webrtc/peer-connection-object)，调用经 JNI [双向转发](https://daiw.org/manual/webrtc/proxy-pattern)——Java 是遥控器，[C++ 核心](https://daiw.org/manual/webrtc/call-recap)干活。`android/native_api/jni/` 封了工具箱：`jvm`（[JVM 生命周期](https://daiw.org/manual/webrtc/android-sdk)）、`scoped_java_ref`（[RAII 管 JNI 引用，`scoped_refptr` 的翻版](https://daiw.org/manual/webrtc/scoped-refptr)）、`java_types`（类型编组）等。两个经典坑——**线程附着**（[native 线程调 Java 前须 attach](https://daiw.org/manual/webrtc/threading-model)）和**引用生命周期**（[长期持有须用 global ref](https://daiw.org/manual/webrtc/scoped-refptr)）——都是[第 10 部分主题](https://daiw.org/manual/webrtc/rtc-base-recap)在跨语言边界的再现。

Apple 平台的绑定是另一套风味。下一章看 iOS/macOS 的 Objective-C 封装。👉 [iOS SDK 与 Objective-C](https://daiw.org/manual/webrtc/ios-sdk)。

## 参考资料

- [1] libwebrtc 源码.`sdk/android/native_api/jni/`（`jvm.h`、`scoped_java_ref.h`、`java_types.h`、`class_loader.h`）。
- [2] libwebrtc 源码.`sdk/android/native_api/peerconnection/`、`sdk/android/src/jni/`。
- [3] 关联[引用计数](https://daiw.org/manual/webrtc/scoped-refptr)、[线程模型](https://daiw.org/manual/webrtc/threading-model)、[代理模式](https://daiw.org/manual/webrtc/proxy-pattern)。
