将 Fluid 与 Teams 配合使用

在本教程结束时,可以将任何 Fluid 驱动的应用程序集成到 Teams 中,并与他人实时协作。

在本部分中,可以了解以下概念:

  1. 将 Fluid 客户端集成到 Teams 选项卡应用程序中。
  2. 运行 Teams 应用程序并将其连接到 Fluid 服务 (Azure Fluid Relay) 。
  3. 创建并获取 Fluid Containers,并将其传递给 React 组件。

有关生成复杂应用程序的详细信息,请参阅 FluidExamples

先决条件

本教程需要熟悉以下概念和资源:

创建项目

  1. 打开命令提示符并导航到要在其中创建项目的父文件夹, /My Microsoft Teams Projects例如 。

  2. 通过运行以下命令并 创建频道选项卡,创建 Teams 选项卡应用程序:

    yo teams
    
  3. 创建后,使用以下命令 cd <your project name>导航到项目。

  4. 项目使用以下库:

    说明
    fluid-framework 包含跨客户端同步数据的 IFluidContainer 和其他 分布式数据结构
    @fluidframework/azure-client 定义 Fluid 容器的起始架构。
    @fluidframework/test-client-utils 定义 InsecureTokenProvider 创建与 Fluid 服务的连接所需的 。

    运行以下命令以安装库:

    npm install @fluidframework/azure-client fluid-framework @fluidframework/test-client-utils
    

编写项目代码

  1. 在代码编辑器中打开文件 /src/client/<your tab name>

  2. 创建一个新文件, Util.ts 并添加以下导入语句:

    //`Util.ts
    
    import { IFluidContainer } from "fluid-framework";
    import { AzureClient, AzureClientProps } from "@fluidframework/azure-client";
    import { InsecureTokenProvider } from "@fluidframework/test-client-utils";
    

定义 Fluid 函数和参数

此应用旨在与所有 Fluid 相关的导入、初始化和函数一起使用在 Microsoft Teams 的上下文中。 这提供了增强的体验,并使将来更易于使用。 可以将以下代码添加到 import 语句:

// TODO 1: Define the parameter key(s).
// TODO 2: Define container schema.
// TODO 3: Define connectionConfig (AzureClientProps).
// TODO 4: Create Azure client.
// TODO 5: Define create container function.
// TODO 6: Define get container function.

注意

注释定义与 Fluid 服务和容器交互所需的所有函数和常量。

  1. TODO 1: 替换为下面的代码:

    export const containerIdQueryParamKey = "containerId";
    

    该常量在追加到 contentUrl Microsoft Teams 设置中的 时导出,稍后用于分析内容页中的容器 ID。 常见的模式是将重要的查询参数键存储为常量,而不是每次都键入原始字符串。

    客户端需要 containerSchema 定义此应用程序中使用的共享对象,然后才能创建任何容器。 此示例使用 SharedMap 作为 initialObjects,但可以使用任何共享对象。

    注意

    map是 对象的 IDSharedMap,它在容器中必须与任何其他 DDS 一样唯一。

  2. TODO: 2 替换为下面的代码:

    const containerSchema = {
        initialObjects: { map: SharedMap }
    };
    
  3. TODO: 3 替换为下面的代码:

    const connectionConfig : AzureClientProps =
    {
        connection: {
            type: "local",
            tokenProvider: new InsecureTokenProvider("foobar", { id: "user" }),
            endpoint: "http://localhost:7070"
        }
    };
    

    在客户端可以使用之前,它需要定义 AzureClientProps 客户端使用的连接类型的 。 需要 connectionConfig 属性才能连接到服务。 使用 Azure 客户端的本地模式。 若要在所有客户端之间启用协作,请将它替换为 Fluid Relay 服务凭据。 有关详细信息,请参阅如何 设置 Azure Fluid Relay 服务

  4. TODO: 4 替换为下面的代码:

    const client = new AzureClient(connectionConfig);
    
  5. TODO: 5 替换为下面的代码:

    export async function createContainer() : Promise<string> {
        const { container } = await client.createContainer(containerSchema);
        const containerId = await container.attach();
        return containerId;
    };
    

    在配置页中创建容器并将其追加到 contentUrl Teams 设置中时,必须在附加容器后返回容器 ID。

  6. TODO: 6 替换为下面的代码:

    export async function getContainer(id : string) : Promise<IFluidContainer> {
        const { container } = await client.getContainer(id, containerSchema);
        return container;
    };
    

    提取 Fluid 容器时,需要返回容器,因为应用程序必须与内容页中的容器及其内的 DDS 交互。

