Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

chrome.tabs.sendMessage not working while sendResponse works

Here is the manifest of the chrome extension :

{
  "name": "myconnector",
  "short_name": "myconnector",
  "version": "1.1",
  "manifest_version": 2,
  "description": "myapp",
  "background": {
    "scripts": ["main.js"],
    "persistent": true
    },
    "externally_connectable": {
      "ids": ["*"],
      "matches": ["*://*.myurl.fr/*"]
  },
  "web_accessible_resources": [ "emulation.js", "content_scripts.js" ],
  "icons": {
    "16": "icon-16.png",
    "128": "icon-128.png"
  },
  "permissions": [
    "tabs",
    "nativeMessaging"
  ]
}

Background page of the chrome extension :

//------ Message received from external web site

chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {

    if(request.areYouThere) {
        onNativeMessage(true);
    }

    if(!port) {
        port = chrome.runtime.connectNative(hostName);
        //port.onMessage.addListener( onNativeMessage );
    }

    port.onMessage.addListener(function(msg) {sendResponse(msg);});

     port.onDisconnect.addListener(function() {
        console.log("Disconnected from native App");
        port = null;
    });

    if (request.data) {
      var data = request.data;
      console.log(JSON.stringify(request));
      port.postMessage(data);
    }

    return true;

  });

// ----- Message received from Native Host App

function onNativeMessage( message ) {
    console.log( 'received message from native app: ' + JSON.stringify( message ) );
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
        chrome.tabs.sendMessage(tabs[0].id, message, function(response){});
    });
}

And here is the code of the web site calling the extension :

$("#my-action").click(function(){

            console.log("calling method MyAction");

            chrome.runtime.sendMessage( "<extension id>",  
                                {data: 
                                    {action:"MyAction"}
                                    }, 
                                function(response) {
                console.log(JSON.stringify(response));
                $("#result").text(JSON.stringify(response));
            });
        });

When I do this :

port.onMessage.addListener(function(msg) {sendResponse(msg);});

The response is correctly sent but I get a chrome.native.lastError.message :

Cannot send a response more than once per chrome.runtime.onMessage listener per document (message was sent by extension for URL undefined).

But when I do this :

port.onMessage.addListener( onNativeMessage );

This method calling onNativeMessage sents a message back to the web site (allegedly ?) using the method chrome.tabs.sendMessage. But the web site never gets the response.

Furthermore, my extension needs to instantiate a port so it can use long-lived connection with my native host app.

Am I doing something wrong ?

like image 312
Thordax Avatar asked Oct 18 '25 15:10

Thordax


1 Answers

When I do this :

port.onMessage.addListener(function(msg) {sendResponse(msg);});

The response is correctly sent but I get a chrome.runtime.lastError.message :

Cannot send a response more than once per chrome.runtime.onMessage listener per document (message was sent by extension for URL undefined).

That's because you're adding a listener EVERY time you get an external message. So after getting the second message, sendResponse() tries to run twice (the new one and the old one again).


But when I do this :

port.onMessage.addListener( onNativeMessage );

This method calling onNativeMessage sends a message back to the web site (allegedly ?) using the method chrome.tabs.sendMessage. But the web site never gets the response.

You can't do that; chrome.tabs.sendMessage sends a message to the content script context, not the webpage.


You should modify your code to only add the listeners once, or at least ensuring that there is one listener at a time.

The trick, of course, is that sendResponse reference changes every time. I guess you can do it with a self-deregistering listener:

if(!port) {
    port = chrome.runtime.connectNative(hostName);

    port.onDisconnect.addListener(function() {
      console.log("Disconnected from native App");
      port = null;
    });
}

var callback = function(msg) {
  sendResponse(msg);
  port.onMessage.removeListener(callback); // The power of closures!
};

port.onMessage.addListener(callback);
like image 195
Xan Avatar answered Oct 21 '25 04:10

Xan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!