Mac: Chrome插件与Native通信实践

本文主要记录一次在Mac上实现Chrome插件与Native通信实践。坑常有,快乐也常有(^▽^)

参考文章:《Chrome extension与Native app通信》《Native messaging》

一、Chrome插件

1、插件配置

  1. 本demo使用的配置版本是 manifest_version : 3,不同的版本API之间存在差异,使用时要注意。
  2. Chrome插件与原生端通信要设置与原生端的通信权限 nativeMessaging。
  3. 设置 **service_worker **后台执行脚本,并可使用DevTools进行调试。
json 复制代码
{
    "name": "Chrome_Plugin",
    "description": "Chrome插件配置",
    "version": "0.0.1",
    "manifest_version": 3,
    "icons": {
        "16": "images/icon16.png",
        "24": "images/icon24.png",
        "32": "images/icon32.png",
        "128": "images/icon128.png"
    },
    "content_scripts": [
        {
            "js": [
                "content.js"
            ],
            "matches": [
                "https://www.google.com/*"
            ]
        }
    ],
    "permissions": [
        "nativeMessaging"
    ],
    "background": {
        "service_worker": "background.js"
    }
}

2、插件代码

content.js

demo中设置了在Google页面点击option键,触发消息发送。

javascript 复制代码
document.addEventListener("keydown", handleClick);

function handleClick(event) {
    if (event.altKey) {
        sendMessage()
    }
}

function sendMessage() {
    // 在 content.js 中发送消息给 background.js
    chrome.runtime.sendMessage('hello python', function (response) {
        console.log("Message sent to background.js");
    });
}

background.js

background.js 用来处理与native之间的通信。使用 chrome.runtime.connectNative() 可建立长连接实现双向通信,如果只需要给native发送消息,可以使用 chrome.runtime.sendNativeMessage(), 其中com.example.native为原生应用程序配置文件中的name

双向通信

javascript 复制代码
// 建立与本地Python服务的连接
var port = chrome.runtime.connectNative('com.example.native');

// 接收来自本地Python服务的消息
port.onMessage.addListener(function (msg) {
  console.log('Received message from native: ' + msg.message);
});
// 连接断开时的回调
port.onDisconnect.addListener(function () {
  console.log('Disconnected');
});

// 接收来自content script的消息
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
    console.log('Received message from content script: ' + message);
    // 发送消息到本地Python服务
    port.postMessage({message: message});
    console.log('Send message to native: ' + message);
});

单向通信

javascript 复制代码
chrome.runtime.sendNativeMessage('com.example.native', msg, function (response) {
     console.log('接收到消息:\n' + response);
});

二、Native应用

1、Python代码

python 复制代码
import struct
import sys
import logging
import json

def read_message():
    # 读取标准输入流中的msg-header(first 4 bytes).
    text_length_bytes = sys.stdin.buffer.read(4)
    # Unpack message length as 4 byte integer, tuple = struct.unpack(fmt, buffer).
    text_length = struct.unpack("I", text_length_bytes)[0]
    # 读取标准输入流中的msg-body bytes
    return sys.stdin.buffer.read(text_length)

def send_message(message):
    # 将msg-header写到标准输出流, I表示int类型占4个字节,相关内容查看文档介绍python-doc/library/struct
    sys.stdout.buffer.write(struct.pack("I", len(message)))
    # 将msg-body写到标准输出流
    sys.stdout.buffer.write(message)
    sys.stdout.flush()

if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG, filename='debug.log', format='%(asctime)s - %(levelname)s - %(message)s')
    logging.debug("native程序启动了")

    while True:
        message = read_message()
        if message:
            logging.debug(f"收到消息:${message}")
            response = {"message": "hello Chrome_Plugin"}
            send_message(json.dumps(response).encode("utf-8"))
    logging.debug(f"程序结束了")

注意事项: 通过标准输入输出流(stdio)读取消息,需要使用struct.unpack读取前四位,获取消息长度后再读取消息内容。GPT一直骗我用 sys.stdin.readline() ,一直读取不到,给我坑坏了。。。参考了文章 《Chrome extension与Native app通信》才得以解决。

2、Python打包

打包Python应用程序需要用到 pyinstaller,pyinstaller可将Python脚本及其依赖项打包成可执行文件,可执行文件在 dist 目录下。

  1. 安装:pip install pyinstaller
  2. 打包:pyinstaller main.py

3、Native配置

json 复制代码
{
  "name": "com.example.native",
  "description": "本地Python程序配置",
  "path": "/Users/whj/Desktop/TOOL_PROJECT/native_demo/dist/main/main",
  "type": "stdio",
  "allowed_origins": [
    "chrome-extension://kjcamdnmifjlmnapcocdfmjmadchcbgg/"
  ]
}

注意事项:

  1. 配置文件名称要与name保持一致
  2. Path为可执行文件存放路径(mac上必须为绝对路径)
  3. allowed_origins配置的是可与native程序通信的Chrome插件,ID可在插件安装后,插件列表中查看。
  4. 配置文件要存放在 ~/Library/Application Support/Google/Chrome/NativeMessagingHosts/

三、联调

1、插件联调

内容脚本联调

content.js可以直接进行断点调试

后台脚本联调

Chrome上可以使用DevTools来查看background.js的打印日志,

2、Python应用联调

目前知道的只能通过输出到日志文件上来查看日志(知识有限(✿◡‿◡)),如果有其它更好的方式欢迎留言分享~

3、常见报错

QA:Failed to start native messaging host.

原因分析:大概率是可执行文件的路径配置有问题,GPT骗我说直接放脚本路径🤮

QA:Native host has exited.

原因分析:Native应用报错了,检查一下Python代码有没有问题

QA:Invalid native messaging host name specified

原因分析:Native应用配置中的name有问题或跟配置文件名不一致,示例:com.example.native

QA:Access to the specified native messaging host is forbidden

原因分析:Native应用配置中没有配置 allowed_origins

相关推荐
whbi1 分钟前
DataX Web 部署方案
前端
BD_Marathon5 分钟前
【JavaWeb】CSS_三种引入方式
前端·css
excel5 分钟前
# Vue 渲染系统的四个关键阶段:从模板编译到新旧 VDOM Patch 的完整机制解析
前端
cos7 分钟前
我的 Claude Code 使用小记 2
前端·ai编程·claude
Dreamboat-L9 分钟前
ES6 (ECMAScript 2015+)
前端·ecmascript·es6
凤凰战士芭比Q1 小时前
web中间件——(二)Nginx(高级功能、优化)
前端·nginx·中间件
阿珊和她的猫1 小时前
表单数据验证:HTML5 自带属性与其他方法的结合应用
前端·状态模式·html5
谷粒.2 小时前
Cypress vs Playwright vs Selenium:现代Web自动化测试框架深度评测
java·前端·网络·人工智能·python·selenium·测试工具
小飞侠在吗8 小时前
vue props
前端·javascript·vue.js
DsirNg9 小时前
页面栈溢出问题修复总结
前端·微信小程序