chromium 37 chrome Native messaging 本地消息机制

01 chrome Native messaging

Native messaging 扩展解决chrome与本地程序通信的问题,可以解决从浏览器启动二进制文件的问题。
是通过扩展为browser进程发送信息,有browser进程启动二进制文件或者和指定的二进制文件通信。

下图参考自 Chrome Native Messaging技术示例
native messaging 通信机制

下面是chrome官方提供的扩展demo。
https://github.com/GoogleChrome/chrome-extensions-samples

nativeMessaging

02 具体操作步骤

02.01 保存demo代码

把 代码下载到 google的临时目录下,在 %localappdata%\Google\Chrome\User Data\Default\ 下创建一个Extensions2目录,将 nativeMessaging 放入。效果如下:
存放demo

02.02 加载插件

[更多工具] --> [扩展程序] --> [开发者模式] --> [加载已解压的扩展程序] --> [选择 nativeMessaging\app 路径] --> [加载]
加载插件
加载成功效果
加载成功效果

02.03 注册host 信息

运行 nativeMessaging\host\install_host.bat
查看注册表信息,
查看注册的host信息
实际是注册了如下注册表信息

REG ADD "HKCU\Software\Google\Chrome\NativeMessagingHosts\com.google.chrome.example.echo" /ve /t REG_SZ /d "%~dp0com.google.chrome.example.echo-win.json" /f

运行的内容是 native-messaging-example-host.bat

这里如果在该bat文件中加入需要运行的exe,既可以执行对应的exe,或者直接把bat换成想要运行的其他可执行程序。

@echo off
:: Copyright (c) 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.

python "%~dp0/native-messaging-example-host" %*

而真正运行的是 python脚本 native-messaging-example-host,所以电脑上应该配置好python运行环境。

#!/usr/bin/env python
# Copyright (c) 2012 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.

# A simple native messaging host. Shows a Tkinter dialog with incoming messages
# that also allows to send message back to the webapp.

import struct
import sys
import threading
import Queue

try:
  import Tkinter
  import tkMessageBox
except ImportError:
  Tkinter = None

# On Windows, the default I/O mode is O_TEXT. Set this to O_BINARY
# to avoid unwanted modifications of the input/output streams.
if sys.platform == "win32":
  import os, msvcrt
  msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
  msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)

# Helper function that sends a message to the webapp.
def send_message(message):
   # Write message size.
  sys.stdout.write(struct.pack('I', len(message)))
  # Write the message itself.
  sys.stdout.write(message)
  sys.stdout.flush()

# Thread that reads messages from the webapp.
def read_thread_func(queue):
  message_number = 0
  while 1:
    # Read the message length (first 4 bytes).
    text_length_bytes = sys.stdin.read(4)

    if len(text_length_bytes) == 0:
      if queue:
        queue.put(None)
      sys.exit(0)

    # Unpack message length as 4 byte integer.
    text_length = struct.unpack('i', text_length_bytes)[0]

    # Read the text (JSON object) of the message.
    text = sys.stdin.read(text_length).decode('utf-8')

    if queue:
      queue.put(text)
    else:
      # In headless mode just send an echo message back.
      send_message('{"echo": %s}' % text)

if Tkinter:
  class NativeMessagingWindow(Tkinter.Frame):
    def __init__(self, queue):
      self.queue = queue

      Tkinter.Frame.__init__(self)
      self.pack()

      self.text = Tkinter.Text(self)
      self.text.grid(row=0, column=0, padx=10, pady=10, columnspan=2)
      self.text.config(state=Tkinter.DISABLED, height=10, width=40)

      self.messageContent = Tkinter.StringVar()
      self.sendEntry = Tkinter.Entry(self, textvariable=self.messageContent)
      self.sendEntry.grid(row=1, column=0, padx=10, pady=10)

      self.sendButton = Tkinter.Button(self, text="Send", command=self.onSend)
      self.sendButton.grid(row=1, column=1, padx=10, pady=10)

      self.after(100, self.processMessages)

    def processMessages(self):
      while not self.queue.empty():
        message = self.queue.get_nowait()
        if message == None:
          self.quit()
          return
        self.log("Received %s" % message)

      self.after(100, self.processMessages)

    def onSend(self):
      text = '{"text": "' + self.messageContent.get() + '"}'
      self.log('Sending %s' % text)
      try:
        send_message(text)
      except IOError:
        tkMessageBox.showinfo('Native Messaging Example',
                              'Failed to send message.')
        sys.exit(1)

    def log(self, message):
      self.text.config(state=Tkinter.NORMAL)
      self.text.insert(Tkinter.END, message + "\n")
      self.text.config(state=Tkinter.DISABLED)


