c++ - C++ 中的 Chrome native 主机,无法与 Chrome 通信

标签 c++ google-chrome-extension chrome-native-messaging

我正在尝试使用 runtime.connectNativepostMessage 实现 Chrome 扩展。我按照 Chrome 文档,下载了 native 消息传递示例,并将 native 应用更改为使用 C++。

但是, native 应用无法接收来自 Chrome 扩展程序的消息。

同时,当原生应用使用printf 函数向chrome 扩展程序写入消息时,该扩展程序无法接收,消息仅显示在控制台中。

有什么办法解决这个问题吗?

最佳答案

您没有提供很多关于您实际尝试过的信息,所以我会尽力解释实现 Chrome 扩展、本地消息传递主机以及在它们之间建立通信所需的步骤。 (请检查以下链接以获取有关 Chrome native 消息传递的更多信息:Chrome Native Messaging How to

Chrome 扩展

首先,我们需要设置 Chrome 扩展程序。由于这将是一个非常简单的扩展,我们只需要 ma​​nifest.json 文件(请注意这是扩展的 list 文件 - native 主机也将有自己的 list 文件)和 background.js javascript 实现。

以下是示例 ma​​nifest.json 文件:

{
  "name": "Test extension",
  "description": "Native messaging test",
   "permissions": [
                    "nativeMessaging",
                    "tabs",
                    "activeTab",
                    "background",
                    "http://*/", "https://*/"
                    ],
  "background": {
    "scripts": ["background.js"]
  },
  "version": "1.0",
  "minimum_chrome_version": "29",
  "manifest_version": 2
}

这里重要的是,将在 background.js 中提供实现,支持的最低 Chrome 版本为 29,同时支持 HTTP 和 HTTPS。

接下来,background.js 文件包含以下内容:

var port = chrome.runtime.connectNative('com.dolby.native_messaging_host');

port.onMessage.addListener(function(msg) {
  console.log(msg.text);
});

port.onDisconnect.addListener(function() {
  console.log("Disconnected");
});

port.postMessage({"text":"This is message from Chrome extension"});

代码本身是不言自明的——我们尝试连接到由 com.dolby.native_messaging_host key 标识的 native 主机(稍后我会谈到这一点)。然后,我们为 onMessage 事件注册一个监听器(当 native 主机向 chrome 扩展程序发送消息时触发此事件)。我们还为断开连接事件注册了一个监听器(例如,当 native 主机死亡时将触发此事件)。最后,我们使用 postMessage 方法发送消息。

本地消息传递主机

现在,原生主机也有自己的 manifest.json 文件。 native 主机的非常简单的 manifest.json 文件如下:

{
  "name": "com.dolby.native_messaging_host",
  "description": "Native messaging host",
  "path": "C:\\Users\\dbajg\\Desktop\\Native-messaging-host\\Debug\\Native-messaging-host.exe",
  "type": "stdio",
  "allowed_origins": [
    "chrome-extension://bjgnpdfhbcpjdfjoplajcmbleickphpg/"
  ]
}

这里有几件有趣的事情:名称标识了注册 native 主机的 key 。路径是 native 主机可执行文件的完整路径。通信类型 stdio 意味着我们正在使用标准输入/输出进行通信(目前仅支持类型)。最后,allowed_origins 指定哪些扩展可以与此本地主机通信 - 因此您必须找出您的扩展的 key 是什么!

下一步是在注册表(适用于 Windows)中注册此本地消息传递主机,并指定其 list 文件的位置。以下屏幕截图解释了如何在 Windows 上执行此操作(检查提供的链接以了解如何在 OSX 和 Linux 中执行此操作):

Registry entry for native messaging host (Windows OS only)

为本地主机添加注册表项后,剩下的唯一事情就是编写本地主机。以下 C++ 代码实现了简单的本地主机,它从标准输入读取消息并将响应写入标准输出(当您发送 #STOP# 消息时,本地主机退出):

#include <iostream>
#include <string>

int main(){
    std::string oneLine = "";

    while (1){
        unsigned int length = 0;

        //read the first four bytes (=> Length)
        /*for (int i = 0; i < 4; i++)
        {
            int read_char = getchar();
            length += read_char * (int) pow(2.0, i*8);
            std::string s = std::to_string((long long)read_char) + "\n";
            fwrite(s.c_str(), sizeof(char), s.size(), f);
            fflush(f);
        }*/

        //Neat way!
        for (int i = 0; i < 4; i++)
        {
            unsigned int read_char = getchar();
            length = length | (read_char << i*8);
        }

        //read the json-message
        std::string msg = "";
        for (int i = 0; i < length; i++)
        {
            msg += getchar();
        }

        std::string message = "{\"text\":\"This is a response message\"}";
        // Collect the length of the message
        unsigned int len = message.length();

        // Now we can output our message
        if (msg == "{\"text\":\"#STOP#\"}"){
            message = "{\"text\":\"EXITING...\"}";
            len = message.length();

            std::cout   << char(len>>0)
                        << char(len>>8)
                        << char(len>>16)
                        << char(len>>24);

            std::cout << message;
            break;
        }
        
        // return stdin message
        len = length;
        std::cout   << char(len>>0)
                    << char(len>>8)
                    << char(len>>16)
                    << char(len>>24);

        std::cout << msg << std::flush;

        // return response message
        // std::cout    << char(len>>0)
        //          << char(len>>8)
        //          << char(len>>16)
        //          << char(len>>24);
        //  
        // std::cout << message << std::flush;
    }
    
    return 0;
}

扩展发送到 native 主机的消息以第一个字节存储消息中的字节数的方式形成。所以 native 主机必须做的第一件事是读取前 4 个字节并计算消息的大小。我在另一篇文章中解释了如何做到这一点:

How to calculate size of the message sent by chrome extension

关于c++ - C++ 中的 Chrome native 主机,无法与 Chrome 通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26582584/

相关文章:

c++ - load-acquire 应该立即看到 store-release 吗?

javascript - 如何在 Google Chrome 扩展程序中使用 HTML5 的 localStorage?

java - 使用可执行 Jar 文件的 Chrome native 消息传递

google-chrome - 后台js中的chrome扩展卸载事件

c++ - chrome 原生消息 : can a native host executable start with arguments?

c++ - 如何在mongoose服务器c++中获取域名

c++ - 使用zlib1.2.7解压gzip数据,如何获取压缩包中的文件名

google-chrome-extension - 如何从后台页面获取当前tabId

c++ - 如何避免使用 `ReplaceInstWithValue()` 使迭代器无效?

javascript - 在回调中调用异步函数