前后端双向 IPC 通信
JadeView 2.0 提供了基于自定义协议的前后端双向 IPC 通信机制,前端通过 jade.invoke / jade.on 与宿主 C/C++ 代码高效交换数据。
通信模型
前端 (JavaScript) 宿主 (C/C++)
│ │
├─ jade.invoke('命令', 数据) ──────►│ register_ipc_handler 回调
│ │ → 返回 jade_text_create(...)
│ ◄────── Promise resolve ────────┤
│ │
├─ jade.on('事件', callback) ──────►│ 注册监听
│ ◄── send_ipc_message(事件,数据)─┤ 主动推送
- 请求-响应:前端
jade.invoke→ 宿主register_ipc_handler回调 → 返回值回到前端 - 事件推送:宿主
send_ipc_message→ 前端jade.on回调
前端到宿主(jade.invoke)
前端代码
// 调用宿主方法,等待返回结果
const result = await jade.invoke('get-config', { key: 'theme' });
console.log('宿主返回:', result);
// 带超时
const data = await jade.invoke('heavy-task', payload, { timeout: 10000 });
宿主 C 代码
#include "jadeview.h"
// IPC 回调:处理前端 jade.invoke('get-config', ...)
const char* get_config_callback(uint32_t window_id, const char* event_data) {
printf("收到 get-config,窗口: %u, 数据: %s\n", window_id, event_data);
// 处理逻辑...
// 返回结果给前端(必须用 jade_text_create 分配)
return jade_text_create("{\"theme\":\"dark\",\"lang\":\"zh\"}");
}
// 在 app-ready 中注册
const char* app_ready_callback(uint32_t window_id, const char* event_data) {
if (window_id == 1 && event_data
&& strcmp(event_data, "success") == 0) {
// 注册 IPC 处理器
register_ipc_handler("get-config", get_config_callback);
// 创建窗口...
}
return NULL;
}
信息
register_ipc_handler 的回调返回值必须用 jade_text_create 分配,库会自动调用 jade_text_free 释放。返回 NULL 表示返回默认成功 JSON。
宿主到前端(send_ipc_message + jade.on)
宿主 C 代码
// 向前端推送事件
void notify_frontend(uint32_t window_id) {
send_ipc_message(window_id, "data-update",
"{\"status\":\"ok\",\"timestamp\":123456}");
}
前端代码
// 订阅宿主推送的事件
const off = jade.on('data-update', (payload) => {
console.log('宿主推送:', payload);
// payload 已是解析后的对象
});
// 不需要时取消订阅
// off();
完整示例
前端
// 1. 初始化时向宿主请求数据
(async function() {
try {
const config = await jade.invoke('get-config', {});
console.log('配置:', config);
} catch (e) {
console.error('请求失败:', e);
}
})();
// 2. 订阅宿主通知
jade.on('data-update', (data) => {
document.getElementById('status').textContent = data.status;
});
// 3. 按钮触发宿主操作
document.getElementById('btn').onclick = async () => {
const result = await jade.invoke('do-action',
{ action: 'save', value: 'hello' });
console.log('结果:', result);
};
宿主 (C)
#include <stdio.h>
#include <string.h>
#include "jadeview.h"
// 处理 get-config
const char* get_config_callback(uint32_t window_id, const char* event_data) {
return jade_text_create("{\"theme\":\"dark\",\"version\":\"2.1\"}");
}
// 处理 do-action
const char* do_action_callback(uint32_t window_id, const char* event_data) {
printf("do-action 收到: %s\n", event_data);
// 处理完后向前端推送结果
send_ipc_message(window_id, "data-update",
"{\"status\":\"saved\"}");
return jade_text_create("{\"ok\":true}");
}
const char* app_ready_callback(uint32_t window_id, const char* event_data) {
if (window_id == 1 && event_data
&& strcmp(event_data, "success") == 0) {
// 注册 IPC 处理器
register_ipc_handler("get-config", get_config_callback);
register_ipc_handler("do-action", do_action_callback);
// 创建窗口
WebViewWindowOptions options = {
.title = "IPC 示例",
.width = 800,
.height = 600,
.frame_style = "normal"
};
create_webview_window("https://example.com", 0, &options, NULL);
}
return NULL;
}
int main() {
jade_on("app-ready", app_ready_callback);
int result = JadeView_init(
1, NULL, NULL,
"IPC 示例",
"com.example.ipc",
0
);
if (result == 0) {
printf("初始化失败\n");
return 1;
}
printf("JadeView 已启动\n");
return 0;
}
命名建议
- 命令名/事件名使用 kebab-case:
get-config、data-update - 前端
jade.invoke第一参数与宿主register_ipc_handler第一参数完全一致(区分大小写) - 前端
jade.on第一参数与宿主send_ipc_message第二参数完全一致
注意事项
- 宿主
register_ipc_handler回调返回值必须用jade_text_create分配 - 前端
jade.on返回取消函数,不需要时调用off()防止泄漏 - 单次传输数据建议控制在约 252MB 以内
- 前端 API 仅在通过 JadeView 协议加载的页面中可用(
set_protocol_service_path或 JAPK)
详细 API 参考:前端通信 API | IPC 通信 API | 事件类型