如何在关闭Dialog时更新Google Workspace Add-on的Card?
解决Google Apps Script中关闭Picker Dialog后更新Card的超时问题
问题背景
在Google Apps Script开发场景中,点击Card内按钮调用showDialog函数弹出集成Google Picker的模态Dialog,用于选择表格,需要实现关闭Dialog时更新Card的功能。此前尝试开发者元数据+循环检测的方案,但因Google的响应时间限制频繁触发超时错误,需寻求正确实现方式。
错误方案分析
之前的方案在showDialog中弹出Dialog后,试图通过循环检测开发者元数据来触发Card更新,但Google Apps Script服务端函数有严格的执行时间限制,这种同步轮询的方式会直接触发超时,且不符合Card Service的异步响应机制。
正确实现方案
核心思路:利用google.script.run的异步回调机制,在Picker选择完成后直接调用服务端的Card更新函数,通过返回ActionResponse完成Card更新。注意:showModalDialog是异步操作,服务端showDialog函数会立即返回,无法同步等待Dialog交互结果。
完整代码示例
服务端代码
// Card内按钮触发的函数,仅负责弹出Dialog function showDialog() { const html = HtmlService.createHtmlOutputFromFile('dialog.html') .setWidth(600) .setHeight(425) .setSandboxMode(HtmlService.SandboxMode.IFRAME); SpreadsheetApp.getUi().showModalDialog(html, '选择表格'); } // 客户端Picker回调触发的服务端函数,负责更新Card function callback(selectedSpreadsheet) { // 根据选中的表格信息构建新Card const card = CardService.newCardBuilder() .setHeader(CardService.newCardHeader().setTitle('已选择表格')) .addSection(CardService.newCardSection() .addWidget(CardService.newTextParagraph().setText(`表格ID:${selectedSpreadsheet.id}\n表格名称:${selectedSpreadsheet.name}`))) .build(); // 返回更新Card的响应 return CardService.newActionResponseBuilder() .setNavigation(CardService.newNavigation().updateCard(card)) .setNotification(CardService.newNotification().setText('导入成功')) .build(); } // 用于获取OAuth令牌,供Google Picker使用 function getOAuthToken() { return ScriptApp.getOAuthToken(); }
dialog.html代码
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css"> <script> let pickerApiLoaded = false; function onApiLoad() { gapi.load('picker', {'callback': () => { pickerApiLoaded = true; // 获取OAuth令牌,初始化Picker google.script.run.withSuccessHandler(createPicker) .getOAuthToken(); }}); } function createPicker(token) { if (pickerApiLoaded && token) { const picker = new google.picker.PickerBuilder() .addView(new google.picker.DocsView(google.picker.ViewId.SPREADSHEETS) .setMode(google.picker.DocsViewMode.LIST)) .setOAuthToken(token) .setCallback(pickerCallback) .setTitle('选择要导入的表格') .build(); picker.setVisible(true); } else { alert('无法加载文件选择器'); } } function pickerCallback(data) { const action = data[google.picker.Response.ACTION]; if (action == google.picker.Action.PICKED) { // 提取选中表格的关键信息 const doc = data[google.picker.Response.DOCUMENTS][0]; const selectedSpreadsheet = { id: doc[google.picker.Document.ID], name: doc[google.picker.Document.NAME] }; // 调用服务端更新Card,成功后关闭Dialog google.script.run.withSuccessHandler(() => { google.script.host.close(); }).callback(selectedSpreadsheet); } else if (action == google.picker.Action.CANCEL) { google.script.host.close(); } } </script> </head> <body> <script src="https://apis.google.com/js/api.js?onload=onApiLoad"></script> </body> </html>
关键说明
- 异步回调逻辑:Picker选择完成后,通过
google.script.run调用服务端callback函数,该函数返回ActionResponse触发Card更新,避免同步等待导致超时。 - Card更新机制:
callback函数必须返回CardService.ActionResponse类型,Google Workspace会自动识别并更新对应的Card。 - Dialog关闭时机:使用
withSuccessHandler确保服务端完成Card更新后再关闭Dialog,避免更新失败但Dialog已关闭的异常情况。
内容的提问来源于stack exchange,提问作者Hamu
相关产品推荐
相关产品推荐

