Chrome 66 允许网页通过 Presentation API 使用辅助连接屏幕,并通过 Presentation Receiver API 控制其内容。
![1 月 2 日。用户选择连接辅助显示屏](https://developer.chrome.google.cn/static/blog/present-web-pages-to-secondary-attached-displays/image/12-user-picks-secondar-03beeb097e67e.jpg?authuser=6&hl=sr)
![2 月 2 日。系统会自动向之前选择的显示屏显示网页](https://developer.chrome.google.cn/static/blog/present-web-pages-to-secondary-attached-displays/image/22-web-page-is-automat-5dab3e95502c3.jpg?authuser=6&hl=sr)
背景
在此之前,Web 开发者可以打造这样的体验,使用户在 Chrome 中看到的内容不同于他们在远程显示屏上看到的内容,同时仍能在本地控制这种体验。例如,在电视上播放视频时在 youtube.com 上管理播放队列,或者在环聊会话中全屏显示时,在笔记本电脑上查看包含演讲者备注的卷轴。
但在某些情况下,用户可能只想将内容呈现到另一个已连接的显示屏上。例如,假设某会议室中有一个用户通过 HDMI 数据线连接到了一台投影仪。用户确实想要在投影仪上全屏演示幻灯片,而不是将演示内容镜像到远程端点,从而让笔记本电脑屏幕可用于演讲者备注和幻灯片控制。虽然网站作者可以通过非常基本的方式(例如弹出一个新窗口,而用户必须手动将其拖动到辅助显示屏并最大化为全屏)来支持此功能,但这会非常繁琐,并且会导致本地和远程演示之间出现不一致的体验。
演示页面
我来介绍一下如何使用 Presentation API 在辅助连接的显示屏上呈现网页。最终结果位于 https://googlechrome.github.io/samples/presentation-api/。
首先,我们将创建一个新的 PresentationRequest
对象,其中包含我们希望在辅助显示屏上显示的网址。
const presentationRequest = new PresentationRequest('receiver.html');
In this article, I won’t cover use cases where the parameter passed to
`PresentationRequest` can be an array like `['cast://foo’, 'apple://foo',
'https://example.com']` as this is not relevant there.
We can now monitor presentation display availability and toggle a "Present"
button visibility based on presentation displays availability. Note that we can
also decide to always show this button.
<aside class="caution"><b>Caution:</b> The browser may use more energy while the <code>availability</code> object is alive
and actively listening for presentation display availability changes. Please
use it with caution in order to save energy on mobile.</aside>
```js
presentationRequest.getAvailability()
.then(availability => {
console.log('Available presentation displays: ' + availability.value);
availability.addEventListener('change', function() {
console.log('> Available presentation displays: ' + availability.value);
});
})
.catch(error => {
console.log('Presentation availability not supported, ' + error.name + ': ' +
error.message);
});
显示演示文稿显示提示需要用户手势,例如点击按钮。因此,我们对按钮点击调用 presentationRequest.start()
,并等待 promise 在用户选择了展示屏幕(例如,我们的用例中的辅助连接的显示屏)后解析。
function onPresentButtonClick() {
presentationRequest.start()
.then(connection => {
console.log('Connected to ' + connection.url + ', id: ' + connection.id);
})
.catch(error => {
console.log(error);
});
}
呈现给用户的列表还可能包含远程端点,例如 Chromecast 设备(如果您已连接到对它们进行通告的网络)。请注意,镜像的屏幕不在列表中。请访问 http://crbug.com/840466。
![演示文稿显示选择器](https://developer.chrome.google.cn/static/blog/present-web-pages-to-secondary-attached-displays/image/presentation-display-pick-6b14dbd5ed08c.png?authuser=6&hl=sr)
promise 解析后,PresentationRequest
对象网址处的网页将呈现给所选屏幕。一切就绪!
现在,我们可以更进一步,监控“close”和“terminate”事件,如下所示。请注意,您可以使用 presentationRequest.reconnect(presentationId)
重新连接到“关闭的”presentationConnection
,其中 presentationId
是上一个 presentationRequest
对象的 ID。
function onCloseButtonClick() {
// Disconnect presentation connection but will allow reconnection.
presentationConnection.close();
}
presentationConnection.addEventListener('close', function() {
console.log('Connection closed.');
});
function onTerminateButtonClick() {
// Stop presentation connection for good.
presentationConnection.terminate();
}
presentationConnection.addEventListener('terminate', function() {
console.log('Connection terminated.');
});
与页面通信
现在您在想,这很好,但是如何在控制器页面(我们刚刚创建的页面)和接收器页面(传递给 PresentationRequest
对象的页面)之间传递消息?
首先,使用 navigator.presentation.receiver.connectionList
检索接收器页面上的现有连接,并监听传入的连接,如下所示。
// Receiver page
navigator.presentation.receiver.connectionList
.then(list => {
list.connections.map(connection => addConnection(connection));
list.addEventListener('connectionavailable', function(event) {
addConnection(event.connection);
});
});
function addConnection(connection) {
connection.addEventListener('message', function(event) {
console.log('Message: ' + event.data);
connection.send('Hey controller! I just received a message.');
});
connection.addEventListener('close', function(event) {
console.log('Connection closed!', event.reason);
});
}
接收消息的连接会触发一个您可以监听的“message”事件。
该消息可以是字符串、Blob、ArrayBuffer 或 ArrayBufferView。
发送它就像从控制器页面或接收器页面调用 connection.send(message)
一样简单。
// Controller page
function onSendMessageButtonClick() {
presentationConnection.send('Hello!');
}
presentationConnection.addEventListener('message', function(event) {
console.log('I just received ' + event.data + ' from the receiver.');
});
您可观看 https://googlechrome.github.io/samples/presentation-api/ 上的示例,了解其工作原理。我相信您和我一样喜欢这款游戏。
示例和演示
请查看我们在本文中使用的官方 Chrome 示例。
此外,我们还建议您观看互动式 Photowall 演示。此 Web 应用允许多个控制器在演示文稿屏幕上以协作方式展示照片幻灯片。您可以访问 https://github.com/GoogleChromeLabs/presentation-api-samples 获取代码。
![Photowall 演示屏幕截图](https://developer.chrome.google.cn/static/blog/present-web-pages-to-secondary-attached-displays/image/photowall-demo-screenshot-10527faacc264.jpg?authuser=6&hl=sr)
还有一件事
Chrome 有一个“投射”浏览器菜单,用户可以在访问网站时随时调用。如果您想控制此菜单的默认呈现方式,请将 navigator.presentation.defaultRequest
分配给之前创建的自定义 presentationRequest
对象。
// Make this presentation the default one when using the "Cast" browser menu.
navigator.presentation.defaultRequest = presentationRequest;
开发提示
如需检查接收器页面并进行调试,请前往内部 chrome://inspect
页面,选择“Other”,然后点击当前显示的网址旁边的“检查”链接。
![检查展示接收器页面](https://developer.chrome.google.cn/static/blog/present-web-pages-to-secondary-attached-displays/image/inspect-presentation-rece-260dbbca83182.png?authuser=6&hl=sr)
您还可以查看内部 chrome://media-router-internals
页面,深入了解内部发现/可用性流程。
后续步骤
自 Chrome 66 起,ChromeOS、Linux 和 Windows 平台均受支持。稍后将支持 Mac。