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

kat*_*ine 8 c++ google-chrome-extension chrome-native-messaging

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

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

同时,当使用该printf功能的本机应用程序向chrome扩展程序写入消息时,扩展程序无法接收并且控制台中只显示消息.

任何想法如何解决问题?

dba*_*ric 22

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

CHROME EXTENSION

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

以下是示例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
}
Run Code Online (Sandbox Code Playgroud)

这里重要的是在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"});
Run Code Online (Sandbox Code Playgroud)

代码本身非常明显 - 我们尝试连接到com.dolby.native_messaging_host密钥标识的本机主机(我将在一分钟内完成).然后,我们为onMessage事件注册一个监听器(当本机主机向chrome扩展发送消息时触发此事件).我们还为断开连接事件注册了一个监听器(例如,当本机主机死亡时,将触发此事件).最后,我们使用postMessage方法发送消息.

天真的消息主持人

现在,本机主机也有自己的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/"
  ]
}
Run Code Online (Sandbox Code Playgroud)

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

下一步是在注册表(对于Windows)中注册此Native Messaging主机,并指定其清单文件的位置.以下屏幕截图说明了如何为Windows(查看提供的链接以了解如何在OSX和Linux中执行此操作):

本机消息传递主机的注册表项(仅限Windows操作系统)

在为本机主机添加注册表项之后,唯一剩下的就是编写本机主机.以下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;
}
Run Code Online (Sandbox Code Playgroud)

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

如何计算chrome扩展程序发送的邮件大小

  • "当使用runtime.connectNative创建消息传递端口时,Chrome会启动本机消息传递主机进程并使其保持运行直到端口被销毁.另一方面,当使用runtime.sendNativeMessage发送消息而不创建消息传递端口时,Chrome启动每条消息的新本机消息传递主机进程." 因此,当扩展调用connectNative时,Native Messaging主机会自动启动,只要打开端口就会打开它. (2认同)

use*_*789 5

对于未来的Google用户,我的方法如下:

C风格

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);
Run Code Online (Sandbox Code Playgroud)

写作

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);
Run Code Online (Sandbox Code Playgroud)

C++风格

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;
Run Code Online (Sandbox Code Playgroud)

写作

string outMsg = "{\"text\":\"This is a response message\"}";
unsigned int outLen = outMsg.length();
char *bOutLen = reinterpret_cast<char *>(&outLen);
cout.write(bOutLen, 4);
cout << outMsg << flush;
Run Code Online (Sandbox Code Playgroud)

  • 在c ++中使用原始缓冲区.啊. (2认同)