一、概述
如果想要通过本地exe程序与chrome插件之间的通信,我们需要利用到NativeMessage。
具体环境与实现步骤见下文。
二、环境
1. window10操作系统
2. chrome浏览器
3. pycharm
三、实现步骤
1. 自己编写一个chrome插件
这里我们需要用到background、content_scripts与manifest.json文件,并使用Test.html进行测试。文件代码如下。
(1)manifest.json中的代码
{
"name" : "FastRun", //插件名字
"version" : "1.0.1", //插件版本号
"description" : "Launch APP ", //对插件的描述
"background" : { //background的具体引用
"scripts": ["background.js"] //这里引用js文件background.js
},
"content_scripts": [ //content_scripts的具体引用
{
//mathes指明哪些网站可以使用content.js
"matches": [ "http://*/*", "https://*/*", "ftp://*/*", "file://*/*" ],
"js": ["content.js"] //这里引用js文件content.js
}
],
//permissons是插件的权限,如果要使用nativeMessage就必须在其中加入nativeMessaging
"permissions" : ["nativeMessaging", "tabs"],
"minimum_chrome_version" : "6.0.0.0",
"manifest_version": 2
}
(2) content.js中的代码
var launch_message;
for (let i = 1; i <= 4; i++) {
//监听,只有监听到来自页面的"myCustomEvent1""myCustomEvent2""myCustomEvent3"...事件才触发
document.addEventListener('myCustomEvent' + i, function (evt) {
//向background.js发送信息
chrome.runtime.sendMessage({
type: "用户点击了按钮",
message: evt.detail
}, function (response) {});
}, false);
}
//接收来自background.js的消息
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
const message = document.querySelector('.message'); //获取message
const newH3 = document.createElement('h3'); //创建一个h3标签
newH3.innerHTML = request; //h3标签的内容为background.js发的消息
message.appendChild(newH3) //把创建的h3标签添加到message中
return true;
});
(3)background.js中的代码
var port = null;
//监听来自content.js的信息
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
//request就是content.js发送过来的消息
if (request.type == "用户点击了按钮") {
connectToNativeHost(request.message);
}
return true;
});
//断开连接时触发
function onDisconnected() {
console.log(chrome.runtime.lastError);
port = null;
}
//接收到来自exe程序的消息时触发
async function onNativeMessage(message) {
console.log('接收到从本地应用程序发送来的消息:' + JSON.stringify(message));
const tabId = await getCurrentTabId()
chrome.tabs.sendMessage(tabId, JSON.stringify(message), function (response) {});
}
//得到当前tabId
function getCurrentTabId() {
return new Promise((resolve, reject) => {
chrome.tabs.query({
active: true,
currentWindow: true
}, function (tabs) {
resolve(tabs.length ? tabs[0].id : null)
});
})
}
//连接到本地主机并获得通信端口
function connectToNativeHost(msg) {
var nativeHostName = "com.my_company.my_application"; //本地主机名(就是在注册表中的名字)
port = chrome.runtime.connectNative(nativeHostName); //根据本地主机名得到通信端口
port.onMessage.addListener(onNativeMessage); //监听exe程序是否发来消息
port.onDisconnect.addListener(onDisconnected); //监听是否断开连接
port.postMessage(msg) //向应用程序发送信息
}
(4) Test.html中的代码
<html>
<style>
.message {
width: 500px;
height: 500px;
background-color: pink;
}
h3 {
background-color: red;
}
</style>
<head>
<script>
function startApp(i) {
//创建CustomEvent事件
var eventName = "myCustomEvent" + i;
var evt = document.createEvent("CustomEvent");
evt.initCustomEvent(eventName, true, false, "用户点击了按钮" + i);
//执行自定义事件
document.dispatchEvent(evt);
}
</script>
</head>
<body>
<button type="button" onClick="startApp(1)" id="startApp">按钮1</button>
<button type="button" onClick="startApp(2)" id="startApp">按钮2</button>
<button type="button" onClick="startApp(3)" id="startApp">按钮3</button>
<button type="button" onClick="startApp(4)" id="startApp">按钮4</button>
<div class="message">
<h1 class="jieshou">接收到的消息:</h1>
</div>
</body>
</html>
2.把自己写的chrome插件安装到chrome浏览器中
(1)把上述创建的4个文件放在同一个文件夹中,命名任意
(2)在chrome浏览器地址栏输入:chrome://extensions 进入插件管理页面
(3)打开右上角《开发者模式》
(4)点击左上角《加载已解压的扩展程序》,选择4个文件所在的文件夹并添加
(5)就可以看到插件已经被安装到chrome浏览器当中,如下图 (每个插件都会自动生成一个独一无二的ID值,我们需要保存自己编写插件的ID值,下面需要用到,记得保存!!!)
3. 创建Test.py并写入代码
打开pycharm,创建Test.py文件,其中代码如下:(没有相应包的话需要先导入相应的包)
import json
import sys
import struct
# 读取来自 stdin 的消息并对其进行解码
def get_message():
raw_length = sys.stdin.buffer.read(4)
if not raw_length:
sys.exit(0)
message_length = struct.unpack('=I', raw_length)[0]
message = sys.stdin.buffer.read(message_length).decode("utf-8")
return json.loads(message)
# 根据信息的内容对信息进行编码以便传输。
def encode_message(message_content):
encoded_content = json.dumps(message_content).encode("utf-8")
encoded_length = struct.pack('=I', len(encoded_content))
# use struct.pack("10s", bytes), to pack a string of the length of 10 characters
return {'length': encoded_length, 'content': struct.pack(str(len(encoded_content))+"s",encoded_content)}
# 向标准输出发送编码好的消息
def send_message(encoded_message):
sys.stdout.buffer.write(encoded_message['length'])
sys.stdout.buffer.write(encoded_message['content'])
sys.stdout.buffer.flush()
# 持续监听chrome插件发来的消息
while True:
message = get_message() # 得到来自chrome插件的消息
if(message=="用户点击了按钮1"): # 根据消息的不同内容,exe程序向chrome插件发送不同的字符串
send_message(encode_message("来自exe程序的消息:按钮1被点击"))
elif(message=="用户点击了按钮2"):
send_message(encode_message("来自exe程序的消息:按钮2被点击"))
elif(message=="用户点击了按钮3"):
send_message(encode_message("来自exe程序的消息:按钮3被点击"))
elif(message=="用户点击了按钮4"):
send_message((encode_message("来自exe程序的消息:按钮4被点击")))
4.把Test.py打包成exe程序
在pycharm终端中输入: pyinstaller -F Test.py (如果没有pyinstaller包的需要先导包)
然后打包好的exe程序就在Test.py所在文件夹下的dist文件夹中,文件名为Test.exe
5.将Test.exe程序写入注册表
(1)首先需要创建一个文件,名为manifest.json(此文件不同于上面创建的manifest.json文件,只是名字一样 , 不要忘记把allowed_origins下的字符串替换成自己所写插件的ID值 !!!),其中代码为:
{
"name": "com.my_company.my_application", //此名就是hostName,即主机名
"description": "Chrome sent message to native app.", //对json文件的描述
"path": "Test.exe", //相对路径,打包好的Test.exe相对于本manifest文件的相对路径
"type": "stdio", //必填项,意为通过标准输入输出流进行通信
"allowed_origins": [
"chrome-extension://jckgmlnngpemfhapkfdapedimdpimlmd/" //中间的字符串是我们编写的插件的ID值,需要自己替换
]
}
(2)按住 win+r 键打开运行windows命令窗口,输入 regedit 进入注册表编辑器,找到HKEY_CURRENT_USER\SOFTWARE\Google\Chrome\NativeMessagingHosts 目录,右键单击NativeMessagingHosts,选择新建,选择项,新建一个名为 com.my_company.my_application 的项(该名就是主机名,名字应与上面那个manifest.json的name值相同),然后选中该新建的项,双击右侧默认,修改数值数据为第二次创建的manifest.json文件在本机的绝对路径,具体操作步骤见下图
6. 测试
完成上述步骤,打开上面创建的 Test.html,出现四个按钮,单击任意一个按钮,chrome插件将向exe程序发送消息,exe程序接收到消息后根据消息返回对应的值并出现在下方。如下图所示
7.补充
插件当中content.js中输出的内容会被打印在当前页面的控制台(按下键盘F12键即可找到控制台),可以自己添加打印信息进行调试。
插件当中background.js中输出的内容会被打印在当前插件的背景页的控制台中(chrome浏览器地址栏输入chrome://extensions,找到自己写的插件,点击背景页就可以找到控制台),可以自己添加打印信息进行调试。