使用 Google Meet 插件 SDK 构建网页版插件

本教程介绍如何使用网页版 Google Meet 插件软件开发套件 (SDK) 构建插件。这样一来,您无需离开 Google Meet 即可在 Web 应用内进行分享和协作。

  • Google Meet 中的 Meet 网页版插件。
    网页版 Meet 插件 SDK 的侧边栏。
  • Google Meet 中的 Meet 网页版插件。
    网页版 Meet 插件 SDK 的主要阶段,可供用户展开协作。

目标

  • 在 Google Cloud 控制台中创建和部署 Web 版 Meet 插件 SDK。
  • 为 Web 版 Meet 插件 SDK 创建主界面和侧边栏。

准备环境

本部分介绍了如何为 Meet 插件 SDK for Web 创建和配置 Google Cloud 项目。

创建 Google Cloud 项目

Google Cloud 控制台

  1. 在 Google Cloud 控制台中,依次点击“菜单”图标 > IAM 和管理 > 创建项目

    前往“创建项目”

  2. 项目名称字段中,为项目输入一个描述性名称。

    可选:如需修改项目 ID,请点击修改。项目创建后,项目 ID 便无法更改,因此请选择符合项目生命周期需求的 ID。

  3. 位置字段中,点击浏览以显示项目的可能位置。然后,点击选择
  4. 点击创建。Google Cloud 控制台会转到“信息中心”页面,您的项目会在几分钟内创建完毕。

gcloud CLI

在以下某个开发环境中,访问 Google Cloud CLI(“gcloud”):

  • Cloud Shell:如需使用已设置 gcloud CLI 的在线终端,请激活 Cloud Shell。
    激活 Cloud Shell
  • 本地 Shell:如需使用本地开发环境,请安装initialize gcloud CLI。
    如需创建 Cloud 项目,请使用“gcloud projects create”命令:
    gcloud projects create PROJECT_ID
    为要创建的项目设置 ID,以替换 PROJECT_ID

启用 API

控制台

  1. 在 Google Cloud 控制台中,启用 Google Workspace Marketplace SDK 和 Google Workspace Add-ons API。

    启用 API

  2. 确认您要在正确的 Cloud 项目中启用 API,然后点击下一步

  3. 确认您启用了正确的 API,然后点击启用

gcloud CLI

  1. 如有必要,将当前 Google Cloud 项目设置为您使用 gcloud config set project 命令创建的项目:

    gcloud config set project PROJECT_ID
    

    PROJECT_ID 替换为您创建的 Cloud 项目的项目 ID

  2. 使用 gcloud services enable 命令启用 Google Workspace Marketplace SDK 和 Google Workspace Add-ons API:

    gcloud services enable appsmarket-component.googleapis.com gsuiteaddons.googleapis.com
    

创建和部署 Web 应用

在下一部分中,您将复制并更新整个 Web 应用项目(使用 Firebase 构建),其中包含 Web 版 Meet 插件 SDK 的所有必需应用代码。首先,您需要配置并部署 Web 应用。

查看示例代码

您可以在 GitHub 上查看和下载基础 Web 应用。

在 GitHub 上查看

以下是基本代码的概览:

  • 它使用 Next.js 构建而成,Next.js 是一个基于 React 的框架。
  • 它使用 Tailwind CSS 来设置样式。
  • src/components 包含大部分应用逻辑。此处没有任何需要更新或修改的内容。
  • src/firebase 包含 Firebase 配置和初始化代码。
  • src/app 包含 Web 应用入口点。
  • src/app/page.tsx 是主页面或项目列表。
  • src/app/project/[id]/page.tsx 是单个项目和任务列表的页面。
  • .env 包含环境配置。

设置 Firebase 项目和 CLI

