天天看點

Chrome 插件: 起動本地應用 (Native messaging)

轉自:http://www.myexception.cn/internet/1729118.html

最近碰到了一個新問題,需要利用Chrome 的插件, 從我們的一個網站中啟動一個我們的本地C#應用,同時給這個應用傳值來進行不同的操作。

在這裡記錄下解決的過程,以便以後查找

首先我們需要建立一個google的插件 這個插件包含了三個檔案

manifest.json(名字不可改, 建插件必須檔案),background.js(檔案名可改, 背景檔案),content.js(content script檔案 負責與網站頁面互動)

首先我們來看看manifest.json 這個檔案

<span style="font-family:SimSun;font-size:18px;">{
	"name" : "FastRun",
	"version" : "1.0.1",
	"description" : "Launch APP ",
	"background" : { "scripts": ["background.js"] },

	"permissions" : [
		"nativeMessaging",
		"tabs",
		"http://xxx/*"
	],
	"content_scripts": [
    {
      "matches": ["http://xxx/*"],
      "js": ["content.js"]
    }
	],
	"minimum_chrome_version" : "6.0.0.0",
	"manifest_version": 2
}</span>
           

裡面的premissions非常重要, 他表示我們的插件在什麼條件運作, "nativeMessaging" 代表要在這個插件中允許調用這種方法

 "xxx"填入你想要的載入的網址 

"content_scripts" 中"xxx" 表示在什麼網頁下運作我們與界面互動的script.

再來看看背景檔案

background.js

var port = null; 
chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
     if (request.type == "launch"){
       	connectToNativeHost(request.message);
    }
	return true;
});


//onNativeDisconnect
function onDisconnected()
{
	console.log(chrome.runtime.lastError);
	console.log('disconnected from native app.');
	port = null;
}

function onNativeMessage(message) {
	console.log('recieved message from native app: ' + JSON.stringify(message));
}

//connect to native host and get the communicatetion port
function connectToNativeHost(msg)
{
	var nativeHostName = "com.my_company.my_application";
	console.log(nativeHostName);
 	port = chrome.runtime.connectNative(nativeHostName);
	port.onMessage.addListener(onNativeMessage);
	port.onDisconnect.addListener(onDisconnected);
	port.postMessage({message: msg});	
 } 
           

在這個檔案裡有兩個方法非常重要 

chrome.runtime.onMessage.addListener

connectToNativeHost

先來看第一個方法,

是一個響應事件,當接收到類型為"launch"的消息時, 調用 connectToNativeHost方法并傳入資料。

com.my_company.my_application

這個是我們之後需要注冊在Regestry和Native Messaging裡面的名字 之後會講到。

runtime.connectNative這個方法連接配接我們的Native Messaging然後利用 postMessage 去發送我們要的資訊給我們的本地應用

當然這裡我們可以替換為 sendNativeMessage 直接給本地應用傳值詳見

https://developer.chrome.com/extensions/runtime#method-connectNative

我們在來看看ContentScript: content.js這個檔案

<span style="font-family:SimSun;"><span style="font-size:18px;">var launch_message;
document.addEventListener('myCustomEvent', function(evt) {
chrome.runtime.sendMessage({type: "launch", message: evt.detail}, function(response) {
  console.log(response)
});
}, false);</span><strong>
</strong></span>
           

很簡單, 響應了一個頁面中的事件"myCustomEvent", 同時釋出一個消息給我們的背景檔案background.js,這個消息包含了消息标示 "launch" 和 我們要傳的值 evt.detail

關于Content Script 的資訊 詳見 https://developer.chrome.com/extensions/content_scripts

到這裡我們的google插件部分就做好了

别忘了在Chrome 插件裡開啟開發者模式 并加載這個插件

-------------------------------------分割線-------------------------------------

我們在來看看 Native Messaging 部分 我們再建一個 json 檔案 我這裡也叫做manifest.json(名字可以不是這個) 存在了我本地C:/Native目錄下

