D28 - 如何打包 Apps Script 的程序码?(一) 变成扩充功能似的 UI 按键

今天的目标

要怎麽将我们的 GAS 成果打包成别人可以使用的版本?我们已经学了快一个月的 GAS 使用方式,但并不是每个人都熟悉 GAS 的进入与使用。我们要怎麽样让其他人也便於上手运用我们 GAS 的成果?这就是今天的主题。

我会介绍其中最主要的两种方式——

  1. 包成扩充功能(Add-On)似的 UI 选项
  2. 包成能用於连接的 API / HTML page

那这两题分别是这两天的主题。那我们今天会主要介绍这个第一个主题背後的「关键问题」——

  1. 怎麽将我的 GAS 成果包装成像是扩充功能那样的 UI 介面,给他人使用?

那我们就开始吧!

Q1. 怎麽将我的 GAS 成果包装成像是扩充功能那样的 UI 介面,给他人使用?

首先先帮大家厘清,我们今天讲的 Add-On 其实翻译上是「外挂功能」,是可以在 Google Workspace Marketplace 上取得的。但因为「外挂」比较不一定好理解,我在上方用「扩充功能」主要是为了初期阅读时的理解方便。实际上的「扩充功能」对应的英文是 Extension,是我们可以挂载在 Chrome 上的像是 OneTab 等,可以在 Google Extensions 取得。

以下实作部分,为了用语上让大家搞混,接下来都会用 Add-On 来说明我们的主题。

Input

  • Google Workspace 系列产品
    • 举凡 Google Docs / Google Sheet / Google Form / Google Slides .... 都算是!
  • 已经完成的 GAS 程序码

那我们今天用的案例是 Google Sheet,会将 D26 的「造表单」 和 D27 的「拿分数」成果转乘 Google Apps Script。

Output

  • 换一个帐号,也能在同一个页面开启的 Add-On。

也分享下,目前做的仅仅是「绑定表单」。如果要上架 Google Workspace Marketplace,那会有另外的 流程 要申请。

Step 1 从 Google Sheet 进入 GAS

今天我们用 Google Sheet 作为连结 GAS 的管道,让我们借用 D14 的影片。

一样第一次按下 GAS 中的「执行」会有「存取验证」需要大家按一下。这边仍是借用一下 D2 的影片。

接着,我们要进入 GAS 中设定 UI 画面。

Step 2 透过 getUi() 来设定

在 Google Workspace 系列产品中,我们主要都是透过 getUi() 来取得可以调整的 UI,再进行调整。使用方式如下主要是透过像 let ui = SpreadsheetApp.getUi(); 来取得可以调整的项目。好,接着我们看完整可以用的程序码——

function greeting_toast_hello(){
  SpreadsheetApp.getActiveSpreadsheet().toast("Hello!")
}

function greeting_toast_hi(){
  SpreadsheetApp.getActiveSpreadsheet().toast("Hi!")
}

function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('客制化工具列')
      .addSubMenu(ui.createMenu('打招呼')
          .addItem('Say Hi', 'greeting_toast'))
      .addToUi();
}

跑起来长这样——

那接下来一步步说明。以下两个是为了方便展示,我先弄的一份比较好观察的程序码。

SpreadsheetApp.getActiveSpreadsheet().toast("Hi!");

跑起来长这样——

接着用 onOpen() 这个 Opening Trigger 来设定,换句话说是设定完後会在每次开启 Google Sheet 时同时帮你自动执行的。所以当然也可以不用设定 UI,也可以是每次有人打开表单就把里面资料清乾净,只要改其中的程序码即可。

但,如果你发现自己的 onOpen() 程序码改了,但结果还没有更新,比较简单的方式是重新整理你的 Google Sheet。要注意的是, onOpen() 是不用也不能执行的,它会显示错误给你如下面影片——

UI 主要有几种主要的案件—— addItem()PromptAlert(prompt)shoeModeless


ui.addItem() 设定基本按键

最基本的按键是透过 addItem() 来达成

function onOpen() {
  let ui = SpreadsheetApp.getUi();
  ui.createMenu('客制化工具列')
      .addItem('Say Hi', 'greeting_toast_hi')
      .addSubMenu(ui.createMenu('打招呼')
          .addItem('Say Hello', 'greeting_toast_hello')
          )
      .addToUi();
}

这段跑起来就是我们上面说明的——

onOpen() 里面的程序逻辑是这样,首先用 getUi() 抓出 ui 後——

  1. createMenu()先设定一个 Menu 叫做「客制化工具列」(可以改自己想要的名字)
  2. 再来跟它说,我要设定一个按键(addItem()),这个按键显示叫「Say Hi」要能帮我执行名叫 greeting_toast_hi 的程序码
  3. 再跟它说,我要一个有按键跑出子目录(addSubMenu()),说我要一个显示「Say Hello」的按键,帮我执行greeting_toast_helloi() 的程序码