在配置页中创建 Fluid 容器

  1. 在代码编辑器中打开文件 src/client/<your tab name>/<your tab name>Config.tsx

    标准 Teams 选项卡应用程序流从配置转到内容页。 若要启用协作,在加载到内容页时保留容器至关重要。 保存容器的最佳解决方案是将容器 ID 作为查询参数追加到 contentUrl 内容页的 和 websiteUrlURL 上。 Teams 配置页中的“保存”按钮是配置页和内容页之间的网关。 它是创建容器并在设置中追加容器 ID 的位置。

  2. 添加下列导入语句:

    import { createContainer, containerIdQueryParamKey } from "./Util";
    
  3. 使用以下代码替换 onSaveHandler 方法。 此处添加的唯一行是调用前面定义的 Utils.ts create 容器方法,然后将返回的容器 ID 追加到 contentUrlwebsiteUrl 作为查询参数。

    const onSaveHandler = async (saveEvent: microsoftTeams.settings.SaveEvent) => {
        const host = "https://" + window.location.host;
        const containerId = await createContainer();
        microsoftTeams.settings.setSettings({
            contentUrl: host + "/<your tab name>/?" + containerIdQueryParamKey + "=" + containerId + "&name={loginHint}&tenant={tid}&group={groupId}&theme={theme}",
            websiteUrl: host + "/<your tab name>/?" + containerIdQueryParamKey + "=" + containerId + "&name={loginHint}&tenant={tid}&group={groupId}&theme={theme}",
            suggestedDisplayName: "<your tab name>",
            removeUrl: host + "/<your tab name>/remove.html?theme={theme}",
            entityId: entityId.current
        });
        saveEvent.notifySuccess();
    };
    

    确保将 替换为 <your tab name> 项目中的选项卡名称。

    警告

    由于内容页 URL 用于存储容器 ID,因此,如果删除 Teams 选项卡,则会删除此记录。 此外,每个内容页只能支持一个容器 ID。

重构内容页以反映 Fluid 应用程序

  1. 在代码编辑器中打开文件 src/client/<your tab name>/<your tab name>.tsx 。 典型的 Fluid 驱动的应用程序由视图和 Fluid 数据结构组成。 专注于获取/加载 Fluid 容器,并将所有与 Fluid 相关的交互保留在React组件中。

  2. 在内容页中添加以下导入语句:

    import { IFluidContainer } from "fluid-framework";
    import { getContainer, containerIdQueryParamKey } from "./Util";
    
  3. 删除内容页中 import 语句下的所有代码,并将其替换为以下内容:

    export const <your tab name> = () => {
      // TODO 1: Initialize Microsoft Teams.
      // TODO 2: Initialize inTeams boolean.
      // TODO 3: Define container as a React state.
      // TODO 4: Define a method that gets the Fluid container
      // TODO 5: Get Fluid container on content page startup.
      // TODO 6: Pass the container to the React component as argument.
    }
    

    确保将 替换为 <your tab name> 为项目定义的选项卡名称。

  4. TODO 1 替换为下面的代码:

    microsoftTeams.initialize();
    

    若要在 Teams 中显示内容页,必须包含 Microsoft Teams JavaScript 客户端库 ,并在页面加载后包含初始化它的调用。

  5. TODO 2 替换为下面的代码:

    const [{ inTeams }] = useTeams();
    

    由于 Teams 应用程序只是网页的 IFrame 注入,因此需要初始化 inTeams 布尔常量,以了解应用程序是否在 Teams 中,以及 Teams 资源(如 contentUrl)是否可用。

  6. TODO 3 替换为下面的代码:

    const [fluidContainer, setFluidContainer] = useState<IFluidContainer | undefined>(undefined);
    

    为容器使用React状态,因为它提供动态更新容器及其中的数据对象的能力。

  7. TODO 4 替换为下面的代码:

    const getFluidContainer = async (url : URLSearchParams) => {
        const containerId = url.get(containerIdQueryParamKey);
        if (!containerId) {
            throw Error("containerId not found in the URL");
        }
        const container = await getContainer(containerId);
        setFluidContainer(container);
    };
    

    分析 URL 以获取由 containerIdQueryParamKey定义的查询参数字符串,并检索容器 ID。 使用容器 ID 可以加载容器。 拥有容器后,设置fluidContainerReact状态,请参阅上一步。

  8. TODO 5 替换为下面的代码:

    useEffect(() => {
        if (inTeams === true) {
            microsoftTeams.settings.getSettings(async (instanceSettings) => {
                const url = new URL(instanceSettings.contentUrl);
                getFluidContainer(url.searchParams);
            });
            microsoftTeams.appInitialization.notifySuccess();
        }
    }, [inTeams]);
    

    定义获取 Fluid 容器的方式后,需要告知React在加载时调用getFluidContainer,然后根据应用程序是否在 Teams 中以状态存储结果。 React的 useState 挂钩提供所需的存储,并且 useEffect 允许对呈现进行调用getFluidContainer,并将返回的值传递到 setFluidContainer

    通过在 末尾useEffect添加inTeams依赖项数组,应用可确保仅在加载内容页面时调用此函数。

  9. TODO 6 替换为下面的代码:

    if (inTeams === false) {
      return (
          <div>This application only works in the context of Microsoft Teams</div>
      );
    }
    
    if (fluidContainer !== undefined) {
      return (
          <FluidComponent fluidContainer={fluidContainer} />
      );
    }
    
    return (
      <div>Loading FluidComponent...</div>
    );
    

    注意

    请务必确保在 Teams 中加载内容页,并在将 Fluid 容器传递到定义为 React 组件之前对其进行定义, (定义为 FluidComponent,请参阅下面的) 。

