C ++中的Chrome原生主机无法与Chrome通信

时间:2014-10-27 07:10:07

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

我正在尝试使用runtime.connectNativepostMessage来实施Chrome扩展程序。我正在关注Chrome文档,下载了本机消息传递示例,并将本机应用程序更改为使用C ++。

但是,原生应用无法从Chrome扩展程序接收消息。

同时,当使用printf函数的本机应用程序向chrome扩展程序写入消息时,扩展程序无法接收,并且消息显示在控制台中。

任何想法如何解决问题?

2 个答案:

答案 0 :(得分:20)

您没有提供有关您实际尝试的内容的大量信息,因此我将尽力解释实施Chrome扩展程序,Native Messaging主机以及在它们之间建立通信所需的步骤。 (请查看以下链接以获取有关Chrome原生消息的更多信息:Chrome Native Messaging How to

CHROME EXTENSION

首先,我们需要设置Chrome扩展程序。由于这将是非常简单的扩展,我们只需要 manifest.json 文件(请注意这是扩展的清单文件 - 本机主机也将有自己的清单文件)和background.js javascript实现。< / p>

以下是示例 manifest.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密钥标识的本机主机(我将在一分钟内完成)。然后,我们为onMessage事件注册一个监听器(当本机主机向chrome扩展发送消息时触发此事件)。我们还为断开事件注册了一个监听器(例如,当本机主机死亡时,将触发此事件)。最后,我们使用postMessage方法发送消息。

NATIVE MESSAGING HOST

现在,本机主机也有自己的manifest.json文件。本机主机的非常简单的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/"
  ]
}

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

下一步是在注册表(对于Windows)中注册此Native Messaging主机,并指定其清单文件的位置。以下屏幕截图介绍了如何针对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;
        }

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

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

    return 0;
}

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

How to calculate size of the message sent by chrome extension

答案 1 :(得分:5)

对于未来的Google用户,请按以下步骤操作:

C风格

        Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
        Marshaller ms = JAXBContext.newInstance(CreateGPSRequest4RAS.class).createMarshaller();

        ms.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        ms.setProperty(Marshaller.JAXB_FRAGMENT, true);
        ms.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "");
        ms.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");

        ms.marshal(gpsRequest, document);

编写

char bInLen[4];
read(0, bInLen, 4); // 0 is stdin
unsigned int inLen = *(unsigned int *)bInLen;
char *inMsg = (char *)malloc(inLen);
read(0, inMsg, inLen);
inMsg[inLen] = '\0';
...
free(inMsg);

C ++风格

char *outMsg = "{\"text\":\"This is a response message\"}";
unsigned int outLen = strlen(outMsg);
char *bOutLen = (char *)&outLen;
write(1, bOutLen, 4); // 1 is stdout
write(1, outMsg, outLen);
fflush(stdout);

编写

char bInLen[4];
cin.read(bInLen, 4);
unsigned int inLen = *reinterpret_cast<unsigned int *>(bInLen);
char *inMsg = new char[inLen];
cin.read(inMsg, inLen);
string inStr(inMsg); // if you have managed types, use them!
delete[] inMsg;