【GOOGLE插件】chrome.runtime.sendNativeMessage与本地应用交互
【GOOGLE插件】chrome.runtime.sendNativeMessage与本地应用交互
- manifest.json
- background.js
- com.examp.nativeapp.json
- c.bat
- 注册表路径
- 测试
- 扩充java通信
manifest.json
{
"manifest_version": 2,
"name": "202502271738",
"description": "",
"version": "0.9.9",
"permissions": [
"activeTab",
"tabs",
"storage",
"commands",
"nativeMessaging"
],
"background": {
"scripts": ["background.js"],
"persistent": false
}
}
background.js
document.addEventListener('DOMContentLoaded', function () {
chrome.runtime.sendNativeMessage('com.example12.nativeapp',{ "message": "Hello from Chrome" },(response) => {
if (chrome.runtime.lastError) {
alert('Error: ' + chrome.runtime.lastError.message);
} else {
alert('Response: ' + JSON.stringify(response));
}
});
})
com.examp.nativeapp.json
{
"name": "com.example12.nativeapp",
"description": "Native messaging host for python app",
"path": "c.bat",
"type": "stdio",
"allowed_origins": [
"chrome-extension://nfdljdonlekonbbjemmdjaljiahfeddj/"
]
}
c.bat
@echo off
python cc.py
cc.py
import json
import sys
def read_message():
"""从标准输入读取消息"""
raw_length = sys.stdin.buffer.read(4)
if not raw_length:
return None
message_length = int.from_bytes(raw_length, byteorder='little')
message = sys.stdin.buffer.read(message_length).decode('utf-8')
return json.loads(message)
def write_message(message):
"""将消息写入标准输出"""
message_json = json.dumps(message).encode('utf-8')
message_length = len(message_json).to_bytes(4, byteorder='little')
sys.stdout.buffer.write(message_length)
sys.stdout.buffer.write(message_json)
sys.stdout.buffer.flush()
def main():
"""主函数,处理消息通信"""
received_message = read_message()
if received_message:
print(f"收到来自 Chrome 插件的消息: {received_message.get('message')}")
response = {"message": "Hello from Python!"}
write_message(response)
else:
print("未接收到消息")
if __name__ == "__main__":
main()
注册表路径
计算机\HKEY_CURRENT_USER\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.example12.nativeapp
名称:默认
类型:REG_SZ
数据:com.examp.nativeapp.json文件所在的路径
测试
只要一加载插件,就会和本地的应用交互,弹出{“message”: “Hello from Python!”}
扩充java通信
本地jar代码
public static void main(String[] args) {
saveToFile("entering app...");
System.setErr(new PrintStream(new FileOutputStream(FileDescriptor.err))); // 保持错误输出
try {
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out), true, "UTF-8"));
System.setErr(new PrintStream(new FileOutputStream(FileDescriptor.err), true, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
while (true) {
if (!processMessage()) break; // 添加退出条件
}
} catch (Exception e) {
}
}
private static boolean processMessage() throws IOException {
// // 读取消息
String inputJson = readMessage();
if (inputJson == null) return false; // 输入流关闭时退出
// 处理消息
saveToFile("正在处理数据...");
saveToFile(inputJson);
String response = createResponse();
// 发送响应
sendMessage(response);
saveToFile("数据返回完成");
return true;
}
// 读取消息(包含4字节长度头)
private static String readMessage() throws IOException {
DataInputStream dis = new DataInputStream(System.in);
byte[] lengthBytes = new byte[4];
// 读取长度头
int bytesRead = dis.read(lengthBytes);
if (bytesRead == -1) return null;
// 转换为小端整数
int messageLength = ByteBuffer.wrap(lengthBytes)
.order(ByteOrder.LITTLE_ENDIAN)
.getInt();
// 读取消息体
byte[] messageBytes = new byte[messageLength];
dis.readFully(messageBytes);
saveToFile("readed message:"+new String(messageBytes, StandardCharsets.UTF_8));
return new String(messageBytes, StandardCharsets.UTF_8);
}
// 保存接收数据到文件
private static void saveToFile(String json) {
try (FileWriter writer = new FileWriter("local_file.json",true)) {
writer.write(json + System.lineSeparator());
} catch (IOException e) {
}
}
// 创建响应JSON
private static String createResponse() {
return "{\"response\": \"Nice to meet you.\"}";
}
private static void sendMessage(String message) throws IOException {
DataOutputStream dos = new DataOutputStream(System.out);
byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8);
// 记录原始消息内容
saveToFile("准备发送响应内容: " + message);
saveToFile("响应字节长度: " + messageBytes.length);
// 写入长度头
byte[] lengthHeader = ByteBuffer.allocate(4)
.order(ByteOrder.LITTLE_ENDIAN)
.putInt(messageBytes.length)
.array();
saveToFile("长度头字节: " + bytesToHex(lengthHeader));
dos.write(lengthHeader);
saveToFile("已写入长度头");
// 写入消息体
dos.write(messageBytes);
saveToFile("已写入消息体,字节数: " + messageBytes.length);
// 强制刷新输出流
dos.flush();
saveToFile("输出流已刷新");
// 在sendMessage方法末尾添加
dos.flush();
saveToFile("数据已发送完成");
saveToFile("实际发送字节数: " + messageBytes.length);
saveToFile("实际发送字节: " + bytesToHex(messageBytes));
saveToFile("长度头HEX: " + bytesToHex(lengthHeader));
}
// 辅助方法:字节转HEX
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X ", b));
}
return sb.toString().trim();
}
testjar的python代码
import struct
import subprocess
import json
import time
import sys
import os
from threading import Thread
def read_output(proc, length, timeout=2):
"""改进版读取函数(兼容Windows)"""
start_time = time.time()
data = b''
print(f"开始读取 {length} 字节...")
while len(data) < length:
remaining = length - len(data)
# 使用标准read方法
chunk = proc.stdout.read(remaining)
if chunk:
print(f"本次读取到 {len(chunk)} 字节: {chunk.hex()}")
data += chunk
else:
if time.time() - start_time > timeout:
raise TimeoutError(f"读取超时,已获取 {len(data)}/{length} 字节")
time.sleep(0.01)
print(f"成功读取完整 {length} 字节")
return data
def run_test():
try:
# 启动Java进程(Windows需要特殊处理)
startupinfo = None
if sys.platform == "win32":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
proc = subprocess.Popen(
['java', '-jar', 'javafxtest.jar'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
bufsize=0,
startupinfo=startupinfo
)
# 发送测试消息
test_msg = {"message": "test"}
message = json.dumps(test_msg).encode('utf-8')
print(f"发送消息长度: {len(message)}")
proc.stdin.write(struct.pack('<I', len(message)))
proc.stdin.write(message)
proc.stdin.flush()
print("消息已发送:",message)
# 读取响应头
print("正在读取响应头...")
resp_header = read_output(proc, 4)
print("响应头原始字节:", resp_header)
resp_length = struct.unpack('<I', resp_header)[0]
print(f"解析出的响应长度: {resp_length}")
# 读取响应体
print("正在读取响应体...")
resp_body = read_output(proc, resp_length)
print("响应体原始字节:", resp_body)
print("解码内容:", resp_body.decode('utf-8'))
except Exception as e:
print(f"测试失败: {str(e)}")
# 打印stderr输出
print("Java错误输出:", proc.stderr.read().decode('utf-8', errors='replace'))
finally:
if proc.poll() is None:
proc.terminate()
if __name__ == "__main__":
# 设置Windows控制台编码
if sys.platform == "win32":
os.system('chcp 65001 > nul') # UTF-8编码
run_test()
c.bat
@echo off
chcp 65001 > nul :: 强制UTF-8编码
setlocal enabledelayedexpansion
:: 使用绝对路径启动Java
set JAVA_EXE="C:\Program Files\Java\jdk1.8.0_341\bin\java.exe"
set JAR_PATH="javafxtest.jar"
%JAVA_EXE% -jar %JAR_PATH%