Chrome 开发 - 第二部分:应用程序






4.78/5 (5投票s)
本文介绍如何编写在 Chrome 浏览器中运行的应用。
1. 引言
上一篇文章讨论了 Chrome 扩展程序,而本文则侧重于 Chrome 应用的开发。这两者有很多共同之处,它们之间的区别乍一看可能显得很微妙。为了帮助理解,先来区分三个术语:
- 软件应用程序 —— 用于帮助用户执行某项活动的软件,例如处理文本、编辑图像或玩游戏。通常具有专用用户界面。
- Web 应用 —— 在浏览器中运行的软件应用程序(应用程序中的应用程序)。
- 浏览器扩展程序 —— 用于自定义浏览体验或增强浏览器功能的软件。很少有用户界面。
Chrome 应用(通常简称 应用)是在 Chrome 浏览器中运行的 Web 应用。对用户而言,它的外观和感觉与普通 Web 应用无异,但它可以访问普通应用程序无法触及的丰富功能。缺点是 Chrome 应用只能在 Chrome 中运行。
从开发者的角度来看,Chrome 应用和扩展程序之间的区别很明显。在扩展程序中,内容脚本提供对 Web 文档的访问,弹出窗口提供基本的用户界面。应用没有内容脚本或弹出窗口,但用户界面要强大得多——应用可以在独立于浏览器之外的窗口中运行。
除了用户界面,应用相对于扩展程序的另一个优势在于对用户系统的底层访问。Chrome 应用可以访问硬件功能,包括蓝牙、TCP/UDP 套接字和通用串行总线 (USB)。它们还可以读取和写入用户的文件系统。我个人最喜欢的功能是 tts(文本转语音),它允许应用生成多种不同语言的语音。
本文将介绍如何编写创建窗口、访问用户文件系统以及将文本转换为语音的应用。但在深入研究代码之前,理解 Chrome 应用的结构以及它在浏览器中启动的方式非常重要。这些主题将在下一节中讨论。
2. 应用开发基础
Chrome 应用的文件结构几乎与扩展程序相同。需要注意三个基本特征:
- 应用的功能和能力必须在名为 manifest.json 的文件中定义。
- 应用可以有后台脚本,但不能有内容脚本或弹出窗口。
- 与扩展程序一样,应用可以通过 Chrome 开发者仪表板进行管理,网址为 chrome://extensions。
本节将首先讨论 manifest.json 的格式,然后介绍安装和启动一个简单应用的流程。
2.1 manifest.json
应用的 manifest 接受许多与扩展程序 manifest 相同的属性。这些属性包括 manifest_version
、name
、description
、version
、icons
和 permissions
。主要区别在于应用的 manifest 必须有一个名为 app
的属性。该属性包含一个 background
属性,该属性将 scripts
字段与包含一个或多个后台脚本的数组关联起来。
如果下载了本文的示例存档,您会发现一个名为 basic_app 的文件夹。此应用的 manifest.json 易于理解:
{ "manifest_version": 2, "name": "Trivial app", "description": "This app doesn't do anything", "version": "1.0", "icons": { "16": "images/cog_sm.png", "48": "images/cog_med.png", "128": "images/cog_lg.png" }, "app": { "background": { "scripts": ["scripts/background.js"] } } }
这应该看起来很熟悉,因为大多数属性的名称和值与上一篇文章中介绍的扩展程序相同。请记住,scripts
数组必须至少命名一个后台脚本。本文的其余部分将讨论应用后台脚本可以访问的许多功能。
2.2 加载和启动应用
如果您打开 Chrome 并访问 chrome://apps,您会看到所有可执行的应用。但该页面不允许您安装新应用。要管理应用,您需要访问上一篇文章中讨论的 Chrome 开发者仪表板。网址是 chrome://extensions,如果勾选了 **开发者模式** 框,页面顶部将显示如图 1 所示的内容。
图 1:开发者模式下的 Chrome 开发者仪表板
左侧的 **加载已解压的扩展程序...** 按钮可以允许您选择一个文件夹并将应用加载到 Chrome 中。理解此过程的最佳方法是进行一次示例演示。
本文附带的 example_code.zip 存档包含一个名为 basic_app 的文件夹。要将此应用加载到 Chrome 中,请按照以下四个步骤操作:
- 下载 example_code.zip 并解压存档。
- 在 Chrome 中,通过导航到 chrome://extensions 打开 Chrome 开发者仪表板。
- 按 **加载已解压的扩展程序...** 按钮并选择 basic_app 文件夹。
- 按确定加载应用。
当扩展程序加载后,将在仪表板的扩展程序列表中添加一个条目。图 2 显示了它的样子。
图 2:Chrome 开发者仪表板中的新条目
注意到 **启动** 链接很重要。与扩展程序不同,应用在安装时不会开始执行。应用必须被显式启动。
**重新加载** 链接会将应用重新加载到 Chrome 中。底部 **后台页面** 链接会打开应用的后台页面。这在您想查看与后台脚本关联的控制台时很有用。
3. chrome.app.runtime 和 chrome.app.window
应用和扩展程序的主要区别在于,应用可以在自己的窗口中执行。要创建这些窗口,应用必须调用两个 API 的函数:chrome.app.runtime
和 chrome.app.window
。第一个 API 使应用能够响应其生命周期中的事件。第二个 API 提供了创建和配置窗口的函数。
3.1 chrome.app.runtime
chrome.app.runtime
API(不要与 chrome.runtime
API 混淆)定义了三个事件。表 1 列出了每个事件。
表 1:chrome.app.runtime 的事件
事件 | 触发器 |
---|---|
onLaunched |
当应用执行时触发 |
onRestarted |
当应用重启时触发 |
onEmbedRequested |
当另一个应用尝试嵌入该应用时触发 |
每个事件都有一个名为 addListener
的函数。它接受一个回调函数,在事件触发时调用。例如,以下代码定义了一个匿名函数,在应用启动时调用:
chrome.app.runtime.onLaunched.addListener(function(...) { ... });
事件回调函数接收的参数取决于事件类型。
3.2 chrome.app.window
要定义其用户界面,应用可以创建一个或多个窗口。在代码中,应用的窗口由 AppWindow
对象表示。chrome.app.window
API 的函数使创建和管理 AppWindow
成为可能,它们列在表 2 中。
表 2:chrome.app.window 的函数
函数 | 描述 |
---|---|
create(string url, CreateWindowOptions opts, function callback) |
创建一个新的 AppWindow |
current() |
返回当前 AppWindow |
get(string id) |
返回具有给定名称的 AppWindow |
getAll() |
返回包含所有 AppWindow 的数组 |
canSetVisibleOnAllWorkspace() |
标识平台是否支持在所有工作区上显示 窗口 |
create
是需要了解的主要函数。它唯一的必需参数是第一个,它标识定义窗口结构和外观的 HTML 文件。第三个参数是一个回调函数,该函数接收新创建的 AppWindow
。
create
的第二个参数是一个 CreateWindowOptions
对象。它有五个可选属性:
id
— 唯一标识窗口的字符串(与应用的 ID 无关)outerBounds
— 一个BoundsSpecification
,用于设置窗口的位置和大小innerBounds
— 一个BoundsSpecification
,用于设置窗口内容的位置和大小frame
— 框架类型:none
或chrome
(默认为chrome
)state
— 窗口的初始状态:normal
、fullscreen
、maximized
或minimized
。
第二个和第三个属性是 BoundsSpecification
。BoundsSpecification
有八个属性用于定义位置和大小:left
、top
、width
、height
、minWidth
、minHeight
、maxWidth
和 maxHeight
。例如,以下代码创建一个 200x200 的 AppWindow
,该窗口的最小尺寸为 100x100 像素,最大尺寸为 300x300 像素:
chrome.app.window.create("window.html", { "outerBounds": {"width": 200, "height": 200, "minWidth": 100, "minHeight": 100, "maxWidth": 300, "maxHeight": 300}}, function(win) { ... } );
如代码所示,create
的第三个参数是一个回调函数,它在 AppWindow
创建后接收它。表 3 列出了 AppWindow
对象的一些属性。
表 3:AppWindow 属性
属性 | 描述 |
---|---|
id |
窗口的 ID,如果可用 |
outerBounds |
窗口的边界 |
innerBounds |
窗口内部内容的边界 |
contentWindow |
相应的 JavaScript window 对象 |
fullscreen() |
将窗口调整为充满屏幕 |
isFullscreen() |
标识窗口是否占据屏幕 |
minimize() |
最小化窗口大小 |
isMinimized() |
标识窗口是否已最小化 |
maximize() |
最大化窗口大小 |
restore() |
将窗口恢复到其原始大小/位置 |
drawAttention() |
引起窗口注意 |
clearAttention() |
清除窗口的注意 |
close() |
关闭窗口 |
show() |
显示窗口 |
hide() |
隐藏窗口 |
setAlwaysOnTop (boolean onTop) |
配置窗口是否应始终 显示在最上方 |
isAlwaysOnTop() |
标识窗口是否始终显示在最上方 |
setInterceptAllKeys (boolean intercept) |
配置窗口是否应接收 所有按键事件 |
setVisibleOnAllWorkspaces (boolean visible) |
配置窗口是否应显示在 所有工作区 |
这些属性易于使用和理解。contentWindow
属性很有趣,因为它提供了对底层 JavaScript
Window
的访问。这允许后台脚本访问常见的 JavaScript Window
属性,例如 document
、setTimeout()
和 alert()
。
除了提供表 3 中的函数外,AppWindow
还提供事件,使脚本能够响应窗口的事件。表 4 列出了这些事件以及触发它们的事件。
表 4:AppWindow 事件
事件 | 触发器 |
---|---|
onBoundsChanged |
窗口边界更改时触发 |
onClosed |
窗口关闭时触发 |
onFullscreened |
窗口设置为占据屏幕时触发 |
onMaximized |
窗口最大化时触发 |
onMinimized |
窗口最小化时触发 |
onRestored |
窗口恢复到其原始边界时触发 |
每个窗口事件都有一个名为 addListener
的属性,它接受一个回调函数,在事件发生时调用。在所有情况下,此回调函数都不会接收任何参数。例如,当窗口移动或调整大小时,以下代码会将消息打印到控制台:
chrome.app.window.create("window.html", {...}, function(win) { win.onBoundsChanged.addListener(function() { console.log("Bounds changed"); }); } );
在此示例中,窗口的内容由 window.html 确定。此 HTML 文档可以包含一个或多个 JavaScript 文件,称为*窗口脚本*。窗口脚本可以访问与后台脚本相同的能力,下一节将介绍一个访问用户文件系统的窗口脚本。
4. 文件系统接口
大多数 Web 应用无法与用户的文件或系统硬件交互。但 Chrome 应用可以通过 chrome.fileSystem
API 访问客户端的文件系统。此功能强大但复杂。因此,我将讨论分为四个部分:
- 获取权限
- chooseEntry 函数
- File API
- chrome.fileSystem API
本节的最后一部分将介绍一个示例应用,该应用将文件内容翻倍。也就是说,它从文件中读取文本并将其写入文件末尾。
4.1 获取权限
要访问用户的文件系统,应用必须通过向 manifest 的 permissions
数组添加一个或多个值来请求权限:
permissions: ["fileSystem"]
— 请求只读权限permissions: [{"fileSystem": ["write"]}]
— 请求读/写权限permissions: [{"fileSystem": ["write", "retainEntries", "directory"]}]
— 请求读取、写入、保留文件以及访问目录(除文件外)的权限
如果授予了权限,脚本就可以访问用户的文件。如果未授予,尝试访问用户文件系统将导致错误。
4.2 chooseEntry 函数
在 chrome.fileSystem
API 中,chooseEntry
函数会打开一个对话框,让用户选择现有文件/目录或识别新文件/目录。其签名如下:
chooseEntry(Object opts, Function callback)
第一个参数是一个对象,用于配置对话框的外观和行为。它有五个可选属性:
type
— 文件对话框类型(openFile
、openWritableFile
、saveFile
或openDirectory
)suggestedName
— 要打开文件的建议名称accepts
— 一个对象数组,用于过滤可选择的文件。每个对象有三个可选属性:description
、mimeTypes
和extensions
acceptsAllTypes
— 对话框是否接受所有类型的文件acceptsMultiple
— 对话框是否接受多选
chooseEntry
的第二个参数是一个回调函数,该函数接收用户选择的结果。选择结果以 Entry
或 FileEntry
对象数组的形式提供。
一个例子可以阐明 chooseEntry
的工作原理。以下代码在窗口脚本中执行,当用户单击 ID 为 browse
的按钮时,会显示一个文件选择对话框。
document.getElementById("browse").onclick = function() { chrome.fileSystem.chooseEntry( { type: "openFile", accepts: [ { description: "Data files (*.dat)", extensions: ["dat"]} ] }, function(entry) { console.log("Entry name: " + entry.name); }); }
对话框的外观和初始搜索目录取决于用户的操作系统。图 3 显示了在我的 Windows 7 机器上生成的对话框外观:
图 3:由 chooseEntry 创建的文件选择对话框
如果设置了 acceptsAllTypes
为 true
,对话框将允许用户选择任何文件,无论其扩展名是什么。如果设置了 acceptsMultiple
为 true
,对话框将允许用户选择多个文件。但由于未设置这两个属性,用户只能打开一个 *.dat 文件。通过将 extensions
字段设置为 ["dat"]
来配置必需的后缀。
当用户选择文件时,示例回调函数会接收一个相应的 Entry
并使用 name
属性获取文件的名称。要使用这些 Entry
对象,您需要熟悉 Google 的 File API。
4.3 File API
在 HTML5 开发过程中,Google 提出了一个 File API,它允许 Web 应用程序访问用户的文件。您可以在此处阅读规范。File API 未包含在 HTML5 中,但 chrome.fileSystem
API 依赖它来与客户端的文件系统进行交互。本讨论将介绍 File API 的五个对象:Entry
、FileEntry
、File
、FileReader
和 FileWriter
。
根据 File API,文件由 FileEntry
对象表示,目录由 DirectoryEntry
对象表示。它们都继承自 Entry
类型,其属性列在表 5 中。
表 5:Entry 属性
函数 | 描述 |
---|---|
名称 |
条目的名称 |
fullPath |
条目的完整路径 |
filesystem |
包含该条目的文件系统 |
isFile |
标识该条目是否为文件 |
isDirectory |
标识该条目是否为目录 |
toURL(String mimeType) |
返回条目的 URL |
getMetadata (Function successCallback, Function errorCallback) |
提供条目的最后修改日期 |
getParent (Function successCallback, Function errorCallback) |
提供条目的父目录 |
移除 (Function successCallback, Function errorCallback) |
从文件系统中删除该条目 |
moveTo(DirectoryEntry parent, String newName, Function successCallback, Function errorCallback) |
将条目移动到指定目录 |
copyTo(DirectoryEntry parent, String newName, Function successCallback, Function errorCallback) |
将条目复制到指定目录 |
其中许多函数接受两个回调函数:一个在操作成功完成时调用,另一个在发生错误时调用。以下代码演示了其工作原理。当用户在对话框中选择条目时,remove
函数会将其从文件系统中删除并向日志打印一条消息。如果发生错误,应用将记录一条错误消息。
chrome.fileSystem.chooseEntry( { type: "openFile", accepts: [ { description: "Text files (*.text)", extensions: ["txt"]} ] }, function(entry) { entry.remove( function() {console.log("Deletion successful")}, function() {console.log("Error occurred")} ); });
FileEntry
表示用户文件系统中的一个文件,它具有表 5 中未列出的两个函数:
file(Function successCallback, Function errorCallback)
— 提供条目底层的File
对象createWriter(Function successCallback, Function errorCallback)
— 提供一个能够写入文件的FileWriter
通过访问 FileEntry
的 File
,应用可以使用 FileReader
读取文件内容。同样,FileWriter
允许将数据写入文件。以下小节将讨论这两种功能。
4.3.1 从文件中读取数据
Google 的 File API 定义了一个 FileReader
对象,它能够读取 File
中的数据。通常,使用此对象需要四个步骤:
- 使用其构造函数创建一个新的
FileReader
:var reader = new FileReader();
- 调用
FileReader
的三个读取函数之一。 - 为
FileReader
完成读取数据时响应的函数赋值。 - 在函数内部,通过
FileReader
的result
属性访问数据。
对于第二个步骤,FileReader
对象有三个读取数据的函数:
readAsArrayBuffer(File f)
— 以ArrayBuffer
的形式返回文件内容(用于二进制数据)readAsText(File f, String encoding)
— 以字符串形式返回文件内容readAsDataURL(File f)
— 以 Base64 编码的字符串形式返回文件内容
FileReader
具有许多与事件相关的属性,onload
属性用于标识在读取器完成从文件加载数据时调用的函数。以下代码演示了如何使用它:
// Create the new FileReader var reader = new FileReader(); // Assign a function to be called when the read is complete reader.onload = function() { console.log("Result: " + reader.result); } // Call the read function when the File is available entry.file(function(f) { reader.readAsText(f); }
准确地说,FileReader
的读取函数操作的是 Blob
,而 File
是 Blob
的一种。以下讨论将更详细地解释 Blob
。
4.3.2 向文件写入数据
FileEntry
对象的 createWriter
函数提供了一个 FileWriter
,它能够将数据写入底层文件。它比 FileReader
更易于使用,表 6 列出了它的属性。
表 6:FileWriter 属性
函数 | 描述 |
---|---|
length |
文件的字节长度 |
位置 |
文件中的当前写入位置 |
readyState |
写入器的状态(INIT 、WRITING 或 DONE ) |
error |
错误条件 |
write(Blob data) |
将数据写入文件 |
seek(long long offset) |
将写入位置移动到指定位置 |
truncate(unsigned long long size) |
将文件长度更改为指定大小 |
abort() |
终止写入操作 |
write
函数接受一个 Blob
。根据文档,Blob
是“一个类似文件的、不可变的原始数据对象”。关于 Blob
需要知道的重要一点是,Blob
构造函数接受一个字符串、Blob
、ArrayBuffer
、ArrayBufferView
数组,或这些对象的任何组合。例如,以下代码将一个字符串写入与 FileWriter
关联的文件:
writer.write(new Blob(["Example text"]);
与 FileReader
类似,FileWriter
提供可以分配给函数的事件。如果一个函数被设置为等于写入器的 onwriteend
事件,则在写入操作完成后将调用该函数。如果一个函数被设置为等于写入器的 onerror
事件,则在发生错误时将调用该函数。如果 entry
是一个 FileEntry
,则以下代码演示了如何创建 FileWriter
并将 Blob
写入相应的文件:
// Write the received data to the file entry.createWriter(function(writer) { // Called when the write operation is complete writer.onwriteend = function() { console.log("Write finished."); }; // Called if an error occurs writer.onerror = function(error) { console.log("Write error: " + error.toString()); }; // Create a new Blob and write its text to the file writer.write(new Blob(["Example text"])); });
默认情况下,文本将写入文件开头。要更改文本的写入位置,应用应调用 FileWriter
的 seek
函数并提供所需的偏移量。下一个示例应用演示了如何实现这一点。
4.4 chrome.fileSystem API
除了前面讨论过的 chooseEntry
函数外,chrome.fileSystem
API 还提供了许多其他函数。表 7 列出了 chooseEntry
和其他六个函数。
表 7:chrome.fileSystem 的函数(节选)
函数 | 描述 |
---|---|
chooseEntry(Options opts, Function callback) |
创建文件选择对话框 |
getDisplayPath(Entry entry, Function callback) |
为给定的条目提供完整路径 |
getWritableEntry(Entry entry, Function callback) |
为给定的条目提供一个可写入的条目 |
isWritableEntry(Entry entry, Function callback) |
标识应用是否有权限 写入该条目 |
retainEntry(Entry entry) |
返回条目的字符串标识符 |
restoreEntry(String id, Function callback) |
根据其标识符访问条目 |
isRestorable(String id, Function callback) |
标识应用是否有权限 根据其标识符恢复条目 |
在大多数这些函数中,第二个参数是在操作完成时调用的回调函数。例如,getWritableEntry
的第二个参数是一个回调函数,如果应用有权写入该条目,它将提供该 Entry
。
如果应用需要操作多个 Entry
对象,它可以为每个对象分配一个标识符。retainEntry
返回一个 Entry
的标识符,然后可以使用 restoreEntry
根据标识符访问 Entry
对象。
4.5 示例应用程序
在示例存档中,file_demo 应用中的代码展示了如何读取和写入文件。它包含一个后台脚本 background.js,该脚本创建一个 200x200 的窗口作为应用的 UI。其代码如下:
// Responds when the app is launched chrome.app.runtime.onLaunched.addListener(function() { // Create the window chrome.app.window.create( "window.html", { "outerBounds": {"width": 200, "height": 200} }); });
窗口的外观由 window.html 文件定义,其标记如下:
<html> <body> <button id="browse">Select File</button> <script src="scripts/window.js"></script> </body> </html>
这会创建一个按钮并将 JavaScript 代码注入到 window.js 脚本中。当单击按钮时,此代码会调用 chooseEntry
以允许用户选择一个文本文件。脚本代码如下:
document.getElementById("browse").onclick = function() { // Open a dialog box chrome.fileSystem.chooseEntry( { type: "openFile", accepts: [ { description: "Text files (*.txt)", extensions: ["txt"]} ] }, function(entry) { // Create a FileReader var reader = new FileReader(); // Called when the read is complete reader.onload = function() { // Create a FileWriter entry.createWriter(function(writer) { // Write to the end of the file writer.seek(writer.length); // Log a message when the write operation is completed writer.onwriteend = function() { console.log("Write successful"); }; // Log a message if an error occurs writer.onerror = function(error) { console.log("Write error: " + error.toString()); }; // Create a Blob and write its text to the file writer.write(new Blob([reader.result])); }); } // Call the read function when the File is available entry.file(function(f) { reader.readAsText(f); }); }); }
用户选择文件后,应用会创建一个 FileReader
并将其 onload
属性与一个匿名函数关联起来。当读取文件文本时,此函数会创建一个 FileWriter
并调用其 seek
函数跳到文件末尾。脚本将文件文本写入文件末尾,如果操作成功完成,则会在控制台打印一条消息。
5. 文本转语音
从 Chrome 浏览器 14 版本开始,它就包含了一个文本转语音引擎。如果应用 manifest 的 permissions
数组包含 "tts"
,则应用可以使用 chrome.tts
API 访问语音引擎。表 8 列出了该 API 的函数并提供了每个函数的描述。
表 8:chrome.tts 的函数
函数 | 描述 |
---|---|
speak(String utterance, Object options, Function callback) |
生成并发出给定文本的语音 |
getVoices(Function callback) |
返回可用语音的集合 |
stop( ) |
停止正在进行的语音 |
pause( ) |
暂停正在进行的语音 |
resume() |
暂停后恢复朗读 |
isSpeaking(Function callback) |
标识引擎当前是否正在说话 |
顾名思义,speak
函数从文本生成语音并发出语音。唯一的必需参数是第一个,它标识要发出的文本。以下代码发出浏览器的名称:
chrome.tts.speak("Chrome");
第三个参数标识在语音完成之前调用的函数。speak
的第二个参数是一个对象,用于配置语音的生成方式。其所有属性都是可选的:
voiceName
— 要使用的语音名称lang
— 要使用的语言gender
— 所需性别(male
或female
)rate
— 相对于默认语速的语速(2 - 两倍速,0.5 - 半速)pitch
— 相对于默认音高的音高(2 - 更高音高,0 - 更低音高)volume
— 说话音量(0 到 1 之间)enqueue
— 如果为 true,则将语音添加到当前语音的队列中;如果为 false(默认),则中断当前语音extensionId
— 包含所需语音引擎的扩展程序 IDrequiredEventTypes
— 必须支持的事件类型desiredEventTypes
— 感兴趣的事件类型onEvent
— 在期望的事件上调用的函数
例如,以下代码以快速的英式男声说话:
chrome.tts.speak("It's just a flesh wound", {voiceName: "Google UK English Male", rate: 1.5});
getVoices
提供一个包含所有可生成语音的数组。每个语音都由一个 TtsVoice
对象表示,以下小节将对此进行详细讨论。
5.1 TtsVoice
Chrome 应用可以使用多种不同的语音生成语音。每种语音都由一个 TtsVoice
表示,表 9 列出了其不同的属性。
表 9:TtsVoice 属性
函数 | 描述 |
---|---|
voiceName |
语音的名称 |
lang |
语音的语言 |
gender |
语音的性别:男性或女性 |
remote |
该语音是否通过网络提供 |
extensionId |
提供此语音的扩展程序的 ID |
eventTypes |
语音可能触发的事件 |
例如,以下代码使用 getVoices
访问 Chrome 的预装语音并显示其属性:
chrome.tts.getVoices(function(voices) { for (var i = 0; i < voices.length; i++) { console.log("Name: " + voices[i].voiceName); console.log("Language: " + voices[i].lang); console.log("Gender: " + voices[i].gender); console.log("Extension: " + voices[i].extensionId); console.log("Events: " + voices[i].eventTypes); } });
当这段代码在 Chrome 51 中执行时,数组包含二十种语音。表 10 列出了十二种语音及其性别、语言和支持的事件。
表 10:内置语音
语音名称 | 性别/语言 | 事件 |
---|---|---|
Google 美国英语 |
female /en-US |
start , end , interrupted , cancelled , error |
Google 英国英语男声 |
male /en-GB |
start , end , interrupted , cancelled , error |
Google 英国英语女声 |
female /en-GB |
start , end , interrupted , cancelled , error |
Google 西班牙语 |
female /es-ES |
start , end , interrupted , cancelled , error |
Google 美国西班牙语 |
female /en-US |
start , end , interrupted , cancelled , error |
Google 法语 |
female /fr-FR |
start , end , interrupted , cancelled , error |
Google 德语 |
female /de-DE |
start , end , interrupted , cancelled , error |
Google 意大利语 |
female /it-IT |
start , end , interrupted , cancelled , error |
Google 印尼语 |
female /id-ID |
start , end , interrupted , cancelled , error |
Google 荷兰语 |
female /nl-NL |
start , end , interrupted , cancelled , error |
Google 波兰语 |
female /pl-PL |
start , end , interrupted , cancelled , error |
Google 巴西葡萄牙语 |
female /pt-BR |
start , end , interrupted , cancelled , error |
当应用选择一种语音进行文本转语音生成时,该语音决定了应用可以响应哪些语音事件。事件处理是通过在 speak
第二个参数中设置 desiredEventTypes
属性并通过将函数分配给 onEvent
属性来配置的。
5.2 示例代码
在本篇文章的示例代码中,tts_demo 展示了 Chrome 应用如何将文本转换为语音。窗口提供了用于设置发音内容和选择语音的控件。图 4 显示了该窗口的外观。
图 4:tts_demo 应用窗口
当按下 **说话** 按钮时,将调用 speak
函数,并将文本框中的文本作为参数。语音的名称由组合框的选择决定。项目 scripts/window.js 中的代码显示了如何实现这一点:
var voiceselect = document.getElementById("voiceselect"); // Access available voices chrome.tts.getVoices(function(voices) { // Add voice options for (var i = 0; i < voices.length; i++) { voiceselect.options[i] = new Option(voices[i].voiceName, i); } voiceselect.selectedIndex = 2; }); // Stop the speech document.getElementById("stop").onclick = function() { // Stop if speaking chrome.tts.isSpeaking(function(speaking) { if (speaking) { chrome.tts.stop(); } }); } // Speak in the desired language document.getElementById("speak").onclick = function() { var text = document.getElementById("utterance").value; var voice = voiceselect.options[voiceselect.selectedIndex].text; chrome.tts.speak(text, {voiceName: voice}); }
这演示了如何使用 isSpeaking
和 stop
函数。如果用户单击停止图像,应用将调用 isSpeaking
以确保引擎当前正在生成语音。如果回调函数提供的值为 true,则应用将调用 stop
函数。这不仅会停止当前的语音,还会清除队列中任何待定的发音内容。
历史
2016 年 6 月 17 日 - 首次提交文章