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

相关推荐
不想有bug的小菜鸟5 分钟前
vue3使用iframe全屏展示pdf效果
前端·pdf
m0_748238635 分钟前
Spring Boot项目接收前端参数的11种方式
前端·spring boot·后端
u0100559606 分钟前
前端代理,解决跨域问题讲解
前端
quitv11 分钟前
react脚手架配置别名
前端·javascript·react.js
m0_5287238120 分钟前
前端如何进行性能优化
前端·性能优化
化作繁星21 分钟前
在 Vue 3 中,如何缓存和复用动态组件
前端·vue.js·缓存
一粒沙-41 分钟前
iOS 将GIF图分享至微信
前端·ios
graywen1 小时前
从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
前端
Gazer_S2 小时前
【现代前端框架中本地图片资源的处理方案】
前端·javascript·chrome·缓存·前端框架
林的快手4 小时前
CSS默认样式
前端·css·vue.js·chrome·css3