编辑器插件授权

在大多数情况下,您必须先授权插件,然后才能使用。对于许多 Web 应用项目(例如 Web 应用),授权都很简单:当您尝试使用项目时,脚本项目会请求它需要的所有缺少的权限。获得授权后,您可以自由使用脚本项目。使用该脚本项目的每个人都会单独进行授权。

编辑器插件的授权模型更为复杂。由于这些插件适用于 Google 云端硬盘中的文件(可以与他人共享的文件),因此在构建编辑器插件时必须考虑不同的授权模式。Google Workspace 编辑器应用也会在他们的界面中提供一个插件菜单,即使您尚未授权这些插件,这些菜单也会填充这些插件。这会给授权模型增加额外的复杂性。

授权模式

编辑器插件的两个属性使其特别易于共享和使用:

  • 从商店获取编辑器插件后,您可以在打开或创建的每个文档对应的插件菜单中看到该插件。这些文档的协作者不会看到该插件,除非您在实际使用该插件。
  • 在文档中使用编辑器插件后,您的协作者也会在“插件”菜单中看到该插件,但仅会在该文档中看到该插件(除非他们也安装了该插件)。

这种分享模式对于大多数用户来说都很自然。不过,由于编辑器插件会在文档打开时自动运行其 onOpen(e) 函数来添加菜单项,因此上述行为会增加 Apps 脚本的授权规则的复杂性。毕竟,用户不愿意在每次打开文档时都使用插件访问个人数据。本指南可帮助您了解代码的功能和时机。

已安装与已启用

如果您在菜单中看到编辑器插件,它处于两种状态之一(或两种):已安装和已启用。在特定商店用户选择插件并授权其访问其 Google 数据后,系统会为特定用户安装编辑器插件。相反,如果给定文档中的插件使用某个插件,则系统会在该插件中启用该插件。如果两个人同时协作处理某个文档,并且其中一位用户使用某个插件,则系统会为一位用户安装该插件,并为文档启用该插件。

下表总结了这两种状态。请注意,在将脚本作为插件进行测试时,您可以选择在这两种状态下之一或同时在这两种状态下运行测试。

已安装 已启用
适用对象 用户 文档
原因 从商店获取插件 使用文档时在商店中获取插件,或
使用文档中之前安装的插件
菜单公开范围 在用户打开或创建的所有文档中仅限该用户 该文档上的所有协作者
onOpen(e) AuthMode.NONE(除非也已启用,在此情况下为 AuthMode.LIMITED) AuthMode.LIMITED

授权模式

编辑器插件会在文档打开时自动运行其 onOpen(e) 函数来添加菜单项,但为了保护用户的数据,Apps 脚本会限制 onOpen(e) 函数的功能。如果插件未在当前文档中使用,这些限制便会更加严格。

具体而言,已安装和已启用的状态决定了 onOpen(e) 函数在哪种授权模式下运行。Apps 脚本将授权模式作为 Apps 脚本事件参数 eauthMode 属性传递;e.authMode 的值对应于 Apps 脚本 ScriptApp.AuthMode 枚举中的一个常量。

如果当前文档中启用了编辑器插件,onOpen(e) 将在 AuthMode.LIMITED 中运行。如果未启用该插件,但只安装了该插件,则 onOpen(e)AuthMode.NONE 中运行。

授权模式的概念适用于所有 Apps 脚本执行,例如从脚本编辑器、菜单项或 Apps 脚本 google.script.run 调用运行,不过只有当脚本因为触发器(如 onOpen(e)onEdit(e)onInstall(e))而运行时,才能检查 e.authMode 属性。Google 表格中的自定义函数使用自己的授权模式 AuthMode.CUSTOM_FUNCTION,它与 LIMITED 类似,但限制略有不同。其余时间的脚本将在 AuthMode.FULL 中运行,如下表所述。

NONE LIMITED CUSTOM_FUNCTION FULL
发生时间: onOpen(e)(如果用户安装了插件,但未在文档中启用该插件) onOpen(e)(所有其他时间)
onEdit(e)(仅适用于 Google 表格)
自定义函数 所有其他时间,包括:
可安装的触发器
onInstall(e)
google.script.run
访问用户数据 仅限语言区域 仅限语言区域 仅限语言区域
文档访问权限 是 - 只读
访问界面 添加菜单项 添加菜单项
Properties 的访问权限
对“Jdbc”和“UrlFetch”的访问权限
其他服务 Logger
Utilities
任何不访问用户数据的服务 任何不访问用户数据的服务 所有服务

完整的生命周期

如果已为当前用户安装某个插件,或在当前文档中启用了该插件,则该插件会在文档中加载,这会使该插件显示在插件菜单中,并开始监听简单触发器 onInstall(e)onOpen(e)onEdit(e)。如果用户点击某个插件的菜单项,它就会运行

正在安装

从应用店中安装编辑器插件后,其 onInstall(e) 函数会在 AuthMode.FULL 中运行。这使得插件能够运行复杂的设置例程,但也务必使用 onInstall(e) 创建菜单项,因为文档已经打开,因此 onOpen(e) 函数尚未运行。为方便起见,您只需从 onInstall(e) 调用 onOpen(e),如以下示例所示:

function onInstall(e) {
  onOpen(e);
  // Perform additional setup as needed.
}

开场白

打开文档后,它会加载当前用户已安装或任何协作者在文档中启用了的每个编辑器插件,并调用其每个 onOpen(e) 函数。onOpen(e) 运行的授权模式取决于插件是否已安装或启用

如果插件仅创建了基本菜单,那么模式就无关紧要。以下示例展示了一个简单的 onOpen(e) 可能如下所示:

function onOpen(e) {
  SpreadsheetApp.getUi().createAddonMenu() // Or DocumentApp.
      .addItem('Insert chart', 'insertChart')
      .addItem('Update charts', 'updateCharts')
      .addToUi();
}

但是,如果您要根据存储的 Apps 脚本属性添加动态菜单项、读取当前文档的内容或执行其他高级任务,则需要检测授权模式并进行适当处理。以下示例展示了高级 onOpen(e) 函数可能是什么样子的,它根据授权模式更改了其行为:

function onOpen(e) {
  var menu = SpreadsheetApp.getUi().createAddonMenu(); // Or DocumentApp.
  if (e && e.authMode == ScriptApp.AuthMode.NONE) {
    // Add a normal menu item (works in all authorization modes).
    menu.addItem('Start workflow', 'startWorkflow');
  } else {
    // Add a menu item based on properties (doesn't work in AuthMode.NONE).
    var properties = PropertiesService.getDocumentProperties();
    var workflowStarted = properties.getProperty('workflowStarted');
    if (workflowStarted) {
      menu.addItem('Check workflow status', 'checkWorkflow');
    } else {
      menu.addItem('Start workflow', 'startWorkflow');
    }
  }
  menu.addToUi();
}

正在运行

当用户点击某个插件菜单项时,Apps 脚本会先检查用户是否已安装该插件,并在没有安装时提示他们进行安装。如果用户授权了插件,脚本会运行与 AuthMode.FULL 中的菜单项相对应的函数。在文档中,该插件也会启用(如果尚未启用)。