В Chrome Native Messaging: как долго длится время жизни нативного объекта экземпляра приложения?

Живое приложение, которое общается с расширением Chrome, существует вечно? Я имею в виду, должен ли он присутствовать, например, до того, как произойдет обратная передача Я не смог найти никакой конфигурации для этого, чтобы добавить в файл манифеста.

У меня есть страница, на странице есть несколько объектов. После нажатия на объект и отправки / получения одного сообщения с помощью приложения Native оно больше не работает для остальных объектов.

Мой точный вопрос: как долго длится время жизни нативного объекта экземпляра приложения? Должен ли этот объект реагировать, например, навсегда? Или мне нужен цикл, например, для чтения сообщений из стандартного ввода, если это непрерывный обмен данными?

Вот мой фоновый скрипт:

var host_name = "files.mffta.java.nativeapp";
var port = null;
initPort();
function initPort() {
    console.log( 'Connecting to native host: ' + host_name );
    port = chrome.runtime.connectNative( host_name );
    port.onMessage.addListener( onNativeMessage );
    port.onDisconnect.addListener( onDisconnected );
}

// Listen for messages that come from the content script.
chrome.runtime.onMessage.addListener(
  function( messageData, sender, sendResponse ) {
    if( messageData ) {
        sendNativeMessage(messageData);
        sendResponse( { res: 'done!' } );
    }
  } );

// Sending a message to the port.
function sendNativeMessage(messageData) {
    if( port == null )
        initPort();
    console.log( 'Sending message to native app: ' + JSON.stringify( messageData ) );
    port.postMessage( messageData );
    console.log( 'Sent message to native app.' );
}

// Receiving a message back from the Native Client API.
function onNativeMessage( message ) {
    console.log( 'recieved message from native app: ' + JSON.stringify( message ) );

    alert( "messaged received from Native: " + JSON.stringify( message ) );
    //sending a message to Content Script to call a function
    if( message.methodName && message.methodName != "" ) {
        chrome.tabs.query( { active: true, currentWindow: true }, function( tabs ) {
            chrome.tabs.sendMessage( tabs[0].id, message, function( response ) {
                // Call native again to return JavaScript callback function results
                alert ("calc res received by extension : " + response);
                sendNativeMessage({ type: "JSCallbackRes", callbackRes: response });
            } );
        } );
    }
}

// Disconnecting the port.
function onDisconnected() {
    console.log( "ERROR: " + JSON.stringify( chrome.runtime.lastError ) );
    console.log( 'disconnected from native app.' );
    port = null;
}

Мое манифест расширения:

{
  "name": "Files.ChromeExt.Operarations",
  "version": "1.0",
  "manifest_version": 2,
  "description": "This extension calls a Native API which that API calls some x-Files related operations.",
  "icons": {
    "128": "x-files_icon.png"
  },
  "permissions": [
    "nativeMessaging", "activeTab"
  ],
  "background": {
    "persistent": true,
    "scripts": ["main.js"]
  },
  "content_scripts" : [{"matches": ["http://localhost/*","https://localhost/*"], 
    "js": ["contentscripts/page.js"]}]
} 

Java-программа: [как было задано в комментариях]

import java.io.IOException;
import javax.swing.JOptionPane;

public class Applet {

    public Applet(){}

    public static void main(String[] args) {
        try {
            readMessage();
            sendMessage("{\"msg\" : \"hello\"}");

        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, ex.getMessage());
        }
    }

    public static String readMessage() {
        String msg = "";
        try {
            int c, t = 0;
            for (int i = 0; i <= 3; i++) {
                t += Math.pow(256.0f, i) * System.in.read();
            }

            for (int i = 0; i < t; i++) {
                c = System.in.read();
                msg += (char) c;
            }
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, "error in reading message from JS");
        }
        return msg;
    }

    public static void sendMessage(String msgdata) {
        try {
            int dataLength = msgdata.length();
            System.out.write((byte) (dataLength & 0xFF));
            System.out.write((byte) ((dataLength >> 8) & 0xFF));
            System.out.write((byte) ((dataLength >> 16) & 0xFF));
            System.out.write((byte) ((dataLength >> 24) & 0xFF));

            // Writing the message itself
            System.out.write(msgdata.getBytes());
            System.out.flush();
        } catch (IOException e) {
            JOptionPane.showMessageDialog(null, "error in sending message to JS");
        }
    }
}

