CefMessageRouter
The below classes implement support for routing aynchronous messages between JavaScript running in the renderer process and C++ running in the browser process. An application interacts with the router by passing it data from standard CEF C++ callbacks (OnBeforeBrowse, OnProcessMessageRecieved, OnContextCreated, etc). The renderer-side router supports generic JavaScript callback registration and execution while the browser-side router supports application-specific logic via one or more application-provided Handler instances. The renderer-side router implementation exposes a query function and a cancel function via the JavaScript 'window' object: // Create and send a new query. var request_id = window.cefQuery({ request: 'my_request', persistent: false, onSuccess: function(response) {}, onFailure: function(error_code, error_message) {} }); // Optionally cancel the query. window.cefQueryCancel(request_id); When |window.cefQuery| is executed the request is sent asynchronously to one or more C++ Handler objects registered in the browser process. Each C++ Handler can choose to either handle or ignore the query in the Handler::OnQuery callback. If a Handler chooses to handle the query then it should execute Callback::Success when a response is available or Callback::Failure if an error occurs. This will result in asynchronous execution of the associated JavaScript callback in the renderer process. Any queries unhandled by C++ code in the browser process will be automatically canceled and the associated JavaScript onFailure callback will be executed with an error code of -1. Queries can be either persistent or non-persistent. If the query is persistent than the callbacks will remain registered until one of the following conditions are met: A. The query is canceled in JavaScript using the |window.cefQueryCancel| function. B. The query is canceled in C++ code using the Callback::Failure function. C. The context associated with the query is released due to browser destruction, navigation or renderer process termination. If the query is non-persistent then the registration will be removed after the JavaScript callback is executed a single time. If a query is canceled for a reason other than Callback::Failure being executed then the associated Handler's OnQueryCanceled method will be called. Some possible usage patterns include: One-time Request. Use a non-persistent query to send a JavaScript request. The Handler evaluates the request and returns the response. The query is then discarded. Broadcast. Use a persistent query to register as a JavaScript broadcast receiver. The Handler keeps track of all registered Callbacks and executes them sequentially to deliver the broadcast message. Subscription. Use a persistent query to register as a JavaScript subscription receiver. The Handler initiates the subscription feed on the first request and delivers responses to all registered subscribers as they become available. The Handler cancels the subscription feed when there are no longer any registered JavaScript receivers. Message routing occurs on a per-browser and per-context basis. Consequently, additional application logic can be applied by restricting which browser or context instances are passed into the router. If you choose to use this approach do so cautiously. In order for the router to function correctly any browser or context instance passed into a single router callback must then be passed into all router callbacks. There is generally no need to have multiple renderer-side routers unless you wish to have multiple bindings with different JavaScript function names. It can be useful to have multiple browser-side routers with different client- provided Handler instances when implementing different behaviors on a per- browser basis. This implementation places no formatting restrictions on payload content. An application may choose to exchange anything from simple formatted strings to serialized XML or JSON data. EXAMPLE USAGE 1. Define the router configuration. You can optionally specify settings like the JavaScript function names. The configuration must be the same in both the browser and renderer processes. If using multiple routers in the same application make sure to specify unique function names for each router configuration. // Example config object showing the default values. CefMessageRouterConfig config = new CefMessageRouterConfig(); config.jsQueryFunction = "cefQuery"; config.jsCancelFunction = "cefQueryCancel"; 2. Create an instance of CefMessageRouter in the browser process. messageRouter_ = CefMessageRouter.create(config); 3. Register one or more Handlers. The Handler instances must either outlive the router or be removed from the router before they're deleted. messageRouter_.addHandler(myHandler); 4. Add your message router to all CefClient instances you want to get your JavaScript code be handled. myClient.addMessageRouter(messageRouter_); 4. Execute the query function from JavaScript code. window.cefQuery({request: 'my_request', persistent: false, onSuccess: function(response) { print(response); }, onFailure: function(error_code, error_message) {} }); 5. Handle the query in your CefMessageRouterHandler.onQuery implementation and execute the appropriate callback either immediately or asynchronously. public boolean onQuery(CefBrowser browser, long query_id, String request, boolean persistent, CefQueryCallback callback) { if (request.indexOf("my_request") == 0) { callback.success("my_response"); return true; } return false; // Not handled. } 6. Notice that the success callback is executed in JavaScript.