macOS下Firefox原生消息传递调用失败问题求助
Firefox原生消息传递失败排查(macOS)
错误日志
Bookmarks: Array(5) [ {…}, {…}, {…}, {…}, {…} ] background.js:13:11 Native messaging failed: Error: An unexpected error occurred background.js:21:29 exportBookmarks moz-extension://e32bef2f-a8ae-4b3e-b67c-49730ae7bcc1/background.js:21 (Async: promise callback) exportBookmarks moz-extension://e32bef2f-a8ae-4b3e-b67c-49730ae7bcc1/background.js:21 <anonym> moz-extension://e32bef2f-a8ae-4b3e-b67c-49730ae7bcc1/background.js:29
扩展清单 (manifest.json)
{ "manifest_version": 2, "name": "Albert bookmark export", "version": "1.0", "permissions": [ "bookmarks", "nativeMessaging" ], "background": { "scripts": [ "background.js" ] }, "browser_specific_settings": { "gecko": { "id": "bookmark_export@albertlauncher.org", "strict_min_version": "50.0" } } }
扩展后台脚本 (background.js)
async function getBookmarks() { let bookmarks = []; function traverse(nodes) { for (let n of nodes) { if (n.url) bookmarks.push({id: n.id, title: n.title, url: n.url}); if (n.children) traverse(n.children); } } const tree = await browser.bookmarks.getTree(); traverse(tree); console.log("Bookmarks:", bookmarks); return bookmarks; } async function exportBookmarks() { let bookmarks = await getBookmarks(); browser.runtime.sendNativeMessage("bookmark_export", { bookmarks }) .then(response => { console.log("Received response from native host:", response); }) .catch(err => { console.error("Native messaging failed:", err); }); // Error: An unexpected error occurred } browser.bookmarks.onCreated.addListener(exportBookmarks); browser.bookmarks.onRemoved.addListener(exportBookmarks); browser.bookmarks.onChanged.addListener(exportBookmarks); browser.bookmarks.onMoved.addListener(exportBookmarks); exportBookmarks();
原生宿主清单 (bookmark_export.json)
{ "name": "bookmark_export", "description": "Writes Firefox bookmarks to a JSON file", "path": "/tmp/bookmark_export.sh", "type": "stdio", "allowed_extensions": ["bookmark_export@albertlauncher.org"] }
原生宿主脚本 (bookmark_export.py)
#!/usr/bin/env python3 import sys, json, struct, traceback with open("/tmp/0_albert_bookmark_export.txt", "w") as f: f.write("I have been called\n") def get_message(): rawLength = sys.stdin.buffer.read(4) if len(rawLength) == 0: sys.exit(0) messageLength = struct.unpack('@I', rawLength)[0] message = sys.stdin.buffer.read(messageLength).decode('utf-8') return json.loads(message) # Encode a message for transmission, # given its content. def encode_message(messageContent): # https://docs.python.org/3/library/json.html#basic-usage # To get the most compact JSON representation, you should specify # (',', ':') to eliminate whitespace. # We want the most compact representation because the browser rejects # messages that exceed 1 MB. encodedContent = json.dumps(messageContent, separators=(',', ':')).encode('utf-8') encodedLength = struct.pack('@I', len(encodedContent)) return {'length': encodedLength, 'content': encodedContent} # Send an encoded message to stdout def send_message(encodedMessage): sys.stdout.buffer.write(encodedMessage['length']) sys.stdout.buffer.write(encodedMessage['content']) sys.stdout.buffer.flush() def write_bookmarks_file(data): with open("Bookmarks.json", "w", encoding="utf-8") as f: json.dump(data, f, indent=2) def send_response(data): encoded = json.dumps(data).encode("utf-8") sys.stdout.buffer.write(struct.pack("<I", len(encoded))) sys.stdout.buffer.write(encoded) sys.stdout.buffer.flush() if __name__ == "__main__": with open("debug.log", "w") as f: f.write("I have been called\n") try: f.write("get_message\n") msg = get_message() f.write("write_bookmarks_file\n") write_bookmarks_file(msg) f.write("send_message\n") send_message(encode_message(json.dumps({"status": "ok"}))) f.write(json.dumps(msg) + "\n") except Exception as e: f.write(traceback.format_exc())
问题排查关键点
- 宿主路径不匹配:清单中
path指向不存在的/tmp/bookmark_export.sh,需改为Python脚本的绝对路径,比如/Users/你的用户名/albert/plugins/python/plugins/firefox/firefox_extension/bookmark_export.py。 - 脚本权限不足:给Python脚本添加可执行权限,执行
chmod +x /Users/你的用户名/albert/plugins/python/plugins/firefox/firefox_extension/bookmark_export.py。 - 工作目录写入权限:脚本中
Bookmarks.json和debug.log默认写入Firefox启动目录,改为绝对路径(如/tmp/Bookmarks.json)避免权限问题。 - 消息格式不一致:
get_message用@I解析长度,send_response用<I打包,需统一字节序;send_message传递json.dumps结果会导致JSON嵌套,直接传字典{"status": "ok"}即可。 - 宿主清单权限:确保
bookmark_export.json权限为644,执行chmod 644 ~/Library/Application\ Support/Mozilla/NativeMessagingHosts/bookmark_export.json。
内容的提问来源于stack exchange,提问作者ManuelSchneid3r
相关产品推荐
相关产品推荐