Изучив журнал Chrome, я вижу следующие сообщения:

  • Собственный узел обмена сообщениями попытался отправить сообщение длиной 1936028240 байт.
  • {"message": "Ошибка связи с собственным хостом обмена сообщениями."}", источник: chrome-extension://XXX

Я тестирую их на 64-битной машине с Win 8.0.

Обновление: теперь я убежден, что хост работает вечно, если вызывается connectNative и порт не останавливается из-за ошибки. Таким образом, коренная причина сообщений об ошибках выше должна быть чем-то иным, чем время жизни порта. Я имею в виду, что какая-то ошибка в моем сообщении принудительно останавливает порт.

Я высоко ценю любые комментарии, которые вы можете дать.

1 ответ

Решение

При использовании chrome.runtime.sendNativeMessage, родное приложение будет доступно сразу после получения и перед отправкой сообщения. Так как прием сообщения асинхронный, вы не можете предполагать, что приложение все еще живо, когда обратный вызов sendNativeMessage называется.

Если вы хотите, чтобы родное приложение оставалось подольше, используйте chrome.runtime.connectNative, Это создаст порт, и нативное приложение будет работать до тех пор, пока оно не выйдет или пока не вызовет добавочный номер. disconnect() в порту. Если ваше приложение неожиданно завершает работу рано, то, скорее всего, вы допустили ошибку при реализации собственного протокола обмена сообщениями.

Для точного формата собственного протокола обмена сообщениями, посмотрите на документацию: https://developer.chrome.com/extensions/nativeMessaging


Что касается вашего редактирования, сообщение об ошибке совершенно ясно: длина недействительна. Предполагается, что длина находится в собственном байтовом порядке системы (который может быть прямым или старшим). Когда вы получите следующее сообщение об ошибке с чрезмерной разницей смещений, тогда есть две возможности:

  1. Порядок байтов целого числа неверен, или
  2. Ваш вывод содержит некоторые неожиданные символы, которые приводят к смещению байтов и приводят к тому, что байты находятся в неправильном месте.

Чтобы узнать, в каком случае вы находитесь, просмотрите число как шестнадцатеричное число. Если имеется много конечных нулей, это показывает, что порядок байтов неверен. Например, если ваше сообщение имеет длину 59, шестнадцатеричное значение 3b, Если порядковый номер указан неверно, отображается следующее сообщение:

Собственный узел обмена сообщениями попытался отправить сообщение длиной 989855744 байта.

1493172224 является 3b 00 00 00 в шестнадцатеричном формате, и вы можете заметить, что 3b есть, но не в том конце (другими словами, порядок байтов обратный). Решением этой проблемы для вашей системы является редактирование кода для печати байтов в обратном порядке.

Если шестнадцатеричное представление числа не выглядит удаленно близко к вашему номеру, то есть вероятность, что длина сообщения неверна. Напомним, что stdio используется для связи, поэтому, если вы выводите что-то еще (например, ошибки) в stdout (System.out) вместо stderr (System.err), то протокол нарушается и ваше приложение будет остановлено.

        System.err.println(ex.getStackTrace());                     // <-- OK
        System.out.println("[ error -> " + ex.getMessage() + " ]"); // <-- BAD

В Windows также проверьте, установлен ли для режима stdout (и stdin) режим O_BINARY. В противном случае Windows вставит дополнительный байт перед 0A (0D 0A), что приводит к смещению всех байтов и неправильному числу. Java Runtime уже включает двоичный режим, поэтому для вашего случая это не актуально.

Другие вопросы по тегам