这边就是基础的部分。接着我们来讲解其它用法。


ui.alert 设定提醒视窗

先来个我们常用的「提醒视窗」,这边都先上程序码——

function onOpen() {
  let ui = SpreadsheetApp.getUi();
  ui.alert('Hello, world');
}

跑起来长这样,一使用功能就会跳盖版通知。


ui.prompt() 设定可回应的弹跳视窗

这边的话则是可回应的弹跳视窗,也看说看回应,可以直接抓出回应的数值,甚至是直接回传。

function onOpen() {
  let ui = SpreadsheetApp.getUi();
  let response = ui.prompt('我想认识你', '可以知道你的名字是?', ui.ButtonSet.YES_NO);

  if (response.getSelectedButton() == ui.Button.YES) {
  SpreadsheetApp.getActiveSpreadsheet().toast('使用者的大名是  %s.', response.getResponseText());
} else if (response.getSelectedButton() == ui.Button.NO) {
  SpreadsheetApp.getActiveSpreadsheet().toast('使用者不想提供大名');
} else {
  SpreadsheetApp.getActiveSpreadsheet().toast('使用者连直接关掉');
}
}

跑起来长这样——

以上的功能虽然都用 onOpen 举例,但实际上都是可以搭配其他 GAS 的功能使用,以下就示范搭配的方式。


showModalDialog 呈现 HTML 的页面

那我们要怎麽样用更浮夸的 页面 呢?可以考虑加上 HTML

function onOpen() {
    SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
      .createMenu('Custom Menu')
      .addItem('Show dialog', 'showDialog')
      .addToUi();
}

function showDialog() {
  var html = HtmlService.createHtmlOutput('<p>这是一种简单的小程序</p>')
      .setWidth(250)
      .setHeight(300);
  SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
      .showModalDialog(html, '客制化外挂');
}

主要就是,设定好页面的长与宽,以及你要丢进去的 HTML body即可。跑起来长这样——


showSidebar 呈现 HTML 的页面

同样地, HTML 页面也可以用成 Sidebar 的形式。程序码如下——

function onOpen() {
    SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
      .createMenu('Custom Menu')
      .addItem('Show Sidebar', 'showSideBar')
      .addToUi();
}

function showSideBar() {
  var html = HtmlService.createHtmlOutput('<p>这是一种简单的小程序</p>')
      .setTitle('我的 Side Bar');

  SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
      .showSidebar(html);
}

跑起来长这样——

而以上这两个案例的 HTML 页面中,也可以镶入简单的 CSS 语法,并将 createHTMLOU 变成 createHtmlOutputFromFile 即可,可以参考官方的范例 与玩一下 HTML 与 CSS。如果想知道原本的 API 是怎麽写,可以参考 Google Apps Script Class Ui

如果要用 Google Slides、Google Document、Google Form 等,基本上是只要将上方五个案例的 SpreadSheetApp 换成 SlidesAppDocumentsAppFormApp 即可。


好,那今天我们主要到这边,今天我们学了——

  1. 透过 onOpen() 设定一开始就开启的程序
  2. 透过 getUi 设定五种不同的打包方式

以上可以帮助我们打包。而只要打包好(设定好onOpen())之後,那不管是谁,只要用电脑的浏览器打开 Google Sheet 等产品,就可以看到我们的「客制化工具列」,基本上就可以使用罗。


那今天就到这边,铁人赛也接近了尾声。我们也到了最後的打包阶段,希望内容对大家有所帮助。如果还有问题,透过留言之外,也可以到 Facebook Group,想开很久这次铁人赛才真的开起来,欢迎来当 Founding Member。如果不想错过可以订阅按赞小铃铛(?),也欢迎留言跟我说你还想知道什麽做法/主题。我们明天见。


<<:  Day 28-Unit Test 应用於使用重构与测试手法优化 C# Code-2 (情境及应用-8)

>>:  [Day 13]每天前进一点应该也是进步吧?(前端篇)

[Day 28]粗糙集特徵选择简介-6

这里我用 pandas.DataFrame 里的 groupby 帮我做分类 然後用 apply(l...

Day 7 [Python ML] Machine Learning的处理流程

Step 1: 蒐集数据 要先将自己需要的数据下载好,并且确认资料格式而去做不同的处理 Step ...

Day 22 Selenium模组一

今天的影片内容为介绍另一个强大的模组—Selenium 有了它,我们就可以随心所欲地控制浏览器并执行...

Are You Ready? ES2022!

本系列文章经过重新编排和扩充,已出书为ECMAScript关键30天。原始文章因当时准备时程紧迫,...

DAY27-Firebase Domain设定

前言: 昨天跟大家介绍了如何把你写好的网页透过firebase deploy到网路上,但目前还只能透...