web page、extension和native messaging host三者之间用UTF-8编码的json字符串通讯。
web page同extension之间进行message exchange,extension同native messaging host之间message exchange.#include "stdafx.h" /* Title: native messaging c++ program Author: kagula Date: 2015-10-22 */ #include <stdio.h> #include <fcntl.h> #include <io.h> #include "SimpleLog.h" #include <iostream> #include <string> #include <sstream> using namespace std; void sendMessage(const string &strMsg) { // We need to send the 4 bytes of length information unsigned int len = strMsg.length(); std::cout << char(((len >> 0) & 0xFF)) << char(((len >> 8) & 0xFF)) << char(((len >> 16) & 0xFF)) << char(((len >> 24) & 0xFF)); //output integer value directly will lead byte order problem. // Now we can output our message cout << strMsg; cout.flush(); } simpleLogClass logger; int _tmain(int argc, _TCHAR* argv[]) { logger.fileMaxSize = 64*1024; logger.fileName = "e:\\a.log"; logger.fileOldName = "e:\\a.old.log"; _setmode(_fileno(stdin), O_BINARY); _setmode(_fileno(stdout), O_BINARY); _setmode(_fileno(stderr), O_BINARY); int bufSize; do { bufSize = 0; //unlike >> operator and scanf function, //read function will wait until read all 4 bytes! cin.read((char*)&bufSize, 4); stringstream ss; ss << "bufSize = " << bufSize << endl; logger.info(ss.str()); if (bufSize> 0) { char *pData = new char[bufSize+1]; memset(pData, 0, bufSize + 1); cin.read(pData, bufSize); string response = "{\"echo\":"; response.append(pData); response.append("}"); sendMessage(response); logger.info(response); delete pData; } else { break; } } while (true); return 0; }
{ "name": "com.google.chrome.example.echo", "description": "Chrome Native Messaging API Example Host", "path": "chrome_native_messaging_host.exe", "type": "stdio", "allowed_origins": [ "chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/" ] }
注意host name中不能出现大写字母。
<!DOCTYPE html> <!-- * Copyright 2013 The Chromium Authors. All rights reserved. Use of this * source code is governed by a BSD-style license that can be found in the * LICENSE file. --> <html> <head> <script src='./main.js'></script> </head> <body> <button id='connect-button'>Connect</button> <input id='input-text' type='text' /> <button id='send-message-button'>Send</button> <div id='response'></div> </body> </html>
// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. var port = null; var getKeys = function(obj){ var keys = []; for(var key in obj){ keys.push(key); } return keys; } function appendMessage(text) { document.getElementById('response').innerHTML += "<p>" + text + "</p>"; } function updateUiState() { if (port) { document.getElementById('connect-button').style.display = 'none'; document.getElementById('input-text').style.display = 'block'; document.getElementById('send-message-button').style.display = 'block'; } else { document.getElementById('connect-button').style.display = 'block'; document.getElementById('input-text').style.display = 'none'; document.getElementById('send-message-button').style.display = 'none'; } } function sendNativeMessage() { message = {"text": document.getElementById('input-text').value}; port.postMessage(message); appendMessage("Sent message: <b>" + JSON.stringify(message) + "</b>"); } function onNativeMessage(message) { appendMessage("Received message: <b>" + JSON.stringify(message) + "</b>"); } function onDisconnected() { appendMessage("Failed to connect: " + chrome.runtime.lastError.message); port = null; updateUiState(); } function connect() { var hostName = "com.google.chrome.example.echo"; appendMessage("Connecting to native messaging host <b>" + hostName + "</b>") port = chrome.runtime.connectNative(hostName); port.onMessage.addListener(onNativeMessage); port.onDisconnect.addListener(onDisconnected); updateUiState(); } document.addEventListener('DOMContentLoaded', function () { document.getElementById('connect-button').addEventListener( 'click', connect); document.getElementById('send-message-button').addEventListener( 'click', sendNativeMessage); updateUiState(); });
function focusOrCreateTab(url) { chrome.windows.getAll({"populate":true}, function(windows) { var existing_tab = null; for (var i in windows) { var tabs = windows[i].tabs; for (var j in tabs) { var tab = tabs[j]; if (tab.url == url) { existing_tab = tab; break; } } } if (existing_tab) { chrome.tabs.update(existing_tab.id, {"selected":true}); } else { chrome.tabs.create({"url":url, "selected":true}); } }); } chrome.browserAction.onClicked.addListener(function(tab) { var manager_url = chrome.extension.getURL("main.html"); focusOrCreateTab(manager_url); }); document.addEventListener("DOMContentLoaded", function () { }); var port = null; var hostName = "com.google.chrome.example.echo"; function connect() { port = chrome.runtime.connectNative(hostName); port.onMessage.addListener(onNativeMessage); port.onDisconnect.addListener(onDisconnected); } function onNativeMessage(message) { console.log("onNativeMessage=>"+JSON.stringify(message)); chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { chrome.tabs.sendMessage(tabs[0].id, {data: JSON.stringify(message)}, function(response) { console.log(JSON.stringify(message)); }); }); } function onDisconnected() { port = null; } chrome.runtime.onMessageExternal.addListener( function(request, sender, sendResponse) { console.log("chrome.runtime.onMessageExternal.addListener in background.js"); if (request.data) var data = request.data; if(data=="connect") { connect(); } else { if(port==null) { console.log("disconnect with"+hostName); return; } console.log("Hi, there is message ["+data+"]from the website"); var message = {"text": request.data}; port.postMessage(message); } });
function appendMessage(text) { document.getElementById('response_div_id').innerHTML += "<p>" + text + "</p>"; } chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { if (request.data != null) { console.log("get response from extension" + request.data); appendMessage("get response from extension" + request.data); console.log("create custom event"); var evt = new CustomEvent('Event'); evt.initCustomEvent('customEvent', true, true, {'data': request.data}); console.log("fire custom event"); document.getElementById('response_div_id').dispatchEvent(evt) } });
manifest.json源码清单
{ "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcBHwzDvyBQ6bDppkIs9MP4ksKqCMyXQ/A52JivHZKh4YO/9vJsT3oaYhSpDCE9RPocOEQvwsHsFReW2nUEc6OLLyoCFFxIb7KkLGsmfakkut/fFdNJYh0xOTbSN8YvLWcqph09XAY2Y/f0AL7vfO1cuCqtkMt8hFrBGWxDdf9CQIDAQAB", "name": "Native Messaging Example", "version": "1.0", "manifest_version": 2, "description": "Send a message to a native application.", "browser_action": { "default_icon": "icon-16.png" }, "icons": { "16": "icon-16.png", "48": "icon-128.png", "128": "icon-128.png" }, "permissions": [ "nativeMessaging", "tabs", "http://*/*", "https://*/*" ], "content_scripts": [ { "matches": ["http://*/*"], "js": ["content.js"] } ], "externally_connectable": {"matches": ["*://*.example.com/*"]}, "background" : { "scripts": ["background.js"] } }
<html> <head> <Script type="text/javascript"> window.onload=function(){ //after html loaded var obj = document.getElementById('response_div_id'); obj.addEventListener('customEvent', function(e){ console.log('customEvent 事件触发了=>'+e.detail.data); }, false); } // The ID of the extension we want to talk to. var kagulaExtensionId = "pldlmdbmiepkhemhgofdefdomcmamcfk"; function requestConnect() { console.log("connect"); chrome.runtime.sendMessage(kagulaExtensionId, {data: "connect"}); } function requestEcho() { console.log("Make a simple request"); var reqData = document.getElementById('input-text').value; chrome.runtime.sendMessage(kagulaExtensionId, {data: reqData}, function(response) { alert(response); }); } </Script> </head> <body> <button id='connect-button' OnClick="javascript:requestConnect()">连接</button> <input id='input-text' type='text' value='fromKagula'/> <button id='send-message-button' OnClick="javascript:requestEcho()">发送消息</button> <div id="response_div_id"></div> </body> </html>