def Main():
  if not Tkinter:
    send_message('"Tkinter python module wasn\'t found. Running in headless ' +
                 'mode. Please consider installing Tkinter."')
    read_thread_func(None)
    sys.exit(0)

  queue = Queue.Queue()

  main_window = NativeMessagingWindow(queue)
  main_window.master.title('Native Messaging Example')

  thread = threading.Thread(target=read_thread_func, args=(queue,))
  thread.daemon = True
  thread.start()

  main_window.mainloop()

  sys.exit(0)


if __name__ == '__main__':
  Main()

03 运行效果

这个扩展demo,可以直接使用命令行运行。chrome://apps 查找到插件,点击运行,效果如下:
从chrome://apps运行插件

或者直接地址栏输入 chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/main.html
地址栏直接输入插件id

点击页面的 Connect 按钮,效果如下:
点击Connect按钮效果
输入一些文字后,点击 Send 按钮的效果

点击 Send 按钮的效果

04 Chromium的相关修改

如果是Chromium二次开发的浏览器,只需要加入自己对应的注册表键值即可

自己的浏览器注册表键值

05 一些问题

这种方式启动的exe或者脚本,需要另外进行进程管理,chrome关闭时,并不能关闭启动的第三方进程。

如果要使用和chrome一样的进程名,可能需要一些周折。

如果是自己编译的进程好,可以考虑修改utility 及 subtype类型,来模糊第三方进程名称,但是,它依然不是chrome自己的进程,仍然需要自己管理这个特殊的进程。

06 参考

Chrome Native Messaging技术示例

nativeMessaging

Native Message 解决Chrome插件权限问题

Chrome浏览器扩展开发系列之十四:本地消息机制Native messaging

chrome.runtime 调用本地程序

代理配置扩展

Google chrome浏览器中通过扩展调用本地应用程序以及和程序相互通讯(C++)

ChromeNativeMessaging 原生消息通信

Native Messaging

examples/api/nativeMessaging

07 使用c++ demo

把python程序换成c++ 代码,效果相同

// chrome_native_messaging_host.exe
// chromeHost.cpp
#include <iostream>
#include <string>
#include <fstream>
#include <Windows.h>

using namespace std;

void func()
{
	string message = "{\"text\": \"This is a response message\",\"num\": \"three\"}";
	unsigned int len = message.length();
	//先输出长度
	cout << char(((len >> 0) & 0xFF))
		<< char(((len >> 8) & 0xFF))
		<< char(((len >> 16) & 0xFF))
		<< char(((len >> 24) & 0xFF));
	//再输出内容并结束
	cout << message;
	cout.flush();
}

int main(int argc, char* argv[]) {
	string input = "";
	while (1)
	{
		Sleep(5 * 1000);
		func();
	}

	getline(cin, input);
	cout << "You entered: " << input << endl;
	ofstream myfile;
	myfile.open("example1.txt");
	myfile << "Writing this to a file.\n";
	myfile << input;
	myfile.close();
	system("pause");
	return 0;
}

修改 com.google.chrome.example.echo-win.json

// 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.

{
  "name": "com.google.chrome.example.echo",
  "description": "Chrome Native Messaging API Example Host",
  //"path": "native-messaging-example-host.bat",
  "path": "chrome_native_messaging_host.exe",
  "type": "stdio",
  "allowed_origins": [
    "chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"
  ]
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值