Skip to the content.

Teams Tab App 代码深入浅出 - 配置页面

上一篇文章我们使用Teams Toolkit 来创建、运行 tab app。这篇文章我们深入来分析看一下tab app 的代码。

先打开代码目录,可以看到在 src 目录下有入口文件 index.tsx,然后在 components 目录下有更多的一些 tsx 文件,tsx 是 typescript的一种扩展文件,主要用于 react 开发。

TeamsTookkit

我们打开 index.tsx,看一下代码。

import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
import "./index.css";

ReactDOM.render(<App />, document.getElementById("root"));

可以看到代码极其简单明了,就是一个 <App>,那我们就打开 App.tsx 看看。

import { Provider, teamsTheme } from "@fluentui/react-northstar";
import Privacy from "./Privacy";
import TermsOfUse from "./TermsOfUse";
import Tab from "./Tab";
import TabConfig from "./TabConfig";
import { useTeams } from "msteams-react-base-component";

.........

export default function App() {
  const { theme } = useTeams({})[0];
  return (
    <Provider theme={theme || teamsTheme} styles=>
      <Router>
        <Route exact path="/">
          <Redirect to="/tab" />
        </Route>
          <>
            <Route exact path="/privacy" component={Privacy} />
            <Route exact path="/termsofuse" component={TermsOfUse} />
            <Route exact path="/tab" component={Tab} />
            <Route exact path="/config" component={TabConfig} />
          </>
      </Router>
    </Provider>
  );
}

App.tsx 也算简单,有几个地方需要我们注意的,第一个就是调用了 useTeams() 方法来获取当前的 teams 的theme,teams实际上有几个不同的theme,调用 “msteams-react-base-component” 的 useTeams() 就能够拿到当前的 theme,然后把 theme 设置给了 Provider,在 Router方面则一看就明白,配置了一些路径和对应的 component。

这些路径实际上在 manifest.json 里有用到。我们打开 /build/appPackage/manifest.local.json 文件,我们可以看到:

{
    ...
    "developer": {
        "name": "Teams App, Inc.",
        "websiteUrl": "https://localhost:53000",
        "privacyUrl": "https://localhost:53000/index.html#/privacy",
        "termsOfUseUrl": "https://localhost:53000/index.html#/termsofuse"
    },
    "configurableTabs": [
        {
            "configurationUrl": "https://localhost:53000/index.html#/config",
            "canUpdateConfiguration": true,
            "scopes": [
                "team",
                "groupchat"
            ]
        }
    ],
    "staticTabs": [
        {
            "entityId": "index",
            "name": "Personal Tab",
            "contentUrl": "https://localhost:53000/index.html#/tab",
            "websiteUrl": "https://localhost:53000/index.html#/tab",
            "scopes": [
                "personal"
            ]
        }
    ],
    ....
}

Privacy.tsxTermsOfUse.tsx 非常简单,我们不在展开,我们先来看一下 TabConfig.tsx。简化后的内容如下:

import { app, pages } from "@microsoft/teams-js";

class TabConfig extends React.Component {
  render() {
    app.initialize().then(() => {
      pages.config.registerOnSaveHandler((saveEvent) => {
        const baseUrl = `https://${window.location.hostname}:${window.location.port}`;
        pages.config.setConfig({
          suggestedDisplayName: "My Tab",
          entityId: "Test",
          contentUrl: baseUrl + "/index.html#/tab",
          websiteUrl: baseUrl + "/index.html#/tab",
        }).then(() => {
          saveEvent.notifySuccess();
        });
      });

      pages.config.setValidityState(true);
    });

    return (
      <div>...</div>
    );
  }
}

这个基本是 tab 配置页面的标准写法,调用 app.initialize() 方法,然后注册一个 “Save” buttton 的回调函数,在这个回调函数里,调用 pages.config.setConfig() 函数来告诉 Teams,我们新建的tab的配置,新建的tab 的url是什么。

注册完后,调用了 pages.config.setValidityState(true); 来告诉 Teams,我们的 config 页面已经配置好了,可以让用户来点击 Save 按钮了。这里面有点绕,但如果各位仔细看上面的代码,也不难理解。

我们再来整理一下这个流程:

    app.initialize().then(() => {
      pages.config.registerOnSaveHandler((saveEvent) => { // 注册回调函数,当用户点击 Save 按钮时,这个方法会被触发
        const baseUrl = `https://${window.location.hostname}:${window.location.port}`;
        pages.config.setConfig({  // 告诉 Teams 新建的 tab 的具体情况,比如tab 名字和 url
          suggestedDisplayName: "My Tab",
          entityId: "Test",
          contentUrl: baseUrl + "/index.html#/tab",
          websiteUrl: baseUrl + "/index.html#/tab",
        }).then(() => {
          saveEvent.notifySuccess(); // 告诉 Teams,Save点击事件处理完毕
        });
      });
      pages.config.setValidityState(true); // 告诉 Teams可以允许用户点击 Save 按钮
    });

    return (
      <div>...</div> // 返回 config 页面的 html 内容
    );

*/index.html#/tab 对应到的是 Tab component,对于 Tab 具体页面里基本都是React的一些写法,我这里就不再展开讲 React 开发了,值得一提的是,我们应该尽量使用 fluentuimsteams-react-base-component 库,让使用 React 开发teams tab更加方便,并且风格和teams更加一致。

Written on November 19, 2022