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

相关推荐
水银嘻嘻4 小时前
12 web 自动化之基于关键字+数据驱动-反射自动化框架搭建
运维·前端·自动化
小嘟嚷ovo4 小时前
h5,原生html,echarts关系网实现
前端·html·echarts
十一吖i5 小时前
Vue3项目使用ElDrawer后select方法不生效
前端
只可远观5 小时前
Flutter目录结构介绍、入口、Widget、Center组件、Text组件、MaterialApp组件、Scaffold组件
前端·flutter
周胡杰5 小时前
组件导航 (HMRouter)+flutter项目搭建-混合开发+分栏效果
前端·flutter·华为·harmonyos·鸿蒙·鸿蒙系统
敲代码的小吉米5 小时前
前端上传el-upload、原生input本地文件pdf格式(纯前端预览本地文件不走后端接口)
前端·javascript·pdf·状态模式
是千千千熠啊5 小时前
vue使用Fabric和pdfjs完成合同签章及批注
前端·vue.js
九月TTS6 小时前
TTS-Web-Vue系列:组件逻辑分离与模块化重构
前端·vue.js·重构
我是大头鸟6 小时前
SpringMVC 内容协商处理
前端
Humbunklung6 小时前
Visual Studio 2022 中添加“高级保存选项”及解决编码问题
前端·c++·webview·visual studio