javascriptgoogle-chromegoogle-chrome-extensionchrome-extension-manifest-v3

How to communicate between service work on chrome extension


I write codes below that popup.js, content.js and background.js. It can communicate popup.js <-> background.js. But content.js which is embedded in the site can't communicate background.js. Console.log in runtime.sendMessgae just say "undefine". How can I communicate background.js between content.js?

manifest.js

{
    "manifest_version": 3,
    "name": "test_project",
    "short_name": "test",
    "version": "1.0.0",
    "description": "",
    "action": {
        "default_popup": "page/index.html"
    },
    "permissions": ["identity","scripting","storage","alarms"],
    "content_scripts": [
        {
            "matches": ["file:///*"],
            "js": [
                "popup.bundle.js"
            ]
        },
        {
            "matches": [ "*://mail.google.com/*" ],
            "js": [
                "content.bundle.js"
            ],
            "run_at": "document_start"
        }
    ],
    "background": {
        "service_worker": "background.bundle.js"
    },
    "oauth2": {
        "client_id": "",
        "scopes": [
            "https://www.googleapis.com/auth/gmail.compose"
        ]
    },
    "web_accessible_resources": [{
        "resources": [
            "extension.bundle.js",
            "extension.bundle.js.map",
            "gmailJsLoader.bundle.js",
            "gmailJsLoader.bundle.js.map"
        ],
        "matches": ["<all_urls>"]
    }],
    "host_permissions": [
        "https://*/*"
    ],
    "options_page": "page/options.html"
}

background.js

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    console.log('πŸ“₯ λ©”μ‹œμ§€ μˆ˜μ‹ :', request);

    if (request.action === 'getAuthToken') {
        console.log('πŸš€ getAuthToken 호좜 μ‹œμž‘');
        chrome.identity.getAuthToken({ interactive: true }, (token) => {
        if (chrome.runtime.lastError) {
            console.error('❌ 였λ₯˜ λ°œμƒ:', chrome.runtime.lastError);
            sendResponse({ success: false, error: chrome.runtime.lastError.message });
        } else {
            console.log('βœ… μ•‘μ„ΈμŠ€ 토큰:', token);
            sendResponse({ success: true, token });
        }
        });
        // 비동기 응닡을 λŒ€κΈ°
        return true;
    }
});

popup.js

// It can work
document.getElementById('inesrtAddressBookButton').addEventListener('click', () => {
        chrome.runtime.sendMessage(EXTENSION_ID, { action: 'getAuthToken' }, (response) => {
            console.log(response)
        })
})

content.js

// It loaded on gmail
const loaderId = setInterval(() => {
    if (!window._gmailjs) {
        return;
    }

    clearInterval(loaderId);
    startExtension(window._gmailjs);
}, 100);

function startExtension(gmail) {
    console.log("Extension loading...");
    window.gmail = gmail;
    gmail.observe.on("load", () => {
        gmail.observe.on("compose", (compose) => {

            var content_html = $(`
                <div>
                    test
                </div>
            `);

            gmail.tools.add_compose_button(compose, content_html, function() {
                getAuthTokenAndFetchData(compose)
            }, "");
        });
    });
}

function getAuthTokenAndFetchData(compose) {
    chrome.runtime.sendMessage(EXTENSION_ID, { action: 'getAuthToken' }, (response) => {
        console.log(response)
    })
}

Solution

  • Judging by the fact that you access page variables on window, the code runs in a DOM script element or in an explicitly specified MAIN world (more info). The script is no longer a part of the extension's context, but just an unprivileged web page script without access to chrome global API that only exists in the isolated content script.

    To send a message to the extension you need to use externally_connectable messaging: https://developer.chrome.com/docs/extensions/develop/concepts/messaging#external-webpage

    Note that you don't need it in the chrome-extension:// pages such as the action popup, so you can remove EXTENSION_ID in your popup.js that runs in the page specified as default_popup.