将 Fluid 与 Teams 配合使用
在本教程结束时,可以将任何 Fluid 驱动的应用程序集成到 Teams 中,并与他人实时协作。
在本部分中,可以了解以下概念:
- 将 Fluid 客户端集成到 Teams 选项卡应用程序中。
- 运行 Teams 应用程序并将其连接到 Fluid 服务 (Azure Fluid Relay) 。
- 创建并获取 Fluid Containers,并将其传递给 React 组件。
有关生成复杂应用程序的详细信息,请参阅 FluidExamples。
先决条件
本教程需要熟悉以下概念和资源:
创建项目
打开命令提示符并导航到要在其中创建项目的父文件夹,
/My Microsoft Teams Projects
例如 。通过运行以下命令并 创建频道选项卡,创建 Teams 选项卡应用程序:
yo teams
创建后,使用以下命令
cd <your project name>
导航到项目。项目使用以下库:
库 说明 fluid-framework
包含跨客户端同步数据的 IFluidContainer 和其他 分布式数据结构 。 @fluidframework/azure-client
定义 Fluid 容器的起始架构。 @fluidframework/test-client-utils
定义 InsecureTokenProvider
创建与 Fluid 服务的连接所需的 。运行以下命令以安装库:
npm install @fluidframework/azure-client fluid-framework @fluidframework/test-client-utils
编写项目代码
在代码编辑器中打开文件
/src/client/<your tab name>
。创建一个新文件,
Util.ts
并添加以下导入语句://`Util.ts import { IFluidContainer } from "fluid-framework"; import { AzureClient, AzureClientProps } from "@fluidframework/azure-client"; import { InsecureTokenProvider } from "@fluidframework/test-client-utils";
定义 Fluid 函数和参数
此应用旨在用于Microsoft Teams 的上下文中,其中包含所有与 Fluid 相关的导入、初始化和函数。 这提供了增强的体验,并使将来更易于使用。 可以将以下代码添加到 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 服务和容器交互所需的所有函数和常量。
将
TODO 1:
替换为下面的代码:export const containerIdQueryParamKey = "containerId";
常量在附加到
contentUrl
Microsoft Teams 设置中的 时导出,稍后用于分析内容页中的容器 ID。 常见的模式是将重要的查询参数键存储为常量,而不是每次都键入原始字符串。客户端需要
containerSchema
定义此应用程序中使用的共享对象,然后才能创建任何容器。 此示例使用 SharedMap 作为initialObjects
,但可以使用任何共享对象。注意
map
是 对象的 IDSharedMap
,它在容器中必须与任何其他 DDS 一样唯一。将
TODO: 2
替换为下面的代码:const containerSchema = { initialObjects: { map: SharedMap } };
将
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 服务。将
TODO: 4
替换为下面的代码:const client = new AzureClient(connectionConfig);
将
TODO: 5
替换为下面的代码:export async function createContainer() : Promise<string> { const { container } = await client.createContainer(containerSchema); const containerId = await container.attach(); return containerId; };
在配置页中创建容器并将其追加到
contentUrl
Teams 设置中时,必须在附加容器后返回容器 ID。将
TODO: 6
替换为下面的代码:export async function getContainer(id : string) : Promise<IFluidContainer> { const { container } = await client.getContainer(id, containerSchema); return container; };
提取 Fluid 容器时,需要返回容器,因为应用程序必须与内容页中的容器及其内的 DDS 交互。
在配置页中创建 Fluid 容器
在代码编辑器中打开文件
src/client/<your tab name>/<your tab name>Config.tsx
。标准 Teams 选项卡应用程序流从配置转到内容页。 若要启用协作,在加载到内容页时保留容器至关重要。 保存容器的最佳解决方案是将容器 ID 作为查询参数追加到
contentUrl
内容页的 和websiteUrl
URL 上。 Teams 配置页中的“保存”按钮是配置页和内容页之间的网关。 它是创建容器并在设置中追加容器 ID 的位置。添加下列导入语句:
import { createContainer, containerIdQueryParamKey } from "./Util";
使用以下代码替换
onSaveHandler
方法。 此处添加的唯一行是调用前面定义的Utils.ts
create 容器方法,然后将返回的容器 ID 追加到contentUrl
和websiteUrl
作为查询参数。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 应用程序
在代码编辑器中打开文件
src/client/<your tab name>/<your tab name>.tsx
。 典型的 Fluid 驱动的应用程序由视图和 Fluid 数据结构组成。 专注于获取/加载 Fluid 容器,并将所有与 Fluid 相关的交互保留在React组件中。在内容页中添加以下导入语句:
import { IFluidContainer } from "fluid-framework"; import { getContainer, containerIdQueryParamKey } from "./Util";
删除内容页中 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>
为项目定义的选项卡名称。将
TODO 1
替换为下面的代码:microsoftTeams.initialize();
若要在 Teams 中显示内容页,必须包含 Microsoft Teams JavaScript 客户端库 ,并在页面加载后包含用于初始化它的调用。
将
TODO 2
替换为下面的代码:const [{ inTeams }] = useTeams();
由于 Teams 应用程序只是网页的 IFrame 注入,因此需要初始化
inTeams
布尔常量,以了解应用程序是否在 Teams 中,以及 Teams 资源(如contentUrl
)是否可用。将
TODO 3
替换为下面的代码:const [fluidContainer, setFluidContainer] = useState<IFluidContainer | undefined>(undefined);
为容器使用React状态,因为它提供动态更新容器及其中的数据对象的能力。
将
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 可以加载容器。 拥有容器后,设置fluidContainer
React状态,请参阅上一步。将
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
依赖项数组,应用可确保仅在加载内容页面时调用此函数。将
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
。