You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome扩展Manifest V3中Google Picker调用异常问题求助

解决Manifest V3 Chrome扩展中Google Picker的沙箱与WebSocket错误问题

核心问题分析

  1. 沙箱iframe未配置allow-scripts时,无法执行api.js脚本;添加allow-scripts后,沙箱环境限制被部分解除,api.js尝试连接无效的ws://localhost:undefined/导致报错。
  2. 未在Manifest V3中声明沙箱页面,同时缺少Google Picker所需的权限配置和身份验证逻辑。

分步解决方案

1. 更新Manifest配置

添加sandboxed_pages声明沙箱页面,补充OAuth2配置用于Google身份验证:

{
  "manifest_version": 3,
  "name": "example",
  "version": "1.0.0",
  "action": { "default_title": "click me" },
  "permissions": [
    "activeTab",
    "tabs",
    "storage",
    "identity"
  ],
  "oauth2": {
    "client_id": "你的Google OAuth客户端ID.apps.googleusercontent.com",
    "scopes": [
      "https://www.googleapis.com/auth/drive.file"
    ]
  },
  "sandboxed_pages": [
    "picker.html"
  ],
  "content_scripts": [
    {
      "js": ["content.tsx"],
      "matches": ["https://*.google.com/*"]
    }
  ],
  "background": {
    "service_worker": "service-worker.ts",
    "type": "module"
  }
}

2. 调整iframe的sandbox属性

同时开启allow-same-origin、allow-scripts、allow-popups和allow-top-navigation,满足Google Picker运行需求:

<iframe sandbox="allow-same-origin allow-scripts allow-popups allow-top-navigation" className="picker-html" src={chrome.runtime.getURL("picker.html")}></iframe>

3. 修改picker.html与脚本逻辑

移除直接引入的api.js,改为动态加载并初始化Picker,通过postMessage传递选中的文件信息:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Google Picker</title>
</head>
<body>
  <div id="picker-container"></div>
  <script>
    window.addEventListener('message', async (event) => {
      if (event.data.type === 'INIT_PICKER' && event.data.authToken) {
        await loadGoogleApi();
        initPicker(event.data.authToken);
      }
    });

    function loadGoogleApi() {
      return new Promise((resolve) => {
        const script = document.createElement('script');
        script.src = 'https://apis.google.com/js/api.js';
        script.onload = () => {
          gapi.load('picker', resolve);
        };
        document.head.appendChild(script);
      });
    }

    function initPicker(authToken) {
      const picker = new google.picker.PickerBuilder()
        .addView(google.picker.ViewId.DOCUMENTS)
        .setOAuthToken(authToken)
        .setDeveloperKey('你的Google API开发者密钥')
        .setCallback((data) => {
          if (data.action === google.picker.Action.PICKED) {
            const file = data.docs[0];
            window.parent.postMessage({
              type: 'FILE_SELECTED',
              file: {
                id: file.id,
                name: file.name,
                url: file.url
              }
            }, '*');
          }
        })
        .build();
      picker.setVisible(true);
    }
  </script>
</body>
</html>

4. 扩展侧的身份验证与通信逻辑

在内容脚本或popup中,先获取OAuth令牌,再触发Picker初始化:

async function openGooglePicker() {
  try {
    const authToken = await chrome.identity.getAuthToken({ interactive: true });
    const pickerIframe = document.querySelector('.picker-html');
    pickerIframe.contentWindow.postMessage({
      type: 'INIT_PICKER',
      authToken: authToken
    }, chrome.runtime.getURL(''));
  } catch (err) {
    console.error('获取授权令牌失败:', err);
  }
}

window.addEventListener('message', (event) => {
  if (event.data.type === 'FILE_SELECTED') {
    console.log('选中的文件:', event.data.file);
    // 后续处理文件信息的逻辑
  }
});

// 绑定按钮点击事件
document.getElementById('open-picker-btn').addEventListener('click', openGooglePicker);

关键注意事项

  • 需在Google Cloud Console中创建OAuth客户端ID,配置正确的重定向URI(格式为chrome-extension://<扩展ID>/)。
  • allow-popups是Picker弹出选择窗口的必要权限。
  • 使用postMessage时,建议将*替换为扩展URL以提升安全性。

内容的提问来源于stack exchange,提问作者user2602774

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 23:12:45