为 Fluid 视图和数据创建React组件

你已集成 Teams 和 Fluid 的基本创建流。 现在可以创建自己的React组件来处理应用程序视图和 Fluid 数据之间的交互。 从现在起,逻辑和流的行为就像其他 Fluid 驱动的应用程序一样。 设置基本结构后,可以通过更改 ContainerSchema 和应用程序视图与内容页中的 DDSes/数据对象的交互,将任何 Fluid 示例创建为 Teams 应用程序。

启动 Fluid 服务器并运行应用程序

如果使用 Azure 客户端本地模式在本地运行 Teams 应用程序,请确保在命令提示符中运行以下命令以启动 Fluid 服务:

npx @fluidframework/azure-local-service@latest

若要运行并启动 Teams 应用程序,请打开另一个终端,并按照 说明运行应用程序服务器

警告

不保留具有 ngrok的可用隧道的 HostName。 每次运行都会生成不同的 URL。 创建新 ngrok 隧道后,将无法再访问旧容器。 有关生产方案,请参阅 将 AzureClient 与 Azure Fluid Relay 配合使用

注意

安装其他依赖项,使此演示与 Webpack 5 兼容。 如果收到与“缓冲区”包相关的编译错误,请运行 npm install -D buffer 并重试。 这将在 Fluid Framework 的未来版本中得到解决。

后续步骤

将 AzureClient 与 Azure Fluid Relay 配合使用

由于这是一个 Teams 选项卡应用程序,因此协作和交互是main重点。 将前面提供的本地模式 AzureClientProps 替换为 Azure 服务实例中的非本地凭据,以便其他人可以在应用程序中加入并与你交互。 请参阅 如何预配 Azure Fluid Relay 服务

重要

请务必隐藏传入 AzureClientProps 的凭据,避免意外提交到源代码管理。 Teams 项目附带一个 .env 文件,你可以在其中将凭据存储为环境变量,并且文件本身已包含在 中 .gitignore。 若要在 Teams 中使用环境变量,请参阅 设置和获取环境变量

警告

InsecureTokenProvider 是在本地测试应用程序的一种便捷方法。 你负责处理任何用户身份验证,并将 安全令牌 用于任何生产环境。

设置和获取环境变量

若要在 Teams 中设置并检索环境变量,可以利用内置 .env 文件。 以下代码用于在 中 .env设置环境变量:

# .env

TENANT_KEY=foobar

若要将文件的内容 .env 传递给客户端应用,需要将它们 webpack.config.js 配置为 , webpack 以便在运行时提供对这些内容的访问权限。 使用以下代码从 .env添加环境变量:

// webpack,config.js

webpack.EnvironmentPlugin({
    PUBLIC_HOSTNAME: undefined,
    TAB_APP_ID: null,
    TAB_APP_URI: null,
    REACT_APP_TENANT_KEY: JSON.stringify(process.env.TENANT_KEY) // Add environment variable here
}),

可以在 中访问环境变量 Util.ts

// Util.ts

tokenProvider: new InsecureTokenProvider(JSON.parse(process.env.REACT_APP_TENANT_KEY!), { id: "user" }),

提示

对代码进行更改时,项目会自动重新生成,应用程序服务器会重新加载。 但是,如果对容器架构进行更改,则只有在关闭并重启应用程序服务器时,这些更改才会生效。 为此,请转到命令提示符并按 Ctrl-C 两次。 然后运行或gulp ngrok-serve再次运行gulp serve

另请参阅