这篇文章详细讲解了如何在 Android 系统中通过 Native(C++)代码调用 Java 编写的 Binder 服务。我们可以用两种方式实现,以下用通俗的语言分步解释:
核心概念
Binder 是 Android 的跨进程通信(IPC)机制,类似「快递员」在不同进程间传递数据。
- 服务端(Java)提供功能(如计算器)
- 客户端(C++)调用服务端的功能
方法一:手动操作(底层方式)
1. 获取服务
cpp
Copy
sp<IServiceManager> sm = defaultServiceManager(); // 拿到系统服务管理器
sp<IBinder> ibinder = sm->getService(String16("hello")); // 查找名为"hello"的服务
就像在快递站问:"有没有叫'hello'的快递员?"
2. 打包数据
cpp
Copy
Parcel data, reply; // 准备发送和接收的包裹
data.writeInterfaceToken(descriptor); // 告诉服务端你要调用的接口
3. 发送请求
cpp
Copy
ibinder->transact(代码, data, &reply, 0); // 发送包裹,等待回复
类似告诉快递员:"用第一个业务代码(FIRST_CALL_TRANSACTION)把包裹送给服务端"。
4. 处理结果
cpp
Copy
int result = reply.readInt32(); // 拆包裹读取结果
ALOGI("结果: %d", result);
方法二:自动生成(AIDL方式)
1. 定义接口
用 .aidl 文件声明服务接口(如 IHelloService.aidl),工具会自动生成 C++ 和 Java 代码。
2. 生成代码
bash
Copy
aidl-cpp IHelloService.aidl # 生成 C++ 代理类
这会生成类似 IHello.h/cpp 的代码,封装了底层 Binder 操作。
3. 调用服务
cpp
Copy
// 直接调用生成的类方法,就像本地函数!
IHello::getService()->hello();
IHello::getService()->sum(3, 4);
关键对比
| 方式 | 优点 | 缺点 |
|---|---|---|
| 手动操作 | 灵活,适合简单场景 | 代码复杂,容易出错 |
| AIDL生成代码 | 自动处理打包/解包,代码简洁 | 需要提前定义接口,生成代码步骤 |
实战步骤
- 编译代码:用
mm命令编译 Native 客户端。 - 推送文件:将生成的
CppClient和服务端 Jar 包推送到设备。 - 启动服务:在 Android Shell 中运行 Java 服务端。
- 运行客户端:执行 C++ 客户端,查看日志验证结果。
总结
- 底层方式:直接操作 Binder 的
transact(),适合临时需求或学习原理。 - AIDL方式:通过接口定义自动生成代码,更规范、安全,推荐实际开发使用。
两种方法殊途同归,最终都实现了跨语言(C++ ↔ Java)的进程间通信,体现了 Android Binder 的强大灵活性。