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

相关推荐
DK七七27 分钟前
多端校园圈子论坛小程序,多个学校同时代理,校园小程序分展示后台管理源码
开发语言·前端·微信小程序·小程序·php
老赵的博客38 分钟前
QSS 设置bug
前端·bug·音视频
Chikaoya39 分钟前
项目中用户数据获取遇到bug
前端·typescript·vue·bug
南城夏季39 分钟前
蓝领招聘二期笔记
前端·javascript·笔记
Huazie39 分钟前
来花个几分钟,轻松掌握 Hexo Diversity 主题配置内容
前端·javascript·hexo
NoloveisGod1 小时前
Vue的基础使用
前端·javascript·vue.js
GISer_Jing1 小时前
前端系统设计面试题(二)Javascript\Vue
前端·javascript·vue.js
海上彼尚2 小时前
实现3D热力图
前端·javascript·3d
杨过姑父2 小时前
org.springframework.context.support.ApplicationListenerDetector 详细介绍
java·前端·spring
理想不理想v2 小时前
使用JS实现文件流转换excel?
java·前端·javascript·css·vue.js·spring·面试