Microsoft Teams Meeting Apps – Lifecycle basics

Microsoft Teams Meeting Apps – Lifecycle basics

Recently I posted a series about my first Microsoft Teams meeting apps sample covering pre-meeting and in-meeting experience. Behind the scenes and technically this was a tab based component while code was mainly acting in the frontend.

Another scenario would be to act on the Teams meeting lifecycle. With that you can trigger some action once a meeting starts or ends. In this post I want to show the very, very basics of this while already having a more concrete sample in mind to which I might comeback here later.

Content

The bot channel

The meeting lifecycle events can be handled by a bot. Therefore a bot channel needs to be setup. I already explained this in earlier posts while handling search based messaging extensions but as this has slightly changed over time, her once again:

  • Go to our Azure portal and Bot Services and click “Create”
  • Pick “Azure Bot”
  • Once again click the “Create” button inside
  • Choose a valid name, subscription and resource group
  • Free pricing tier is sufficient in this experimental phase
  • Either create a Microsoft App ID on your own or let the Bot create it for you
    (In the latter case you will get a secret which will be stored in an own Azure Key Vault, pay attention to clean up if you do not use that)
Create a Bot for Microsoft Teams

Having the bot created, open the resource and under “Channels” add a featured “Teams channel”. Furthermore under Configuration add the following messaging endpoint:

https://xxxxx.ngrok.io/api/messages 

Later the xxxxx will be exchanged by the real given random ngrok url received. Also on the “Configuration” tab click “Manage” beside the Microsoft App ID and generate a new secret and note this down. The App ID and secret are later needed to be filled in the environment variables (or better in app configuration/key vault for enterprise-ready scenarios 👌)

Manage Bot’s App ID

Solution setup

Having the bot channel registered it’s time for the solution. With the yeoman generator for teams a simple bot (only) solution needs to be created:

yo teams for a Teams Meeting Bot

Only a bot is needed for this, nothing else. After the solution is created, two files need to be adapted first.

In the .env file the app id and secret of the bot need to be entered and the HOSTNAME needs to be prepared (will be changed with each new ngrok url as usual while debugging Teams apps)

# The public domain name of where you host your application
PUBLIC_HOSTNAME=xxxxx.ngrok.io

...
# App Id and App Password for the Bot Framework bot
MICROSOFT_APP_ID=79d38cb0-15f9-11ec-9698-cd897c926095
MICROSOFT_APP_PASSWORD=*****

Furthermore in the manifest the following settings are necessary:

  "validDomains": [
    "{{PUBLIC_HOSTNAME}}",
    "token.botframework.com"
  ],
  "webApplicationInfo": {
    "id": "{{MICROSOFT_APP_ID}}",
    "resource": "https://RscPermission",
    "applicationPermissions": [
      "OnlineMeeting.ReadBasic.Chat"
    ]
  }

The webApplicationInfo is to establish permissions to the meeting’s chat as the bot will post it’s activities there.

Implementation

The implementation part is reduced to the bot’s TeamsActivityHandler. And against to what’s coming from yo teams by default it can be even simplified for the small demo purposes here:

@BotDeclaration(
    "/api/messages",
    new MemoryStorage(),
    process.env.MICROSOFT_APP_ID,
    process.env.MICROSOFT_APP_PASSWORD)

export class BotMeetingLifecycle1Bot extends TeamsActivityHandler {
    public constructor(conversationState: ConversationState) {
        super();
    }

    async onEventActivity(context) {
        if (context.activity.type == 'event' && context.activity.name == "application/vnd.microsoft.meetingStart") {
            var meetingObject = context.activity.value;
            await context.sendActivity(`Meeting ${meetingObject.Title} started at ${meetingObject.StartTime}`);
        }
    
        if (context.activity.type == 'event' && context.activity.name == "application/vnd.microsoft.meetingEnd") {
            var meetingObject = context.activity.value;
            await context.sendActivity(`Meeting ${meetingObject.Title} ended at ${meetingObject.EndTime}`);
        }
      };
}

Basically only 2.5 lines need an explanation here. Both if statements detect if it’s either the meetingStart or the meetingEnd event. Inside both if statements first the event payload is accessed and from there the “Title” of the chat/meeting and either the StartTime or the EndTime are picked and send back via sendActivity() in a formatted string only. A simple result would look like this:

A bot posting to the chat on meeting (really) started/ended

Deploy and test

At the time of writing (Sept 2021) the meeting lifecycle events are still in developer preview and might be subject to change. So it’s not recommended for productional use, yet. But to have this working you would first need to enable “Developer Preview” on client basis. This can be achieved by clicking on the three dots (…) next to your account settings in the upper right and from there check About | Developer Preview. Of course this might not be enabled in your enterprise but in a browser accessing your very own dev tenant you should be able to do so.

Enabling Developer Preview in Teams client

To simply test the solution I recommend to fire up two independent NodeJS console windows.

  • In both windows switch to the solution directory (where the gulpfile is located)
  • In one run gulp start-ngrok and copy the given url
    • No minimize that window, it’s not neede actively anymore
  • Paste the url to your .env next to PUBLIC_HOSTNAME=
  • Paste the url in your bot configuration (+ /api/messages)
  • Run gulp manifest in the other (not start-ngrok) NodeJS console
  • Afterwards run gulp serve –debug here
  • Create a meeting in Teams with at least one participant
  • Expand/edit the meeting
  • Click (+) on the upper Tabs
  • Click “Manage Apps”
  • Sideload your just created app package for <your solution directory>\package\*.zip

Once the app is added, “Join” the meeting. Short after you joined you should see a message in the meeting chat. If you leave the meeting afterwards you should see another simple message in the meeting chat.

Our bot posting to the chat on meeting (really) started/ended

This were the very basics on the Microsoft Teams Meeting Lifecycle events. Quite simple, yet, but the basis for great ideas beyond that. As you have a bot of course you could post much richer information with adaptive cards or (in combination with) task modules to which you can add further actions and activities.

I might come back with a more complex but also more realistic idea very soon but still this post and it’s sample will be the base for that. Meanwhile you can have a look at the whole solution in my GitHub repository.

Markus is a SharePoint architect and technical consultant with focus on latest technology stack in Microsoft 365 and SharePoint Online development. He loves the new SharePoint Framework as well as some backend stuff around Azure Automation or Azure Functions and also has a passion for Microsoft Graph.
He works for Avanade as an expert for Microsoft 365 Dev and is based in Munich.
Although if partially inspired by his daily work opinions are always personal.

One thought on “Microsoft Teams Meeting Apps – Lifecycle basics

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s