Passing message from one listener to another

a 夏天 提交于 2019-12-13 06:53:07

问题


I'm developing an extension for Chrome, and here's the workflow I'm trying to achieve:

popup sends message -> content script 1 listens -> content script 1 sends message -> content script 2 listens -> content script 2 performs action

In concept it's fine and dandy; what I've done is set up 2 listeners: one in each content script:

Popup:

chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
                console.log('popup send request');
                chrome.tabs.sendMessage(tabs[0].id, obj);
            });

Content script 1:

chrome.runtime.onMessage.addListener((function (request, sender) {
    this.log('wg got request', 'request', request, 'sender', sender);
    if (request.action == 'options-updated') {
        this.updateOptions(request, (function() {
            var obj = {action: 'refresh', WG: window.WG};
            this.log('wg forwarded request');
            chrome.runtime.sendMessage(obj); // attempting to forward another request
            return true;
        }).bind(this));
    }
    return true;
}).bind(window.WG));

Content script 2:

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    console.log('content script got request', 'request', request, 'sender', sender);
    if (request.WG) {
        request.WG.log('message', request.action);
        if (request.action == 'refresh') {
            WGRefresh(request.WG, request.options);
        }
    }
    return true;
});

Problem is, content script 2 only receives the first message. So the output I'm getting is:

popup send request content script got request (first, to ignore) wg got request (same, first, don't ignore here) wg forward request

And then nothing. The content script should have fired it again, and in the request I always send "action", which I check for in the listener, but for the logs I don't differentiate (it should ALWAYS log, so this means the request never gets there).

I've tried returning true in all the listeners, according to the documentation it will keep the chain running and not stop after the first hit, but even so it's not working. What am I doing wrong?!


回答1:


There are 2 sendMessage functions in Chrome API.

  • chrome.runtime.sendMessage sends a message to all open extension pages (i.e. background, popup, etc.)
  • chrome.tabs.sendMessage sends a message to all content scripts from the extension in a given tab

So the call to chrome.runtime.sendMessage() in your first content script can't reach any other content script.

What's more, you can't call chrome.tabs directly from a content script.

To do what you want, you need to set up a background script that will act like a proxy between CS1 and CS2. Technically, you could use the popup, but it's unreliable, as the popup may be closed and then nobody would be listening. The background page (or better yet, an event page) is designed specifically for that purpose.

So the scheme becomes: popup -(tabs.sendMessage)-> CS1 -(runtime.sendMessage)-> background -(tabs.sendMessage)-> CS2

Do note that background page will need to know the tab ID to send the message to. If it's the same tab for some reason, e.g. you're trying to message across frames, you can use the sender parameter in the callback.

See Messaging docs for more details.



来源:https://stackoverflow.com/questions/28302566/passing-message-from-one-listener-to-another

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!