我正在Chrome扩展程序内容脚本中创建getUserMedia
流,并且希望将其传递到后台脚本。
您不能在它们之间传递不可使用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)}});
});
背景脚本:
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
}
这很好...直到我尝试将其应用到生成的<video />
元素上为止,此时控制台会显示找不到该文件。
我认为是因为背景脚本和内容脚本位于沙盒环境中。
是否有解决此问题的方法,而不必做一些像通过WebRTC实际传输流之类的核操作?
答案 0 :(得分:1)
blob网址很可能与来源绑定在一起,因此我认为这不起作用。请参阅适配器存储库中的一些讨论here。
您是否尝试过在内容和后台脚本之间创建RTCPeerConnection并以这种方式发送流?由于多种原因并不理想,但总比没有好。
答案 1 :(得分:1)
我发现这是一个起源问题。
内容脚本在当前网页的上下文中运行,而后台脚本在扩展名的上下文中运行。
blob URL按来源分组,因此,以通常无法从一个域到另一域的AJAX相同的方式,两个域也不能确定blob URL。
此问题的解决方法是运行内容脚本而不是在当前网页上运行(因此不在content_scripts
下的清单中指定),而是在新标签页或弹出窗口中运行。
背景:
window.open('content-page.html');
内容页面:
<script src='content-script.js'></script>
然后,由content-script.js生成的任何Blob URL都将在后台可读,因为它们现在都在扩展程序的上下文中运行,即共享来源。
[编辑]
如果您不喜欢弹出窗口的想法(毕竟,在Mac上,这些窗口均显示为完整选项卡),则可以将iframe
注入当前选项卡并运行contenet脚本从那里。
为此,请从清单中调用内容脚本:
{
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content-script-curr-tab.js"]
}]
}
然后在其中:
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);
然后,最后在page-to-inject-into-iframe.html
中:
<script src='script-to-inject-into-iframe.js'></script>
然后在那做你的事!