Firebase 是一个移动应用和 Web 应用开发平台,可帮助开发者构建应用。Firestore 是一个 NoSQL 文档数据库,允许用户存储、同步和查询移动应用及 Web 应用的数据。Firestore 用于存储待办事项列表信息。由于应用将使用 Firebase 功能,因此您应设置 Firebase 项目以及 Firebase CLI。具体操作步骤如下:

  1. 创建一个 Firebase 项目

  2. 创建 Cloud Firestore 数据库

  3. 安装 Firebase CLI更新到其最新版本

  4. 转到基础应用的根目录。

  5. 初始化您的项目。

    将本地项目文件关联到 Firebase 项目:

    firebase init firestore

    在项目初始化期间,Firebase CLI 会提示您执行以下操作:

    1. 选择一个选项:

      选择 Use an existing project,然后选择您创建的 Firebase 项目。

      选定的 Firebase 项目是您本地项目目录的“默认”Firebase 项目。

    2. Firestore 规则应使用什么文件?

      如果系统显示 (firestore.rules),请按 Enter 键。否则,请先输入 firestore.rules,然后按 Enter 键。

    3. 文件 firestore.rules 已存在。是否要使用 Firebase 控制台中的 Firestore 规则覆盖它?(是/否)

      输入“N”,然后按 Enter 键。

    4. 应该将哪个文件用于 Firestore 索引?

      如果系统显示 (firestore.indexes.json),请按 Enter 键。否则,请先输入 firestore.indexes.json,然后按 Enter 键。

Firestore 数据库现已设置完毕,可以用于该应用。

通过 Google 进行 Firebase 身份验证

接下来,启用通过 Google 提供方的身份验证。具体操作步骤如下:

  1. 在 Firebase 控制台中,转到 Authentication 页面。

    前往 Firebase Authentication

  2. 如果这是您首次设置提供方,请点击 Set up sign-in(设置登录)方法。否则,请点击添加新提供商

  3. 选择 Google,并确保将其状态设为启用

在 Firebase 中创建 Web 应用

最后,在 Firebase 项目中创建一个 Web 应用并获取配置。具体操作步骤如下:

  1. 在 Firebase 控制台中,在 Firebase 项目中注册您的 Web 应用

  2. 转到项目设置

  3. 您的应用中,找到并点击您已注册的 Web 应用。

  4. 记下 firebaseConfig 中的值。在下一部分中,您将会在更新环境变量时用到它们。

查找您的 Google Cloud 项目编号

  1. 打开 Google Cloud 控制台。

    转到 Google Cloud 控制台

  2. 点击 Google Cloud 控制台旁边的向下箭头 下拉箭头,然后选择您的项目。

  3. 依次点击“菜单”图标 “菜单”图标 > Cloud 概览

  4. 项目信息部分中,记下项目编号的值。在下一部分中,您将用它来更新环境变量。

更新环境变量

在基本代码的 .env 文件中,使用前面步骤中收集的详细信息填写以下内容:

NEXT_PUBLIC_GOOGLE_PROJECT_NUMBER=GOOGLE_PROJECT_NUMBER
NEXT_PUBLIC_GOOGLE_PROJECT_ID=PROJECT_ID
NEXT_PUBLIC_GOOGLE_API_KEY=API_KEY
NEXT_PUBLIC_GOOGLE_AUTH_DOMAIN=AUTH_DOMAIN
NEXT_PUBLIC_GOOGLE_STORAGE_BUCKET=STORAGE_BUCKET
NEXT_PUBLIC_GOOGLE_MSG_SENDER_ID=MSG_SENDER_ID
NEXT_PUBLIC_GOOGLE_APPID=APP_ID

使用前面步骤中收集的 firebaseConfig 值和项目编号替换以下内容:

  • GOOGLE_PROJECT_NUMBER:您的 Google Cloud 项目的编号
  • PROJECT_ID:您的 Firebase Web 应用的 projectId
  • API_KEY:您的 Firebase Web 应用的 apiKey
  • AUTH_DOMAIN:您的 Firebase Web 应用的 authDomain
  • STORAGE_BUCKET:您的 Firebase Web 应用的 storageBucket
  • MSG_SENDER_ID:您的 Firebase Web 应用的 messagingSenderId
  • APP_ID:您的 Firebase Web 应用的 appId

设置您的应用凭据

要设置 Google 应用凭据,请执行以下操作:

  1. 在 Firebase 控制台中,转到项目设置页面。

    前往“项目设置”

  2. 服务帐号标签页中,选择 Firebase Admin SDK 标签页。

  3. 点击生成新的私钥,并记下所下载 JSON 文件的路径。

  4. 在您的终端中,运行以下命令:

    export GOOGLE_APPLICATION_CREDENTIALS="JSON_PATH"
    

    JSON_PATH 替换为下载的 JSON 文件所在的路径。

部署到开发服务器

