当前位置: 首页 > article >正文

【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%


http://www.kler.cn/a/588866.html

相关文章:

  • Xinference大模型配置介绍并通过git-lfs、hf-mirror安装
  • 【Node.js入门笔记4---fs 目录操作】
  • 【华为OD-E卷 -121 消消乐游戏 100分(python、java、c++、js、c)】
  • 9种Python数据可视化方案,让财务数据焕发生命力
  • 基于Spring Boot的网上蛋糕售卖店管理系统的设计与实现(LW+源码+讲解)
  • 谷云科技RestCloud智能体搭建平台助力企业快速搭建AI Agent
  • spring boot连接clickhouse集群,实现故障节点自动切换
  • Python基于深度学习的多模态人脸情绪识别研究与实现
  • 【TCP】三次挥手,四次挥手详解--UDP和TCP协议详解
  • 【LeetCode110】平衡二叉树
  • 爬虫获取 item_get_video 接口数据:小红书笔记视频详情的深度解析
  • Docker 端口映射的 “隐藏炸弹“ 与安全访问方案
  • 第二十七天 实践分布式任务调度,实现一个简单的分布式任务
  • Linux内核邻接子系统分析
  • PHP与前端框架的无缝集成:最佳实践与案例分析
  • 【Linux篇】初识Linux指令(下篇)
  • 【部署】ubuntu部署olmOCR
  • DICT领域有哪些重要的技术标准和规范?
  • 国科大——计网(0812)——考试真题
  • 96.HarmonyOS NEXT工具类设计模式教程:最佳实践与实现