网络功能
我们希望缩小 Web 与原生之间的功能差距,让开发者能够轻松在开放 Web 平台上打造出色的体验。我们坚信,每位开发者都应具备打造出色网络体验所需的各项功能,我们致力于打造一个功能更强大的网络。
不过,有一些功能(如文件系统访问和空闲检测)是原生应用,但无法在网络上使用。缺少部分功能意味着某些类型的应用无法通过网络分发,或者不太实用。
我们将以开放而透明的方式设计和开发这些新功能。我们会利用现有的开放式网络平台标准流程,在对设计进行迭代的过程中获得开发者和其他浏览器供应商的反馈,以确保实现互操作性设计。
构建内容
在此 Codelab 中,您将了解一些全新的 Web API,或仅在标记后可用的 Web API。因此,此 Codelab 将重点介绍 API 本身以及这些 API 可解锁的用例,而不是构建特定的最终产品。
学习内容
此 Codelab 将向您介绍一些前沿 API 的基本机制。请注意,这些机制目前还不是完全成交,非常感谢您就开发者流程提供反馈意见。
您需要满足的条件
由于此 Codelab 中介绍的 API 真正处于前沿,因此每个 API 的要求各不相同。请务必仔细阅读每个部分开头的兼容性信息。
如何进行 Codelab
此 Codelab 不一定要依序完成。每个部分代表一个独立的 API,因此您可以按需挑选您最感兴趣的内容。
Badging API 旨在吸引用户关注后台发生的事件。为简单地在本 Codelab 中进行演示,我们使用 API 吸引用户关注前台发生的事件。然后,您可以做一些脑力的转移,因为工作需要在后台进行。
安装 Airhorner
为了让该 API 正常运行,您需要有一个安装到主屏幕上的 PWA,因此第一步是安装 PWA,例如闻名世界的 airhorner.com。点击右上角的安装按钮或使用三点状菜单手动安装。
系统会显示确认提示,请点击安装。
您的操作系统的基座中现在有一个新的图标。点击即可启动 PWA。它将拥有自己的应用窗口,并在独立模式下运行。
设置徽章
现在您已安装了 PWA,您需要有一些数字数据(徽章只能包含数字)才能显示在徽章上。在 Air Horner 中,有一个很简单的计数操作,那就是 hore 调用的次数。实际上,在安装的 Airhorner 应用上,尝试点击圆号并检查标志。每按一下喇叭就会加一。
那么,这是如何运作的呢?代码实质上是这样的:
let hornCounter = 0;
const horn = document.querySelector('.horn');
horn.addEventListener('click', () => {
navigator.setExperimentalAppBadge(++hornCounter);
});
让汽笛声发出几次并检查 PWA 的图标:它会每过一次就会更新该汽笛声。就是这么简单。
清除徽章
计数器会上调至 99,然后重新开始计数。您也可以手动重置。打开 DevTools 控制台标签,粘贴下面的代码行,然后按 Enter 键。
navigator.setExperimentalAppBadge(0);
或者,您也可以通过如以下代码段所示明确清除徽章,从而移除徽章。现在,PWA 的图标应该又开始重新显示,该图标清晰可辨,而且没有标记。
navigator.clearExperimentalAppBadge();
反馈
您觉得这个 API 怎么样?请抽出一点时间填写这份调查问卷,告诉我们您的看法:
此 API 是否直观易用?
您准备好运行示例了吗?
还有其他意见吗?是否缺少功能?请填写这份调查问卷,提供快速反馈。谢谢!
借助 Native File System API,开发者可以构建强大的 Web 应用,以便与用户本地设备上的文件进行交互。用户授予 Web 应用访问权限后,此 API 允许 Web 应用直接读取用户设备上的文件和文件夹内容,或者保存对这些内容的更改。
读取文件
Native File System API 的“Hello, world”是读取本地文件并获取文件内容。创建一个纯 .txt
文件并输入一些文本。接下来,导航到任何安全的网站(即,通过 HTTPS 访问的网站),如 example.com,然后打开 DevTools 控制台。将下面的代码段粘贴到控制台中。由于 Native File System API 需要用户手势,因此我们在文档中附加双击处理程序。我们稍后需要用到文件句柄,因此只需将其设为全局变量即可。
document.ondblclick = async () => {
window.handle = await window.chooseFileSystemEntries();
const file = await handle.getFile();
document.body.textContent = await file.text();
};
然后,当您双击 example.com 页面上的任意位置时,系统会显示文件选择器。
选择您之前创建的 .txt
文件。文件内容随后会取代 example.com 的实际 body
内容。
保存文件
接下来,我们需要进行一些更改。因此,请通过粘贴以下代码段来使 body
变为可修改状态。现在,您可以像浏览器一样编辑文本。
document.body.contentEditable = true;
现在,我们希望将这些更改写回原始文件。因此,我们需要在文件句柄上添加一个写入器,我们可以在控制台中粘贴以下代码段。同样,我们需要用户手势,所以这次我们将等待主文档被点击。
document.onclick = async () => {
const writer = await handle.createWriter();
await writer.truncate(0);
await writer.write(0, document.body.textContent);
await writer.close();
};
现在,当您点击(而不是双击)文档时,系统会显示权限提示。当您授予权限时,该文件的内容将是您以前在body
中编辑过的任何内容。请使用其他编辑器打开文件(或双击文档并重新打开文件),以启动所做更改。
恭喜!您刚刚创建了世界上最小的文本编辑器:[citation needed]
。
反馈
您觉得这个 API 怎么样?请抽出一点时间填写这份调查问卷,告诉我们您的看法:
此 API 是否直观易用?
您准备好运行示例了吗?
还有其他意见吗?是否缺少功能?请填写这份调查问卷,提供快速反馈。谢谢!
通过 Shape Detection API,您可以使用加速形状的检测器(例如人类人脸)并处理静态图片和/或实时图片 Feed。操作系统具有高性能且高度优化的功能检测器,如 Android FaceDetector。Shape Testing API 打开这些原生实现,并通过一组 JavaScript 接口公开它们。
目前,受支持的功能包括通过 FaceDetector
接口进行人脸检测、通过 BarcodeDetector
接口进行条形码检测,以及通过 TextDetector
接口进行文本检测(光学字符识别)。
人脸检测
形状检测 API 的一项出色功能是人脸检测。为了进行测试,我们需要一个包含人脸的页面。此页面以作者的形象为切入点。如以下屏幕截图所示。在受支持的浏览器中,会识别脸部和脸部标志的边界框。
通过混音或修改 Glitch 项目(尤其是 script.js 文件),您可以轻松实现这一点。
如果您希望完全动态化,而不只是使用作者的头像,那么请在非公开标签页或访客模式下转到该 Google 搜索结果页,其中包含丰富的头像。现在,在该页面上,右键点击任意位置并点击检查,打开 Chrome 开发者工具。接下来,在“控制台”标签页中,粘贴以下代码段。该代码会用半透明的红色方框突出显示检测到的人脸。
document.querySelectorAll('img[alt]:not([alt=""])').forEach(async (img) => {
try {
const faces = await new FaceDetector().detect(img);
faces.forEach(face => {
const div = document.createElement('div');
const box = face.boundingBox;
const computedStyle = getComputedStyle(img);
const [top, right, bottom, left] = [
computedStyle.marginTop,
computedStyle.marginRight,
computedStyle.marginBottom,
computedStyle.marginLeft
].map(m => parseInt(m, 10));
const scaleX = img.width / img.naturalWidth;
const scaleY = img.height / img.naturalHeight;
div.style.backgroundColor = 'rgba(255, 0, 0, 0.5)';
div.style.position = 'absolute';
div.style.top = `${scaleY * box.top + top}px`;
div.style.left = `${scaleX * box.left + left}px`;
div.style.width = `${scaleX * box.width}px`;
div.style.height = `${scaleY * box.height}px`;
img.before(div);
});
} catch(e) {
console.error(e);
}
});
您会注意到,有一些 DOMException
消息,并非所有图片都正在处理中。这是因为首屏图片内嵌为数据 URI,因此可以访问,而非首屏图片则来自未配置为支持 CORS 的其他网域。为了进行演示,我们无需担心这一点。
人脸地标检测
除了人脸本身之外,macOS 还支持检测人脸地标。如需测试对人脸地标的检测,请将以下代码段粘贴到控制台中。温馨提示:由于 crbug.com/914348 的影响,地标的阵容并不完美,但您可以查看它们的前进方向以及此功能的强大程度。
document.querySelectorAll('img[alt]:not([alt=""])').forEach(async (img) => {
try {
const faces = await new FaceDetector().detect(img);
faces.forEach(face => {
const div = document.createElement('div');
const box = face.boundingBox;
const computedStyle = getComputedStyle(img);
const [top, right, bottom, left] = [
computedStyle.marginTop,
computedStyle.marginRight,
computedStyle.marginBottom,
computedStyle.marginLeft
].map(m => parseInt(m, 10));
const scaleX = img.width / img.naturalWidth;
const scaleY = img.height / img.naturalHeight;
div.style.backgroundColor = 'rgba(255, 0, 0, 0.5)';
div.style.position = 'absolute';
div.style.top = `${scaleY * box.top + top}px`;
div.style.left = `${scaleX * box.left + left}px`;
div.style.width = `${scaleX * box.width}px`;
div.style.height = `${scaleY * box.height}px`;
img.before(div);
const landmarkSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
landmarkSVG.style.position = 'absolute';
landmarkSVG.classList.add('landmarks');
landmarkSVG.setAttribute('viewBox', `0 0 ${img.width} ${img.height}`);
landmarkSVG.style.width = `${img.width}px`;
landmarkSVG.style.height = `${img.height}px`;
face.landmarks.map((landmark) => {
landmarkSVG.innerHTML += `<polygon class="landmark-${landmark.type}" points="${
landmark.locations.map((point) => {
return `${scaleX * point.x},${scaleY * point.y} `;
}).join(' ')
}" /></svg>`;
});
div.before(landmarkSVG);
});
} catch(e) {
console.error(e);
}
});
条形码检测
Shape Detection API 的第二项功能是条形码检测。与以前一样,我们需要使用条形码网页,例如此代码。在浏览器中打开该二维码时,您会看到各种二维码被解密。重新编辑或编辑 Glitch 项目,尤其是 script.js 文件,以了解其实现方式。
如果您需要动态性更高的图片,我们可以再次使用 Google 图片搜索。这一次,请在浏览器中以私密模式或访客模式转到此 Google 搜索结果页。现在,请将下面的代码段粘贴到 Chrome DevTools 控制台标签页中。片刻之后,识别出的条形码将使用原始值和条形码类型进行注解。
document.querySelectorAll('img[alt]:not([alt=""])').forEach(async (img) => {
try {
const barcodes = await new BarcodeDetector().detect(img);
barcodes.forEach(barcode => {
const div = document.createElement('div');
const box = barcode.boundingBox;
const computedStyle = getComputedStyle(img);
const [top, right, bottom, left] = [
computedStyle.marginTop,
computedStyle.marginRight,
computedStyle.marginBottom,
computedStyle.marginLeft
].map(m => parseInt(m, 10));
const scaleX = img.width / img.naturalWidth;
const scaleY = img.height / img.naturalHeight;
div.style.backgroundColor = 'rgba(255, 255, 255, 0.75)';
div.style.position = 'absolute';
div.style.top = `${scaleY * box.top + top}px`;
div.style.left = `${scaleX * box.left - left}px`;
div.style.width = `${scaleX * box.width}px`;
div.style.height = `${scaleY * box.height}px`;
div.style.color = 'black';
div.style.fontSize = '14px';
div.textContent = `${barcode.rawValue}`;
img.before(div);
});
} catch(e) {
console.error(e);
}
});
文本检测
Shape Detection API 的最后一个功能是文本检测。您现在应该知道了:我们需要包含包含文字的图片的网页,例如包含 Google 图书扫描结果的此网页。在受支持的浏览器中,您会看到系统识别出的文本以及围绕文本段落绘制的边界框。重新编辑或编辑 Glitch 项目,尤其是 script.js 文件,以了解其实现方式。
若要动态进行测试,请在私密标签页或访客模式下转到此搜索结果页。现在,请将下面的代码段粘贴到 Chrome DevTools 控制台标签页中。稍等片刻,系统就会识别出其中的一些文本。
document.querySelectorAll('img[alt]:not([alt=""])').forEach(async (img) => {
try {
const texts = await new TextDetector().detect(img);
texts.forEach(text => {
const div = document.createElement('div');
const box = text.boundingBox;
const computedStyle = getComputedStyle(img);
const [top, right, bottom, left] = [
computedStyle.marginTop,
computedStyle.marginRight,
computedStyle.marginBottom,
computedStyle.marginLeft
].map(m => parseInt(m, 10));
const scaleX = img.width / img.naturalWidth;
const scaleY = img.height / img.naturalHeight;
div.style.backgroundColor = 'rgba(255, 255, 255, 0.75)';
div.style.position = 'absolute';
div.style.top = `${scaleY * box.top + top}px`;
div.style.left = `${scaleX * box.left - left}px`;
div.style.width = `${scaleX * box.width}px`;
div.style.height = `${scaleY * box.height}px`;
div.style.color = 'black';
div.style.fontSize = '14px';
div.innerHTML = text.rawValue;
img.before(div);
});
} catch(e) {
console.error(e);
}
});
反馈
您觉得这个 API 怎么样?请抽出一点时间填写这份调查问卷,告诉我们您的看法:
此 API 是否直观易用?
您准备好运行示例了吗?
还有其他意见吗?是否缺少功能?请填写这份调查问卷,提供快速反馈。谢谢!
Web Share Target API 可让已安装的 Web 应用向底层操作系统注册为共享目标,以从 Web Share API 或系统事件(例如操作系统级共享按钮)接收共享内容。
安装要共享给的 PWA
首先,您需要一个可与之分享的 PWA。这次(但很幸运)Airhorner 无法做到这一点,但 Web Share Target 演示应用是您的后盾。将应用安装到设备的主屏幕。
在 PWA 中分享内容
接下来,您需要分享一些内容,例如 Google 相册的照片。使用“共享”按钮,然后选择“剪贴簿 PWA”作为共享目标。
点按应用图标后,会直接转到 Scrapbook PWA,照片就在那里。
那么,这是如何运作的呢?如需了解详情,请浏览 Scrapbook PWA 的网络应用清单。让 Web Share Target API 正常运行的配置位于清单的 "share_target"
属性中,该属性在其 "action"
字段中指向一个使用 "params"
中列出的参数进行修饰的网址。
然后,共享端会相应地填充此网址模板(通过共享操作实现,或由开发者使用 Web Share API 以编程方式控制),然后接收方随后可以提取参数并对其执行操作(例如显示它们)。
{
"action": "/_share-target",
"enctype": "multipart/form-data",
"method": "POST",
"params": {
"files": [{
"name": "media",
"accept": ["audio/*", "image/*", "video/*"]
}]
}
}
反馈
您觉得这个 API 怎么样?请抽出一点时间填写这份调查问卷,告诉我们您的看法:
此 API 是否直观易用?
您准备好运行示例了吗?
还有其他意见吗?是否缺少功能?请填写这份调查问卷,提供快速反馈。谢谢!
为了避免大量消耗电池电量,大多数设备会在闲置时快速进入休眠状态。虽然大多数情况下这都没有问题,但某些应用需要让屏幕或设备保持唤醒状态才能完成工作。Wake Lock API 提供了一种防止设备变暗和锁定屏幕的方式,或者防止设备进入休眠状态。此功能可实现以前需要原生应用的新体验。
设置屏保
如需测试 Wake Lock API,您必须先确保自己的设备能够进入休眠状态。因此,请在操作系统的偏好设置窗格中启用您选择的屏保,并确保屏保在 1 分钟后启动。请确保设备在一段时间内保持静止不动(没错,我知道很痛苦)。以下屏幕截图显示的是 macOS,当然,您可以在 Android 移动设备或任何受支持的桌面平台上尝试此操作。
设置屏幕唤醒锁定
现在,您已经知道了屏保正常运行,所以您将使用 "screen"
类型的唤醒锁来防止屏保执行其任务。转到唤醒锁定演示应用,然后点击激活 screen
唤醒锁定复选框。
从这一刻起,唤醒锁定处于活动状态。如果您现在有足够的耐心,保持设备静止片刻,屏幕保护程序根本不会启动。
工作原理如需了解相关信息,请转到唤醒锁演示应用的 Glitch 项目并查看 script.js。以下代码段是其中的要点。打开新的标签页(或使用您刚打开的任何标签页),然后将以下代码粘贴到 Chrome 开发者工具控制台中。点击窗口时,您应该会看到一个唤醒锁,它大约 10 秒内处于活动状态(查看控制台日志),而您的屏保不应启动。
if ('wakeLock' in navigator && 'request' in navigator.wakeLock) {
let wakeLock = null;
const requestWakeLock = async () => {
try {
wakeLock = await navigator.wakeLock.request('screen');
wakeLock.addEventListener('release', () => {
console.log('Wake Lock was released');
});
console.log('Wake Lock is active');
} catch (e) {
console.error(`${e.name}, ${e.message}`);
}
};
requestWakeLock();
window.setTimeout(() => {
wakeLock.release();
}, 10 * 1000);
}
反馈
您觉得这个 API 怎么样?请抽出一点时间填写这份调查问卷,告诉我们您的看法:
此 API 是否直观易用?
您准备好运行示例了吗?
还有其他意见吗?是否缺少功能?请填写这份调查问卷,提供快速反馈。谢谢!
我们非常兴奋地推出 Contact Picker API。它允许 Web 应用通过设备的本机联系人管理器访问通讯录,因此您的 Web 应用可以访问您的联系人的姓名、电子邮件地址和电话号码。您可以指定是需要一位还是多位联系人,还是需要所有字段还是部分名称、电子邮件地址和电话号码。
隐私注意事项
选择器打开后,你可以选择要分享的联系人。您会注意到,并不存在“全选”选项;这是我们有意为之,我们希望用户在掌握充分信息后分享信息。同样,访问权限不是持续的,而是一次性的。
访问通讯录
访问联系人是一项简单任务。在选择器打开前,您可以指定所需的字段(选项为 name
、email
和 telephone
),以及是要访问多个联系人还是只访问一个联系人。您可以在 Android 设备上打开此演示应用以测试此 API。源代码的相关部分基本上是以下代码段:
getContactsButton.addEventListener('click', async () => {
const contacts = await navigator.contacts.select(
['name', 'email'],
{multiple: true});
if (!contacts.length) {
// No contacts were selected, or picker couldn't be opened.
return;
}
console.log(contacts);
});
复制和粘贴文本
在此之前,无法以编程方式将图片复制并粘贴到系统剪贴板。最近,我们为 Async Clipboard API 添加了图片支持,
以便您可以复制和粘贴图片新功能是您还可以将图片写入剪贴板。异步剪贴板 API 在一段时间内支持复制和粘贴文本。您可以通过调用 avigator.clipboard.writeText() 将文本复制到剪贴板,然后通过调用 avigator.clipboard.readText() 稍后粘贴该文本。
复制和粘贴图片
现在,您还可以将图片复制到剪贴板。为此,您需要将图片数据作为 blob,然后将其传递给剪贴板项构造函数。最后,您可以通过调用 avigator.clipboard.write() 复制此剪贴板内容。
// Copy: Writing image to the clipboard
try {
const imgURL = 'https://developers.google.com/web/updates/images/generic/file.png';
const data = await fetch(imgURL);
const blob = await data.blob();
await navigator.clipboard.write([
new ClipboardItem(Object.defineProperty({}, blob.type, {
value: blob,
enumerable: true
}))
]);
console.log('Image copied.');
} catch(e) {
console.error(e, e.message);
}
将图片粘贴回剪贴板看上去非常复杂,但实际上只需要从剪贴板项中获取 blob 即可。因为可能有多个模块,您需要循环访问这些标签,直到获得感兴趣的模块。出于安全考虑,目前只能为 PNG 图片,但未来可能会支持更多图片格式。
async function getClipboardContents() {
try {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
try {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
console.log(URL.createObjectURL(blob));
}
} catch (e) {
console.error(e, e.message);
}
}
} catch (e) {
console.error(e, e.message);
}
}
您可以在演示版应用中查看此 API 的实际运作情况,其源代码中的相关代码段已嵌入上方。无需许可即可将图片复制到剪贴板,但您需要授予从剪贴板粘贴图片的权限。
授予访问权限后,您可以从剪贴板读取图片并将其粘贴到应用中:
恭喜,您已完成了本 Codelab 的学习。再次提醒您,大多数 API 仍在不断变化和积极开发。因此,该团队衷心感谢您的反馈,因为只有与您这样的人员互动有助于我们正确获取这些 API。
我们还建议您经常查看我们的功能着陆页。我们会及时更新文档,并提供指向我们所开发 API 的所有深度文章的链接。继续摇滚吧!
Tom 和整个功能团队 🐡?