现在,代码和环境已准备就绪,您就可以将 Web 应用部署到本地开发服务器了。为此,请转到您的 Web 应用目录并执行以下操作:

  1. 运行命令 npm install,然后等待节点模块下载并安装。

  2. 运行以下命令:npm run dev

  3. 转到 http://localhost:3000/ 以验证 Web 应用是否已启动并正在运行。

使用网页版 Meet 插件 SDK

下一步是进行必要的代码更新,以集成代码并将其设为 Google Meet 插件。具体操作步骤如下:

  1. 创建文件 src/meet/meet.d.ts

    1. 您可以从 https://www.gstatic.com/meetjs/addons/0.7.0/index.d.ts 获取最新类型,并将文件保存在本地。
  2. 创建文件 src/meet/utils.ts

    1. 添加函数 createAddonSession。系统会在此处建立会话,以便在 Google Meet 中进行通信。

      export function createAddonSession() {
        let session;
      
        session = window.meet.addon.createAddonSession({
          cloudProjectNumber: `${process.env.NEXT_PUBLIC_GOOGLE_PROJECT_NUMBER}`,
        });
        return session;
      }
      
  3. 创建目录 src/app/meet。此目录将用作所有 Meet 专用路由的专用目录。

  4. 创建文件 src/app/meet/layout.tsx

    1. 所有 Meet 相关页面的通用布局。您可以在此处注入 Meet SDK 脚本,并确保在呈现任何内容之前加载 SDK。

      "use client";
      
      import Script from "next/script";
      import { useState } from "react";
      
      type LayoutProps = {
        children: React.ReactNode;
      };
      
      /**
      * Layout for the add-on pages. Injects the Meet SDK script.
      */
      export default function RootLayout({ children }: LayoutProps) {
        const [sdkAvailable, setSdkAvailable] = useState(false);
        return (<>
        <Script
          src="https://www.gstatic.com/meetjs/addons/0.7.0/meet.addons.js"
          onReady={() => setSdkAvailable(true)}
        />
        {sdkAvailable ? children : <div>Loading...</div>}
        </>);
      }
      
  5. 创建文件 src/app/meet/sidepanel/page.tsx

    1. Meet 插件的侧边栏内容。 本页面专门负责处理内容选择,以及在选择内容时设置协作开始状态。

      "use client";
      
      import { firebaseApp } from "@/firebase/config";
      import { getAuth } from "firebase/auth";
      import { ProjectList } from "@/components/ProjectList";
      import { createAddonSession } from "@/meet/utils";
      import { DocumentReference } from "firebase/firestore";
      import { useSearchParams } from "next/navigation";
      import { useAuthState, useSignInWithGoogle } from "react-firebase-hooks/auth";
      import GoogleButton from "react-google-button";
      
      const auth = getAuth(firebaseApp);
      
      async function startCollaboration(ref: DocumentReference) {
        const url = new URL(window.location.href);
      
        // Initializing session
        const session = await createAddonSession();
        const client = await session.createSidePanelClient();
      
        client.setCollaborationStartingState({
          mainStageUrl: `${url.protocol}//${url.host}/meet/project/${ref.id}`,
          sidePanelUrl: `${url.protocol}//${url.host}/meet/sidepanel?participant=true`,
        });
      }
      
      export default function Home() {
        const params = useSearchParams();
        const [user] = useAuthState(auth);
        const [signInWithGoogle] = useSignInWithGoogle(auth);
      
        const handleProjectSelect = async (ref: DocumentReference) => {
          // Before navigating, make sure project selection is saved
          // for when a shared activity is started.
          await startCollaboration(ref);
        };
      
        if (!user) {
          return (
            <GoogleButton
              onClick={() => signInWithGoogle()}
            ></GoogleButton>
          );
        }
      
        if (params.get("participant")) {
          return <div>You may now close this panel.</div>;
        }
      
        return (
          <div className="px-4">
            <ProjectList onSelect={handleProjectSelect} />
          </div>
        );
      }
      
  6. 创建文件 src/app/meet/project/\[id\]/page.tsx

    1. Meet 插件的主要 Stage 内容。它会显示侧边栏中所选项目的内容。

      "use client";
      
      import { Project } from "@/components/Project";
      import { createAddonSession } from "@/meet/utils";
      import { firebaseApp } from "@/firebase/config";
      import { getAuth, User } from "firebase/auth";
      import { useRouter } from "next/navigation";
      import { useAuthState, useSignInWithGoogle } from "react-firebase-hooks/auth";
      import GoogleButton from "react-google-button";
      
      const auth = getAuth(firebaseApp);
      
      // Monitor auth state changes.
      if (typeof window !== "undefined") {
        auth.onAuthStateChanged(() => {
          onAuthStateSettled(auth.currentUser);
        });
      
        auth.authStateReady().then(() => {
          onAuthStateSettled(auth.currentUser);
        });
      }
      
      /**
      * Check for auth & doc access when auth state changes.
      */
      async function onAuthStateSettled(user: User | null | undefined) {
        const session = await createAddonSession();
        const client = await session.createMainStageClient();
      
        // For participants, side panel should be closed after authentication
        await client.unloadSidePanel();
      }
      
      type PageParams = {
        params: {
          id: string;
        };
      };
      
        export default function Page({ params }: PageParams) {
        const router = useRouter();
        const [user, isUserLoading] = useAuthState(auth);
      
        if (window.meet.addon.getFrameType() === "MAIN_STAGE") {
          if (isUserLoading) {
            return <div>Loading...</div>;
          }
        }
      
        if (!user) {
          return (
              <GoogleButton
                onClick={() => signInWithGoogle()}
              ></GoogleButton>
            );
        }
      
        let backButton = null;
        if (window.meet.addon.getFrameType() === "SIDE_PANEL") {
          backButton = (
            <div className="px-2 pb-2 -my-2">
              <button className="flex flex-row" onClick={() => router.back()}>
                <span className="material-icons">arrow_back</span>previous screen
                <div className="sr-only">navigate back</div>
              </button>
            </div>
          );
        }
      
        return (
          <div className="w-full min-h-screen px-2">
            {backButton}
            <div className="flex flex-col min-h-screeen">
              <Project id={params.id} />
            </div>
          </div>
        );
      }
      

