Chrome 内容和后台脚本可以共享对 blob: URL 的访问吗?

Utk*_*nos 3 javascript google-chrome-extension getusermedia

我正在getUserMediaChrome 扩展内容脚本中创建一个流,我想将它传递给后台脚本。

你不能在它们之间传递非 JSON 数据,所以我的策略是将生成的 blob URL 传递给流。

内容脚本:

function get_stream() {
    navigator.mediaDevices.getUserMedia({video: 1}).then(stream => {
        chrome.runtime.sendMessage({action: 'got_stream', params: {stream_url: URL.createObjectURL(stream)}});
    });
Run Code Online (Sandbox Code Playgroud)

后台脚本:

chrome.runtime.onMessage.addListener(function(data) {
    switch (data.action) {
        case 'got_stream': got_stream(data.params); break;
    }
});

function got_stream(params) {
    let vid = document.createElement('video');
    alert(params.stream_url); //blob:http://...
    vid.src = params.stream_url; //error - file not found
}
Run Code Online (Sandbox Code Playgroud)

这很好......直到我尝试将它应用于生成的<video />元素,此时控制台说找不到文件。

我认为这是因为背景和内容脚本处于沙盒环境中。

有没有什么办法可以解决这个问题,而不必做一些核心的事情,比如通过 WebRTC 或其他什么东西来传输流?

Utk*_*nos 8

我发现这是一个起源问题。

内容脚本在当前网页的上下文中运行,而后台脚本在扩展的上下文中运行。

Blob URL 是按来源分组的,因此,与您通常无法从一个域到另一个域进行 AJAX 一样,两个域也不能共享 Blob URL。

这是通过不在当前网页中运行内容脚本来解决的(因此不在 下的清单中指定content_scripts),而是在新选项卡或弹出窗口中运行。

背景:

window.open('content-page.html');
Run Code Online (Sandbox Code Playgroud)

内容页:

<script src='content-script.js'></script>
Run Code Online (Sandbox Code Playgroud)

然后,由 content-script.js 生成的任何 blob URL 都可以在后台读取,因为它们现在都在扩展的上下文中运行,即共享源。

[编辑]

如果您不喜欢弹出窗口的想法(毕竟,在 Mac 上这些被呈现为完整选项卡),您可以改为将一个iframe注入当前选项卡并从那里运行您的内容脚本。

为此,请从清单中调用内容脚本:

{
    "content_scripts": [{
        "matches": ["<all_urls>"],
        "js": ["content-script-curr-tab.js"]
    }]
}
Run Code Online (Sandbox Code Playgroud)

然后在那:

let ifr = document.createElement('iframe');
ifr.setAttribute('allow', 'microphone; camera'); //necessary for cross-origin frames that request permissions
ifr.style.display = 'none';
ifr.src = chrome.runtime.getURL('page-to-inject-into-iframe.html');
document.body.appendChild(ifr);
Run Code Online (Sandbox Code Playgroud)

注意chrome.runtime.getURL()- 这是在扩展的上下文中而不是网页中托管和运行页面的关键。

然后,最后,在page-to-inject-into-iframe.html

<script src='script-to-inject-into-iframe.js'></script>
Run Code Online (Sandbox Code Playgroud)

然后在里面做你的事情!