<span style="font-family:SimSun;font-size:18px;">{
	"name": "com.my_company.my_application",
	"description": "Chrome sent message to native app.",
	"path": "C:\\MyApp.exe",
	"type": "stdio",
	"allowed_origins": [
		"chrome-extension://ohmdeifpmliljjdkaehaojmiafihbbdd/"
	]
}</span>
           

這裡我們定義了 Native Messaging 的名字, 在path中定義了我們要運作的本地應用程式, allowed_origins 中長串的字元是我們插件的id 可以在安裝插件後從google chrome 插件裡看到(安裝插件 可以在chrome中插件開啟開發者模式并載入我們之前的插件檔案包)

完成這步以後我們需要在WIndows 系統資料庫 中加入google 項目具體如下:

運作-> Regedit -> HKEY_Current_User->Software->Google->Chrome->建立一個叫NativeMessagingHosts的項->建立一個叫com.my_company.my_application的項,  同時在這個項裡預設值設定為我們Native Messaging 的 位置 C:\\Native\\manifest.json

這樣我們就完成了NativeMessaging的設定

-------------------------------------我是分割線-------------------------------------

我們再來看看這個插件如何和我們的網站互動

先建一個簡單的網頁内容如下

<span style="font-family:SimSun;font-size:18px;"><!DOCTYPE HTML>

<html>
<head>
<script>
function startApp() {
	var evt = document.createEvent("CustomEvent");
	evt.initCustomEvent('myCustomEvent', true, false, "im information");
	// fire the event
	document.dispatchEvent(evt);
}

</script>
</head>
<body>

<button type="button" onClick="startApp()" id="startApp">startApp</button>
</body>
</html>
</span>
           

裡面有一個簡單的按鈕, 這個按鈕會啟動方法, 建立一個名叫"myCustomEvent"的事件, 同時附帶有我們要傳的資訊, 并釋出這個事件。 這樣我們插件中的Content.js 就可以接收并響應這個事件了!

-------------------------------------我是分割線-------------------------------------

我們最後再來看看C#程式, 随便做一個非常簡單的程式, 放到了

C://MyApp.exe這裡

在Main裡面 我們可以加入下面這個方法, 利用Console.OpenStandardInput這個 我們可以接收到由頁面傳到我們應用的值并進行我們想要的一些操作, 在這裡我們用一個log4net 記錄我們程式運作情況

[assembly: log4net.Config.XmlConfigurator(Watch = true)]
namespace MyApp
{
    static class Program
    {
        public static log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        [STAThread]
        static void Main(string[] args)
        {
            
            if (args.Length != 0)
            {
                string chromeMessage = OpenStandardStreamIn();
                log.Info("--------------------My application starts with Chrome Extension message: " + chromeMessage + "---------------------------------");
	        }
	    }

        private static string OpenStandardStreamIn()
        {
             We need to read first 4 bytes for length information
            Stream stdin = Console.OpenStandardInput();
            int length = 0;
            byte[] bytes = new byte[4];
            stdin.Read(bytes, 0, 4);
            length = System.BitConverter.ToInt32(bytes, 0);

            string input = "";
            for (int i = 0; i < length; i++)
            {
                input += (char)stdin.ReadByte();
            }

            return input;
        }
    }
}
           

點選我們在頁面上加入的按鈕, 然後檢查log檔案:

2014-07-30 09:23:14,562 [1] INFO  MyApp.Program ----------------------------------------My application starts with Chrome Extension message: {"message":"im information"}---------------------------------

最後一張圖總結下整個過程

Chrome 插件: 起動本地應用 (Native messaging)

如果想要在安裝我們本地軟體時安裝這個插件, 我們需要把我們的插件先釋出到Chrome web store上詳見https://developer.chrome.com/extensions/external_extensions 

在這裡就不再贅述了

繼續閱讀