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

相关推荐
zqx_78 分钟前
随记 前端框架React的初步认识
前端·react.js·前端框架
惜.己25 分钟前
javaScript基础(8个案例+代码+效果图)
开发语言·前端·javascript·vscode·css3·html5
什么鬼昵称1 小时前
Pikachu-csrf-CSRF(get)
前端·csrf
长天一色1 小时前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
NiNg_1_2341 小时前
npm、yarn、pnpm之间的区别
前端·npm·node.js
秋殇与星河1 小时前
CSS总结
前端·css
BigYe程普2 小时前
我开发了一个出海全栈SaaS工具,还写了一套全栈开发教程
开发语言·前端·chrome·chatgpt·reactjs·个人开发
余生H2 小时前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈
程序员-珍2 小时前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
axihaihai2 小时前
网站开发的发展(后端路由/前后端分离/前端路由)
前端