Я пытаюсь реализовать расширение Chrome с помощью runtime.connectNative
а также postMessage
, Я следую документации по Chrome, скачал собственный пример обмена сообщениями и изменил собственное приложение на использование C ++.
Однако собственное приложение не может получить сообщение от расширения Chrome.
Между тем, когда родное приложение использует printf
Функция записи сообщения в расширение Chrome, расширение не может получить, и сообщение просто отображается в консоли.
Есть идеи как решить проблему?
Вы не предоставили много информации о том, что вы на самом деле пробовали, поэтому я сделаю все возможное, чтобы объяснить шаги, необходимые для реализации Chrome Extension, хоста Native Messaging и установить связь между ними. (Пожалуйста, просмотрите следующую ссылку для получения дополнительной информации о Chrome Native Messaging: Chrome Native Messaging Как сделать.
РАСШИРЕНИЕ ХРОМА
Во-первых, нам нужно настроить расширение Chrome. Поскольку это будет очень простое расширение, нам нужно только manifest.json file (обратите внимание, что это файл манифеста расширения — у нативного хоста также будет свой собственный файл манифеста) и реализация 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
}
Важным моментом здесь является то, что реализация будет предоставлена в 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.
Родной СООБЩЕНИЕ ХОЗЯИН
Теперь нативный хост также имеет свой собственный файл 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/"]
}
Пара интересных вещей: имя идентифицирует ключ, под которым зарегистрирован этот нативный хост. Путь — это полный путь к исполняемому файлу собственного хоста. Тип связи stdio означает, что мы используем стандартный ввод / вывод для связи (в настоящее время поддерживается только тип). И наконец, allow_origins указывает, какие расширения могут взаимодействовать с этим собственным хостом — так что вы должны узнать, что является ключом вашего расширения!.
Следующим шагом является регистрация этого узла Native Messaging в реестре (для Windows) и указание расположения его файла манифеста. На следующих снимках экрана показано, как это сделать для Windows (ознакомьтесь с приведенной ссылкой, чтобы узнать, как это сделать в OSX и Linux):
После того, как вы добавили запись реестра для вашего собственного хоста, остается только написать ваш собственный хост. Следующий код 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 байта и вычислить размер сообщения. Я объяснил, как это сделать, в другом посте, который можно найти здесь:
Как рассчитать размер сообщения, отправленного расширением Chrome
Для будущих людей Google вот как я делаю это:
Стиль С
чтение
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);
Пишу
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;
Пишу
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;