创建部署

设置插件的部署:

  1. 在 Google Cloud 控制台中,前往 Google Workspace Add-ons API

    前往 Google Workspace Add-ons API

  2. 点击替代运行时标签页。

  3. 点击创建新部署并输入插件的部署 ID。部署 ID 是任意字符串,可帮助插件开发者识别包含插件清单的部署。部署 ID 为必填项,最多可包含 100 个字符。

  4. 点击下一步

  5. 系统会打开一个侧边栏,供您提交 JSON 格式的插件清单规范。使用此面板输入以下内容作为清单文件:

    {
    "addOns": {
      "common": {
        "name": "My First Meet Web Add-on",
        "logoUrl": "https://fonts.gstatic.com/s/i/googlematerialicons/markunread_mailbox/v6/black-24dp/1x/gm_markunread_mailbox_black_24dp.png"
      },
      "meet": {
        "web": {
          "sidePanelUri": "http://localhost:3000/meet/sidepanel",
          "addOnOrigins": ["http://localhost:3000"]
        }
      }
    }
    }
    
    
  6. 点击提交。如果插件部署成功,您应该会看到以下消息:Deployment "ID" created

  7. 在页面的部署部分下验证部署。

测试网页版 Meet 插件 SDK

如需测试适用于 Web 的完整 Meet 插件 SDK,请运行 Google Meet 并验证应用能否按预期运行。具体操作步骤如下:

  1. 转到 Meet 并发起新会议。
  2. 点击活动
  3. 您的插件部分,您应该会看到 My First Meet Web 插件。选中该图标即可运行该插件。
  4. 插件运行后,侧边栏会打开。
  5. 使用您的 Google 账号登录该应用。登录后,点击新建项目
  6. 选择已创建的 Untitled Project
  7. 点击侧边栏上的 Start Activity
  8. 开始后,系统会关闭侧边栏并打开主 Stage。

现在,该插件可以按预期运行,但仅限于通过应用登录(第 5 步)的用户。通过 Meet 加入活动的其他参与者无法在应用中进行协作,因为他们不能与第一位用户共享同一会话。需要进一步的实现(例如令牌共享机制)才能与他人分享内容。

清理

为避免因本教程中使用的资源导致您的 Google Cloud 帐号产生费用,我们建议您删除该 Cloud 项目。

  1. 在 Google Cloud 控制台中,前往管理资源页面。依次点击菜单图标 > IAM 和管理 > 管理资源

    前往 Resource Manager

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关停以删除项目。