JCEF 和 Java 之间的通信方法

JCEF 和 Java 之间的通信方法

JCEF (Java Chromium Embedded Framework) 是一个将 Chromium 浏览器嵌入 Java 应用程序的框架。以下是 JCEF 中实现 Java 和 JavaScript 双向通信的几种主要方法。

1. 基本通信架构

JCEF 中的通信主要通过以下方式实现:

  • Java → JavaScript:通过 executeJavaScript 方法
  • JavaScript → Java:通过注册 Java 处理器供 JavaScript 调用

2. Java 调用 JavaScript

基本调用方式

// 获取浏览器对象
CefBrowser browser = ...;

// 执行JavaScript代码
browser.executeJavaScript("alert('Hello from Java!');", browser.getURL(), 0);

// 调用函数并获取返回值
browser.executeJavaScript(
    "document.getElementById('myElement').value;", 
    browser.getURL(), 
    0
);

带回调的调用

browser.executeJavaScript(
    "function getData() { return {name: 'John', age: 30}; } getData();",
    browser.getURL(),
    0,
    new CefV8Value.CefV8ValueHandler() {
        @Override
        public boolean execute(String name, CefV8Value object, CefV8Value[] arguments) {
            // 处理返回值
            return true;
        }
    }
);

3. JavaScript 调用 Java

3.1 使用 MessageRouter

这是推荐的方式,支持异步通信。

Java 端设置

// 创建消息路由器
CefMessageRouter msgRouter = CefMessageRouter.create();

// 添加处理器
msgRouter.addHandler(new CefMessageRouter.CefMessageRouterHandler() {
    @Override
    public boolean onQuery(CefBrowser browser, long queryId, String request, 
                          boolean persistent, CefQueryCallback callback) {
        if (request.equals("getUserData")) {
            // 处理请求
            callback.success("{\"name\":\"John\", \"age\":30}");
            return true;
        }
        return false;
    }
    
    @Override
    public void onQueryCanceled(CefBrowser browser, long queryId) {
        // 查询被取消
    }
}, true);

// 将路由器添加到客户端处理器
clientHandler.addMessageRouter(msgRouter);

JavaScript 端调用

window.cefQuery({
    request: "getUserData",
    onSuccess: function(response) {
        console.log("Received data:", JSON.parse(response));
    },
    onFailure: function(error_code, error_message) {
        console.error("Error:", error_code, error_message);
    }
});

3.2 注册 Java 对象到 JavaScript

Java 端注册

CefApp.getInstance().registerJsExtension(
    "java_handler", 
    "var myJavaHandler = {};" +
    "myJavaHandler.callMethod = function(name, args) {" +
    "   native function callJavaMethod();" +
    "   return callJavaMethod(name, args);" +
    "};"
);

// 在客户端处理器中
clientHandler.addHandler(new CefClientHandler() {
    @Override
    public boolean onProcessMessageReceived(
        CefBrowser browser, CefProcessId sourceProcess, CefProcessMessage message) {
        if (message.getName().equals("callJavaMethod")) {
            // 处理来自JS的调用
            return true;
        }
        return false;
    }
});

JavaScript 端调用

myJavaHandler.callMethod("methodName", {param1: "value"});

4. 双向通信完整示例

Java 部分

public class MyCefApp {
    private CefBrowser browser;
    private CefMessageRouter msgRouter;

    public void initBrowser(JFrame frame) {
        CefApp cefApp = CefApp.getInstance();
        CefClient client = cefApp.createClient();
        
        // 创建消息路由器
        msgRouter = CefMessageRouter.create();
        msgRouter.addHandler(new MessageRouterHandler(), true);
        client.addMessageRouter(msgRouter);
        
        // 创建浏览器
        browser = client.createBrowser("http://localhost:8080", false, false);
        frame.add(browser.getUIComponent(), BorderLayout.CENTER);
        
        // 注入Java对象
        injectJavaObject();
    }
    
    private void injectJavaObject() {
        String jsCode = "window.javaBridge = {" +
            "invokeJava: function(request, callback) {" +
            "   window.cefQuery({" +
            "       request: JSON.stringify(request)," +
            "       onSuccess: function(response) { callback(null, JSON.parse(response)); }," +
            "       onFailure: function(code, msg) { callback(new Error(msg), null); }" +
            "   });" +
            "}" +
            "};";
        browser.executeJavaScript(jsCode, browser.getURL(), 0);
    }
    
    private class MessageRouterHandler implements CefMessageRouter.CefMessageRouterHandler {
        @Override
        public boolean onQuery(CefBrowser browser, long queryId, String request, 
                              boolean persistent, CefQueryCallback callback) {
            try {
                JSONObject req = new JSONObject(request);
                String method = req.getString("method");
                JSONObject params = req.getJSONObject("params");
                
                // 处理方法调用
                if ("addNumbers".equals(method)) {
                    int result = params.getInt("a") + params.getInt("b");
                    callback.success("{\"result\": " + result + "}");
                } else {
                    callback.failure(404, "Method not found");
                }
            } catch (Exception e) {
                callback.failure(500, e.getMessage());
            }
            return true;
        }
        
        @Override
        public void onQueryCanceled(CefBrowser browser, long queryId) {
            System.out.println("Query cancelled: " + queryId);
        }
    }
    
    public void callJavaScript(String functionName, JSONObject data) {
        String js = functionName + "(" + data.toString() + ");";
        browser.executeJavaScript(js, browser.getURL(), 0);
    }
}

JavaScript 部分

// 调用Java方法
function addNumbers(a, b, callback) {
    javaBridge.invokeJava({
        method: "addNumbers",
        params: {a: a, b: b}
    }, callback);
}

// 使用示例
addNumbers(5, 7, (err, result) => {
    if (err) {
        console.error("Error:", err);
    } else {
        console.log("Result:", result.result);
    }
});

// 接收Java调用
window.onJavaMessage = function(data) {
    console.log("Received from Java:", data);
    return "Ack";
};

5. 安全注意事项

  1. 输入验证:始终验证来自 JavaScript 的输入
  2. 异常处理:妥善处理通信中的异常
  3. 性能考虑:大量数据传输可能影响性能
  4. 资源清理:在窗口关闭时移除消息处理器

6. 调试技巧

  1. 启用远程调试

    CefApp.getInstance().setRemoteDebuggingPort(8088);
    

    然后访问 http://localhost:8088

  2. 日志记录:实现 CefRenderHandler 来捕获控制台输出

  3. 错误处理:重写 CefLoadHandler 来捕获页面加载错误

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值