N
N
netW0rm2017-02-27 18:07:01
Google Chrome
netW0rm, 2017-02-27 18:07:01

How to organize messaging between chrome extensions and web page?

There is an extension for chrome, you need to communicate with it from any Internet pages by type: request (from the page) - response (from the extension)
Sending messages from web pages is not suitable, because. You need to specify the domain in the manifest. It is required to exchange messages from different domains, which you cannot immediately write in the manifest.

"externally_connectable": {
  "matches": ["*://*.example.com/*"]
}

I tried sending a regular HTTP request, intercepting it in the extension and redirecting to the data URL which contained the response with the message:
// background.js
const extensionId = 'abcdefg...'
const message = 'xyz'
chrome.webRequest.onBeforeRequest.addListener(details => {
  if (details.url === `http://${extensionId}/`) {
    return {
      redirectUrl: 'data:,' + message
    }
  }
}, { urls: ["<all_urls>"] }, ["blocking"])

// webpage.js
const extensionId = 'abcdefg...'
fetch('http://'+extensionId)
  .then(r => r.text())
  .then(message => {
    console.log(message)
  })

but the browser throws an error
Redirects to data: URL are allowed only when mode is "no-cors".

if you enable no-cors fetch will not be able to return the response body and will return status == 0
Any ideas, colleagues?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
N
netW0rm, 2017-02-28
@netW0rm

It turned out)
The scheme is as follows:

//manifect.json
{
    "name": "test",
    "description": "test",
    "version": "0.1",
    "permissions": [
        "management",
        "<all_urls>"
    ],
    "content_scripts": [{
        "matches": ["<all_urls>"],
        "js": ["content.js"],
        "run_at": "document_end"
    }],
    "background": {
        "scripts": ["background.js"]
    },
    "manifest_version": 2
}

//content.js
const script = document.createElement('script')
script.textContent = `${sendMessageToExtension}`
document.documentElement.appendChild(script)

document.addEventListener('pageMessage', ev => {
    chrome.runtime.sendMessage(ev.detail, sendResponse)
})

function sendResponse(response) {
    const event = new CustomEvent(response._id, { detail: response })
    document.dispatchEvent(event)
}

function sendMessageToExtension(extensionId, message) {
    return new Promise((resolve, reject) => {
        const _id = Math.random().toString()

        const event = new CustomEvent('pageMessage', {
            detail: {
                _id,
                message,
                extensionId
            }
        })

        const responseHandler = (event) => {
            resolve(event.detail.message)
            document.removeEventListener(_id, responseHandler)
        }

        document.addEventListener(_id, responseHandler)

        document.dispatchEvent(event)
    })
}

//background.js
chrome.management.getSelf(extension => {
    chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
        if (request.extensionId !== extension.id) return

        // наше сообщение
        const message = request.message
        // готовим ответ
        const response = { result: message.value * 2 }

        sendResponse(Object.assign({}, request, { message: response }))
    })
})

now every page has sendMessageToExtension function
// web page
main()
async function main() {
  const extensionId = 'adifgidpakahghppcfdelejcfgnpdenj'
  const response = await sendMessageToExtension(extensionId, { value: 5 })
  console.log(response.result) // 10
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question