在chrome扩展清单v3中从后台脚本播放音频



在manifest v2中,我曾从后台脚本播放音频,如

new Audio(url)

但在manifest v3中,相同的脚本显示错误

未捕获引用错误:音频未定义

如何在chrome扩展中播放来自后台脚本(在v3中更改为服务工作者(的音频?

使用屏幕外文档的新解决方案

目前无法在服务工作者中直接播放或捕获媒体,因为他们无法访问DOMAPI。

屏幕外文档适用于Chrome版本109,因此这里是我基于Chromium的api测试文件的解决方案。因为屏幕外文档上的代码可以访问所需的API,所以您需要打开一个API并使用消息传递来播放其中的声音。这个解决方案比旧的解决方案优雅得多,因为同样的原因,老的解决方案使用了可见的弹出窗口。

要在服务工作者中播放声音,请使用适当的参数调用playSound()函数,如下所示。如果30秒内不播放声音,屏幕外文档将自动关闭,因为";终身强制执行";。

manifest.json

...
"permissions": ["offscreen"]
...

background.js

/**
* Plays audio files from extension service workers
* @param {string} source - path of the audio file
* @param {number} volume - volume of the playback
*/
async function playSound(source = 'default.wav', volume = 1) {
await createOffscreen();
await chrome.runtime.sendMessage({ play: { source, volume } });
}
// Create the offscreen document if it doesn't already exist
async function createOffscreen() {
if (await chrome.offscreen.hasDocument()) return;
await chrome.offscreen.createDocument({
url: 'offscreen.html',
reasons: ['AUDIO_PLAYBACK'],
justification: 'testing' // details for using the API
});
}

offscreen.html

<script src="offscreen.js"></script>

offscreen.js

// Listen for messages from the extension
chrome.runtime.onMessage.addListener(msg => {
if ('play' in msg) playAudio(msg.play);
});
// Play sound with access to DOM APIs
function playAudio({ source, volume }) {
const audio = new Audio(source);
audio.volume = volume;
audio.play();
}

注意:屏幕外API相对较新,因此一些用户可能还没有支持它所需的最低版本Chrome(109(。如果你关心这些用户,你可以通过检查chrome.offscreen是否未定义来使用旧的解决方案作为polyfill。

最后一件事:您应该更新创建屏幕外文档的对正属性。它是必需的,但尚未使用。文件说明如下:

调整

开发人员提供的字符串,更详细地解释了对后台上下文的需求。用户代理可以在向用户显示时使用它。

原始答案

如官方文件所述:

目前无法在服务人员。为了使Manifest V3扩展能够利用网络的媒体播放和捕获功能,扩展将需要使用chrome.windows.create((或chrome.tabs.create((。一旦创建,扩展就可以使用消息传递到回放文档和服务之间的坐标工人

在他们对此做点什么之前,(希望他们最终会这样做——考虑到他们文章中"current"的用法(这里有一个快速的解决方法:

audio.html

<link href='icon.png' rel='icon' type='image/x-icon'>
<title>Notification</title>
<script src="audio.js"></script>
<style> :root { color-scheme: light dark }</style>

audio.js

resizeTo(0, 0);
onload = () => {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
let audio = new Audio(urlParams.get('src'));
audio.volume = urlParams.get('volume');
audio.play();
setTimeout(close, urlParams.get('length'));
}

background.js(服务人员(

function playSound() {
let url = chrome.runtime.getURL('audio.html');
// set this string dynamically in your code, this is just an example
// this will play success.wav at half the volume and close the popup after a second
url += '?volume=0.5&src=success.wav&length=1000';
chrome.windows.create({
type: 'popup',
focused: true,
top: 1,
left: 1,
height: 1,
width: 1,
url,
})
}

一旦调用playSound(),它将创建一个弹出窗口来播放声音。最好将弹出窗口的图标设置为带有<link>标签的扩展程序的图标,这样用户就可以知道弹出窗口的来源。

请注意,audio.js必须从一个单独的文件进行链接。否则,您将收到一个内联脚本策略冲突错误。

进一步的想法

如果你在用chrome.notifications API发送吐司通知时播放声音,你可能想把弹出窗口移到通知后面。一个简单的方法是在右下角创建一个弹出窗口,其中包含:top: 99999, left: 99999然后在您的javascript:moveTo(window.screenX - 100, window.screenY);

或者,您可以将弹出窗口本身变成toast通知。

更新#1

MV3的屏幕外文档功能似乎正在进行一些工作。有了这个新的API,扩展将能够打开有限的、可以访问DOMAPI的屏幕外文档。

更多信息在提案中。在这里你可以追踪它的发展。

然而,这并不是最终的解决方案。正如提案中所述,从长远来看,Chromium打算直接在扩展服务人员中支持其中的许多能力。

最新更新