适配Unity调用的Google Web App用户授权弹窗实现咨询
现有代码的核心失效原因
onOpen()是Google Sheets/文档容器触发的自动函数,你在doGet里手动调用它时,函数内部创建的HtmlOutput对象只是存在内存里的临时变量,没有作为返回值推送给前端,自然不会弹出任何窗口。- 当前
doGet不做任何授权状态判断,上来就直接调用表格读取逻辑。当Web App设置为“以你的身份执行”时,所有用户的请求都借用你的权限跑,平台永远不会触发面向其他用户的授权弹窗;如果切到“以用户身份执行”,未授权用户直接读取表格会触发权限报错,连可交互的引导页面都拿不到。 - 用Unity的
UnityWebRequest发纯接口请求时,就算后端返回了HTML授权页,客户端也只会把内容当纯文本解析,根本没有渲染、弹出交互窗口的能力。
正确落地实现步骤
基础配置调整
首先把Web App的部署权限配置改成:
- 执行身份:以访问应用的用户身份执行
- 访问权限:允许所有拥有链接的用户访问
这个配置是触发Google官方用户授权流程的前提——只要你的代码用到了需要用户授权的服务(比如读取Spreadsheet、读写UserProperties),平台会自动在用户第一次访问时拦截请求,重定向到Google标准的授权同意页,你不需要手动写代码拉取弹窗。
后端逻辑改造
抛弃之前“调用onOpen弹窗”的逻辑,直接在doGet里做分支判断,根据授权状态返回对应的内容:
- 未授权状态:返回带操作按钮的HTML引导页,引导用户完成授权
- 已授权状态:再执行原来的表格读取、返回JSON数据的逻辑
你自己写的authorize函数只需要做两件事:把授权标记写到UserProperties里,返回提示页面引导用户返回客户端,不需要额外处理平台层面的授权流程。
前端(Unity)适配调整
受Google授权流程的限制,纯接口请求无法完成授权交互,必须做流程跳转:
- Unity第一次发起Get请求时,如果收到未授权的响应/接口权限报错,直接调用系统浏览器打开Web App的公开访问链接
- 用户在浏览器环境下走完Google的官方授权流程、点击页面上的授权按钮完成业务标记后,关闭浏览器返回Unity
- Unity重新发起Get请求,此时后端已经能识别到授权状态,直接返回所需的JSON数据
可直接参考的改造后代码
// 业务授权完成标记函数 function authorize(){ // 写入授权状态 UserProperties.setProperty('author','yes'); // 返回授权完成提示页 return HtmlService.createHtmlOutput(` <div style="padding: 2rem; font-family: system-ui;"> <h3>授权已完成</h3> <p>你可以关闭当前页面,回到客户端继续操作。</p> </div> `).setTitle("授权确认"); } function doGet(e){ // 优先校验授权状态,不要直接读取表格 const hasAuth = UserProperties.getProperty('author'); // 未授权分支:返回授权引导页 if(!hasAuth){ const authUrl = ScriptApp.getService().getUrl({path: '/authorize'}); return HtmlService.createHtmlOutput(` <div style="padding: 2rem; font-family: system-ui; max-width: 400px;"> <h3>应用需要授权才能访问关联的Google Sheets数据</h3> <p>点击下方按钮即可完成授权流程</p> <button onclick="window.location.href='${authUrl}'" style="padding: 0.75rem 1.5rem; background: #1a73e8; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 1rem;" > 完成授权 </button> </div> `).setTitle("授权引导"); } // 已授权分支:执行原有数据读取逻辑 const activeSheet = SpreadsheetApp.getActiveSheet(); const values = []; // 读取第1行目标列数据 for(let i = 3; i <= 16; i++){ const columnChar = String.fromCharCode('A'.charCodeAt() + i); values.push(activeSheet.getRange(`${columnChar}1`).getValue()); } // 读取第2行目标列数据 for(let i = 3; i <= 16; i++){ const columnChar = String.fromCharCode('A'.charCodeAt() + i); values.push(activeSheet.getRange(`${columnChar}2`).getValue()); } // 返回JSON格式数据 return ContentService.createTextOutput(JSON.stringify({result: values})) .setMimeType(ContentService.MimeType.JSON); }
常见踩坑提醒
- 所有推送给前端的HTML内容,必须是
doGet的直接返回值,不要在中间函数里创建HtmlOutput对象却不return,否则前端根本接收不到。 - Google的官方授权弹窗是平台自动触发的,不需要手动调用接口拉取:只要代码以用户身份执行、且触发了需要授权的操作,平台就会自动弹出授权页。之前看不到弹窗的核心原因,是一直使用“以你的身份执行”的部署配置,平台不需要向其他用户索要权限。
- 不要尝试在Unity客户端内直接嵌入授权流程:Google的授权页有严格的域名校验,第三方客户端无法直接承接授权重定向,必须引导用户跳转到系统浏览器完成操作。
内容的提问来源于stack exchange,提问作者DerpDerp
相关产品推荐
相关产品推荐

