Condividi tramite


Guida introduttiva: Aggiungere l'app di chat a una riunione di Teams

Iniziare a usare Servizi di comunicazione di Azure connettendo la soluzione di chat a Microsoft Teams.

In questa guida introduttiva si apprenderà come chattare in una riunione di Teams usando Servizi di comunicazione di Azure Chat SDK per JavaScript.

Codice di esempio

Trovare il codice finalizzato per questa guida introduttiva in GitHub.

Prerequisiti

Partecipare alla chat della riunione

Un utente di Servizi di comunicazione può partecipare a una riunione di Teams come utente anonimo usando l'SDK chiamante. Partecipare alla riunione li aggiunge anche come partecipante alla chat della riunione, in cui possono inviare e ricevere messaggi con altri utenti nella riunione. L'utente non avrà accesso ai messaggi di chat inviati prima della riunione e non sarà in grado di inviare o ricevere messaggi dopo la fine della riunione. Per partecipare alla riunione e avviare la chat, è possibile seguire i passaggi successivi.

Creare una nuova applicazione Node.js

Aprire la finestra del terminale o di comando, creare una nuova directory per l'app e passare a tale directory.

mkdir chat-interop-quickstart && cd chat-interop-quickstart

Eseguire npm init -y per creare un file package.json con le impostazioni predefinite.

npm init -y

Installare i pacchetti di chat

Usare il npm install comando per installare gli SDK di Servizi di comunicazione necessari per JavaScript.

npm install @azure/communication-common --save

npm install @azure/communication-identity --save

npm install @azure/communication-chat --save

npm install @azure/communication-calling --save

L'opzione --save elenca la libreria come dipendenza nel file package.json.

Configurare il framework dell'app

Questa guida introduttiva usa Webpack per aggregare gli asset dell'applicazione. Eseguire il comando seguente per installare i pacchetti webpack, webpack-cli e webpack-dev-server npm e elencarli come dipendenze di sviluppo nel package.json:

npm install webpack@5.89.0 webpack-cli@5.1.4 webpack-dev-server@4.15.1 --save-dev

Creare un file index.html nella directory radice del progetto. Questo file viene usato per configurare un layout di base che consentirà all'utente di partecipare a una riunione e di avviare la chat.

Aggiungere i controlli dell'interfaccia utente di Teams

Sostituire il codice in index.html con il frammento di codice seguente. La casella di testo nella parte superiore della pagina verrà usata per immettere il contesto della riunione di Teams. Il pulsante "Partecipa alla riunione di Teams" viene usato per partecipare alla riunione specificata. Viene visualizzato un popup di chat nella parte inferiore della pagina. Può essere usato per inviare messaggi nel thread della riunione e visualizza in tempo reale tutti i messaggi inviati sul thread mentre l'utente di Servizi di comunicazione è membro.

<!DOCTYPE html>
<html>
   <head>
      <title>Communication Client - Calling and Chat Sample</title>
      <style>
         body {box-sizing: border-box;}
         /* The popup chat - hidden by default */
         .chat-popup {
         display: none;
         position: fixed;
         bottom: 0;
         left: 15px;
         border: 3px solid #f1f1f1;
         z-index: 9;
         }
         .message-box {
         display: none;
         position: fixed;
         bottom: 0;
         left: 15px;
         border: 3px solid #FFFACD;
         z-index: 9;
         }
         .form-container {
         max-width: 300px;
         padding: 10px;
         background-color: white;
         }
         .form-container textarea {
         width: 90%;
         padding: 15px;
         margin: 5px 0 22px 0;
         border: none;
         background: #e1e1e1;
         resize: none;
         min-height: 50px;
         }
         .form-container .btn {
         background-color: #4CAF40;
         color: white;
         padding: 14px 18px;
         margin-bottom:10px;
         opacity: 0.6;
         border: none;
         cursor: pointer;
         width: 100%;
         }
         .container {
         border: 1px solid #dedede;
         background-color: #F1F1F1;
         border-radius: 3px;
         padding: 8px;
         margin: 8px 0;
         }
         .darker {
         border-color: #ccc;
         background-color: #ffdab9;
         margin-left: 25px;
         margin-right: 3px;
         }
         .lighter {
         margin-right: 20px;
         margin-left: 3px;
         }
         .container::after {
         content: "";
         clear: both;
         display: table;
         }
      </style>
   </head>
   <body>
      <h4>Azure Communication Services</h4>
      <h1>Calling and Chat Quickstart</h1>
          <input id="teams-link-input" type="text" placeholder="Teams meeting link"
        style="margin-bottom:1em; width: 400px;" />
        <p>Call state <span style="font-weight: bold" id="call-state">-</span></p>
      <div>
        <button id="join-meeting-button" type="button">
            Join Teams Meeting
        </button>
        <button id="hang-up-button" type="button" disabled="true">
            Hang Up
        </button>
      </div>
      <div class="chat-popup" id="chat-box">
         <div id="messages-container"></div>
         <form class="form-container">
            <textarea placeholder="Type message.." name="msg" id="message-box" required></textarea>
            <button type="button" class="btn" id="send-message">Send</button>
         </form>
      </div>
      <script src="./bundle.js"></script>
   </body>
</html>

Abilitare i controlli dell'interfaccia utente di Teams

Sostituire il contenuto del file client.js con il frammento di codice seguente.

All'interno del frammento di codice sostituire

  • SECRET_CONNECTION_STRINGcon la stringa di connessione del servizio di comunicazione
import { CallClient } from "@azure/communication-calling";
import { AzureCommunicationTokenCredential } from "@azure/communication-common";
import { CommunicationIdentityClient } from "@azure/communication-identity";
import { ChatClient } from "@azure/communication-chat";

let call;
let callAgent;
let chatClient;
let chatThreadClient;

const meetingLinkInput = document.getElementById("teams-link-input");
const callButton = document.getElementById("join-meeting-button");
const hangUpButton = document.getElementById("hang-up-button");
const callStateElement = document.getElementById("call-state");

const messagesContainer = document.getElementById("messages-container");
const chatBox = document.getElementById("chat-box");
const sendMessageButton = document.getElementById("send-message");
const messageBox = document.getElementById("message-box");

var userId = "";
var messages = "";
var chatThreadId = "";

async function init() {
  const connectionString = "<SECRET_CONNECTION_STRING>";
  const endpointUrl = connectionString.split(";")[0].replace("endpoint=", "");

  const identityClient = new CommunicationIdentityClient(connectionString);

  let identityResponse = await identityClient.createUser();
  userId = identityResponse.communicationUserId;
  console.log(`\nCreated an identity with ID: ${identityResponse.communicationUserId}`);

  let tokenResponse = await identityClient.getToken(identityResponse, ["voip", "chat"]);

  const { token, expiresOn } = tokenResponse;
  console.log(`\nIssued an access token that expires at: ${expiresOn}`);
  console.log(token);

  const callClient = new CallClient();
  const tokenCredential = new AzureCommunicationTokenCredential(token);

  callAgent = await callClient.createCallAgent(tokenCredential);
  callButton.disabled = false;
  chatClient = new ChatClient(endpointUrl, new AzureCommunicationTokenCredential(token));

  console.log("Azure Communication Chat client created!");
}

init();

const joinCall = (urlString, callAgent) => {
  const url = new URL(urlString);
  console.log(url);
  if (url.pathname.startsWith("/meet")) {
    // Short teams URL, so for now call meetingID and pass code API
    return callAgent.join({
      meetingId: url.pathname.split("/").pop(),
      passcode: url.searchParams.get("p"),
    });
  } else {
    return callAgent.join({ meetingLink: urlString }, {});
  }
};

callButton.addEventListener("click", async () => {
  // join with meeting link
  try {
    call = joinCall(meetingLinkInput.value, callAgent);
  } catch {
    throw new Error("Could not join meeting - have you set your connection string?");
  }

  // Chat thread ID is provided from the call info, after connection.
  call.on("stateChanged", async () => {
    callStateElement.innerText = call.state;

    if (call.state === "Connected" && !chatThreadClient) {
      chatThreadId = call.info?.threadId;
      chatThreadClient = chatClient.getChatThreadClient(chatThreadId);

      chatBox.style.display = "block";
      messagesContainer.innerHTML = messages;

      // open notifications channel
      await chatClient.startRealtimeNotifications();

      // subscribe to new message notifications
      chatClient.on("chatMessageReceived", (e) => {
        console.log("Notification chatMessageReceived!");

        // check whether the notification is intended for the current thread
        if (chatThreadId != e.threadId) {
          return;
        }

        if (e.sender.communicationUserId != userId) {
          renderReceivedMessage(e.message);
        } else {
          renderSentMessage(e.message);
        }
      });
    }
  });

  // toggle button and chat box states
  hangUpButton.disabled = false;
  callButton.disabled = true;

  console.log(call);
});

async function renderReceivedMessage(message) {
  messages += '<div class="container lighter">' + message + "</div>";
  messagesContainer.innerHTML = messages;
}

async function renderSentMessage(message) {
  messages += '<div class="container darker">' + message + "</div>";
  messagesContainer.innerHTML = messages;
}

hangUpButton.addEventListener("click", async () => {
  // end the current call
  await call.hangUp();
  // Stop notifications
  chatClient.stopRealtimeNotifications();

  // toggle button states
  hangUpButton.disabled = true;
  callButton.disabled = false;
  callStateElement.innerText = "-";

  // toggle chat states
  chatBox.style.display = "none";
  messages = "";
  // Remove local ref
  chatThreadClient = undefined;
});

sendMessageButton.addEventListener("click", async () => {
  let message = messageBox.value;

  let sendMessageRequest = { content: message };
  let sendMessageOptions = { senderDisplayName: "Jack" };
  let sendChatMessageResult = await chatThreadClient.sendMessage(
    sendMessageRequest,
    sendMessageOptions
  );
  let messageId = sendChatMessageResult.id;

  messageBox.value = "";
  console.log(`Message sent!, message id:${messageId}`);
});

I nomi visualizzati dei partecipanti al thread di chat non vengono impostati dal client teams. I nomi vengono restituiti come Null nell'API per elencare i partecipanti, nell'evento participantsAdded e nell'evento participantsRemoved . I nomi visualizzati dei partecipanti alla chat possono essere recuperati dal remoteParticipants campo dell'oggetto call . Quando si riceve una notifica relativa a una modifica del roster, è possibile usare questo codice per recuperare il nome dell'utente aggiunto o rimosso:

var displayName = call.remoteParticipants.find(p => p.identifier.communicationUserId == '<REMOTE_USER_ID>').displayName;

Eseguire il codice

Gli utenti di Webpack possono usare webpack-dev-server per compilare ed eseguire l'app. Eseguire il comando seguente per aggregare l'host dell'applicazione in un server Web locale:

npx webpack-dev-server --entry ./client.js --output bundle.js --debug --devtool inline-source-map

Aprire il browser e passare a http://localhost:8080/. Verrà visualizzata l'app avviata come illustrato nello screenshot seguente:

Screenshot dell'applicazione JavaScript completata.

Inserire il collegamento alla riunione di Teams nella casella di testo. Premere Partecipa alla riunione di Teams per partecipare alla riunione di Teams. Dopo che l'utente di Servizi di comunicazione è stato ammesso alla riunione, è possibile chattare dall'interno dell'applicazione servizi di comunicazione. Passare alla casella nella parte inferiore della pagina per iniziare a chattare. Per semplicità, l'applicazione mostra solo gli ultimi due messaggi nella chat.

Nota

Alcune funzionalità non sono attualmente supportate per gli scenari di interoperabilità con Teams. Altre informazioni sulle funzionalità supportate, vedere Funzionalità delle riunioni di Teams per gli utenti esterni di Teams

In questa guida introduttiva si apprenderà come chattare in una riunione di Teams usando Servizi di comunicazione di Azure Chat SDK per iOS.

Codice di esempio

Se si vuole passare direttamente alla fine, è possibile scaricare questa guida introduttiva come esempio in GitHub.

Prerequisiti

  • Un account Azure con una sottoscrizione attiva. Creare un account gratuitamente
  • Un Mac che esegue Xcode, insieme a un certificato dello sviluppatore valido installato nel portachiavi.
  • Una distribuzione di Teams.
  • Un token di accesso utente per il servizio di comunicazione di Azure. È anche possibile usare l'interfaccia della riga di comando di Azure ed eseguire il comando con il stringa di connessione per creare un utente e un token di accesso.
az communication identity token issue --scope voip --connection-string "yourConnectionString"

Per informazioni dettagliate, vedere Usare l'interfaccia della riga di comando di Azure per creare e gestire i token di accesso.

Configurazione

Creazione del progetto Xcode

In Xcode creare un nuovo progetto iOS e selezionare il modello Single View Application. Questa esercitazione usa il framework SwiftUI, quindi è necessario impostare Il linguaggio su Swift e l'interfaccia utente su SwiftUI. In questo argomento di avvio rapido non verranno creati test. È possibile deselezionare Includi test.

Screenshot che mostra la finestra relativa al nuovo progetto in Xcode.

Installazione di CocoaPods

Usare questa guida per installare CocoaPods nel Mac.

Installare il pacchetto e le dipendenze con CocoaPods

  1. Per creare un Podfile oggetto per l'applicazione, aprire il terminale e passare alla cartella del progetto ed eseguire pod init.

  2. Aggiungere il codice seguente a Podfile sotto la destinazione e salvare.

target 'Chat Teams Interop' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for Chat Teams Interop
  pod 'AzureCommunicationCalling'
  pod 'AzureCommunicationChat'
  
end
  1. Eseguire pod install.

  2. Aprire il .xcworkspace file con Xcode.

Richiedere l'accesso al microfono

Per accedere al microfono del dispositivo, è necessario aggiornare il file Information Property List dell'app con NSMicrophoneUsageDescription. Il valore associato è stato impostato su un string oggetto incluso nella finestra di dialogo utilizzata dal sistema per richiedere l'accesso all'utente.

Nella destinazione selezionare la Info scheda e aggiungere una stringa per "Privacy - Descrizione utilizzo microfono"

Screenshot che mostra l'aggiunta dell'utilizzo del microfono in Xcode.

Disabilitare la sandbox degli script utente

Alcuni degli script all'interno delle librerie collegate scrivono file durante il processo di compilazione. Per consentire questa operazione, disabilitare il sandboxing di script utente in Xcode. Nelle impostazioni di compilazione cercare sandbox e impostare su User Script Sandboxing No.

Screenshot che mostra la disabilitazione della sandbox degli script utente in Xcode.

Partecipare alla chat della riunione

Un utente di Servizi di comunicazione può partecipare a una riunione di Teams come utente anonimo usando l'SDK chiamante. Una volta che un utente ha partecipato alla riunione di Teams, può inviare e ricevere messaggi con altri partecipanti alla riunione. L'utente non avrà accesso ai messaggi di chat inviati prima di partecipare, né sarà in grado di inviare o ricevere messaggi quando non si trovano nella riunione. Per partecipare alla riunione e avviare la chat, è possibile seguire i passaggi successivi.

Configurare il framework dell'app

Importare i pacchetti di comunicazione di Azure in ContentView.swift aggiungendo il frammento di codice seguente:

import AVFoundation
import SwiftUI

import AzureCommunicationCalling
import AzureCommunicationChat

Aggiungere ContentView.swift il frammento di codice seguente, appena sopra la struct ContentView: View dichiarazione:

let endpoint = "<ADD_YOUR_ENDPOINT_URL_HERE>"
let token = "<ADD_YOUR_USER_TOKEN_HERE>"
let displayName: String = "Quickstart User"

Sostituire <ADD_YOUR_ENDPOINT_URL_HERE> con l'endpoint per la risorsa di Servizi di comunicazione. Sostituire <ADD_YOUR_USER_TOKEN_HERE> con il token generato in precedenza, tramite la riga di comando del client di Azure. Altre informazioni sui token di accesso utente: Token di accesso utente

Sostituire Quickstart User con il nome visualizzato che si vuole usare nella chat.

Per mantenere lo stato, aggiungere le variabili seguenti allo ContentView struct:

  @State var message: String = ""
  @State var meetingLink: String = ""
  @State var chatThreadId: String = ""

  // Calling state
  @State var callClient: CallClient?
  @State var callObserver: CallDelegate?
  @State var callAgent: CallAgent?
  @State var call: Call?

  // Chat state
  @State var chatClient: ChatClient?
  @State var chatThreadClient: ChatThreadClient?
  @State var chatMessage: String = ""
  @State var meetingMessages: [MeetingMessage] = []

Aggiungere ora il corpo principale var per contenere gli elementi dell'interfaccia utente. In questa guida introduttiva viene associata la logica di business a questi controlli. Aggiungere il codice seguente allo ContentView struct :

var body: some View {
    NavigationView {
      Form {
        Section {
          TextField("Teams Meeting URL", text: $meetingLink)
            .onChange(of: self.meetingLink, perform: { value in
              if let threadIdFromMeetingLink = getThreadId(from: value) {
                self.chatThreadId = threadIdFromMeetingLink
              }
            })
          TextField("Chat thread ID", text: $chatThreadId)
        }
        Section {
          HStack {
            Button(action: joinMeeting) {
              Text("Join Meeting")
            }.disabled(
              chatThreadId.isEmpty || callAgent == nil || call != nil
            )
            Spacer()
            Button(action: leaveMeeting) {
              Text("Leave Meeting")
            }.disabled(call == nil)
          }
          Text(message)
        }
        Section {
          ForEach(meetingMessages, id: \.id) { message in
            let currentUser: Bool = (message.displayName == displayName)
            let foregroundColor = currentUser ? Color.white : Color.black
            let background = currentUser ? Color.blue : Color(.systemGray6)
            let alignment = currentUser ? HorizontalAlignment.trailing : .leading
            
            HStack {
              if currentUser {
                Spacer()
              }
              VStack(alignment: alignment) {
                Text(message.displayName).font(Font.system(size: 10))
                Text(message.content)
                  .frame(maxWidth: 200)
              }

              .padding(8)
              .foregroundColor(foregroundColor)
              .background(background)
              .cornerRadius(8)

              if !currentUser {
                Spacer()
              }
            }
          }
          .frame(maxWidth: .infinity)
        }

        TextField("Enter your message...", text: $chatMessage)
        Button(action: sendMessage) {
          Text("Send Message")
        }.disabled(chatThreadClient == nil)
      }

      .navigationBarTitle("Teams Chat Interop")
    }

    .onAppear {
      // Handle initialization of the call and chat clients
    }
  }

Inizializzare ChatClient

Creare un'istanza di e abilitare le notifiche dei ChatClient messaggi. Si usano notifiche in tempo reale per la ricezione di messaggi di chat.

Dopo aver configurato il corpo principale, aggiungere le funzioni per gestire la configurazione dei client di chiamata e chat.

onAppear Nella funzione aggiungere il codice seguente per inizializzare CallClient e ChatClient:

  if let threadIdFromMeetingLink = getThreadId(from: self.meetingLink) {
    self.chatThreadId = threadIdFromMeetingLink
  }
  // Authenticate
  do {
    let credentials = try CommunicationTokenCredential(token: token)
    self.callClient = CallClient()
    self.callClient?.createCallAgent(
      userCredential: credentials
    ) { agent, error in
      if let e = error {
        self.message = "ERROR: It was not possible to create a call agent."
        print(e)
        return
      } else {
        self.callAgent = agent
      }
    }
  
    // Start the chat client
    self.chatClient = try ChatClient(
      endpoint: endpoint,
      credential: credentials,
      withOptions: AzureCommunicationChatClientOptions()
    )
    // Register for real-time notifications
    self.chatClient?.startRealTimeNotifications { result in
      switch result {
      case .success:
        self.chatClient?.register(
          event: .chatMessageReceived,
          handler: receiveMessage
      )
      case let .failure(error):
        self.message = "Could not register for message notifications: " + error.localizedDescription
        print(error)
      }
    }
  } catch {
    print(error)
    self.message = error.localizedDescription
  }

Aggiungere la funzione di partecipazione alla riunione

Aggiungere la funzione seguente allo ContentView struct per gestire la partecipazione alla riunione.

  func joinMeeting() {
    // Ask permissions
    AVAudioSession.sharedInstance().requestRecordPermission { (granted) in
      if granted {
        let teamsMeetingLink = TeamsMeetingLinkLocator(
          meetingLink: self.meetingLink
        )
        self.callAgent?.join(
          with: teamsMeetingLink,
          joinCallOptions: JoinCallOptions()
        ) {(call, error) in
          if let e = error {
            self.message = "Failed to join call: " + e.localizedDescription
            print(e.localizedDescription)
            return
          }

          self.call = call
          self.callObserver = CallObserver(self)
          self.call?.delegate = self.callObserver
          self.message = "Teams meeting joined successfully"
        }
      } else {
        self.message = "Not authorized to use mic"
      }
    }
  }

Inizializzare ChatThreadClient

Verrà inizializzato dopo ChatThreadClient che l'utente ha partecipato alla riunione. È quindi necessario controllare lo stato della riunione dal delegato e quindi inizializzare con l'oggetto ChatThreadClient threadId quando si partecipa alla riunione.

Creare la connectChat() funzione con il codice seguente:

  func connectChat() {
    do {
      self.chatThreadClient = try chatClient?.createClient(
        forThread: self.chatThreadId
      )
      self.message = "Joined meeting chat successfully"
    } catch {
      self.message = "Failed to join the chat thread: " + error.localizedDescription
    }
  }

Aggiungere la funzione helper seguente a ContentView, usata per analizzare l'ID del thread chat dal collegamento alla riunione del team, se possibile. Nel caso in cui l'estrazione non riesca, l'utente dovrà immettere manualmente l'ID del thread di Chat usando le API Graph per recuperare l'ID del thread.

 func getThreadId(from teamsMeetingLink: String) -> String? {
  if let range = teamsMeetingLink.range(of: "meetup-join/") {
    let thread = teamsMeetingLink[range.upperBound...]
    if let endRange = thread.range(of: "/")?.lowerBound {
      return String(thread.prefix(upTo: endRange))
    }
  }
  return nil
}

Abilitare l'invio di messaggi

Aggiungere la sendMessage() funzione a ContentView. Questa funzione usa per ChatThreadClient inviare messaggi dall'utente.

func sendMessage() {
  let message = SendChatMessageRequest(
    content: self.chatMessage,
    senderDisplayName: displayName,
    type: .text
  )

  self.chatThreadClient?.send(message: message) { result, _ in
    switch result {
    case .success:
    print("Chat message sent")
    self.chatMessage = ""

    case let .failure(error):
    self.message = "Failed to send message: " + error.localizedDescription + "\n Has your token expired?"
    }
  }
}

Abilitare la ricezione di messaggi

Per ricevere messaggi, implementiamo il gestore per ChatMessageReceived gli eventi. Quando vengono inviati nuovi messaggi al thread, questo gestore aggiunge i messaggi alla meetingMessages variabile in modo che possano essere visualizzati nell'interfaccia utente.

Aggiungere prima di tutto lo struct seguente a ContentView.swift. L'interfaccia utente usa i dati nello struct per visualizzare i messaggi di Chat.

struct MeetingMessage: Identifiable {
  let id: String
  let date: Date
  let content: String
  let displayName: String

  static func fromTrouter(event: ChatMessageReceivedEvent) -> MeetingMessage {
    let displayName: String = event.senderDisplayName ?? "Unknown User"
    let content: String = event.message.replacingOccurrences(
      of: "<[^>]+>", with: "",
      options: String.CompareOptions.regularExpression
    )
    return MeetingMessage(
      id: event.id,
      date: event.createdOn?.value ?? Date(),
      content: content,
      displayName: displayName
    )
  }
}

Aggiungere quindi la receiveMessage() funzione a ContentView. Questo metodo viene chiamato quando si verifica un evento di messaggistica. Si noti che è necessario eseguire la registrazione per tutti gli eventi che si desidera gestire nell'istruzione switch tramite il chatClient?.register() metodo .

  func receiveMessage(event: TrouterEvent) -> Void {
    switch event {
    case let .chatMessageReceivedEvent(messageEvent):
      let message = MeetingMessage.fromTrouter(event: messageEvent)
      self.meetingMessages.append(message)

      /// OTHER EVENTS
      //    case .realTimeNotificationConnected:
      //    case .realTimeNotificationDisconnected:
      //    case .typingIndicatorReceived(_):
      //    case .readReceiptReceived(_):
      //    case .chatMessageEdited(_):
      //    case .chatMessageDeleted(_):
      //    case .chatThreadCreated(_):
      //    case .chatThreadPropertiesUpdated(_):
      //    case .chatThreadDeleted(_):
      //    case .participantsAdded(_):
      //    case .participantsRemoved(_):

    default:
      break
    }
  }

Infine, è necessario implementare il gestore delegato per il client di chiamata. Questo gestore viene usato per controllare lo stato della chiamata e inizializzare il client di chat quando l'utente partecipa alla riunione.

class CallObserver : NSObject, CallDelegate {
  private var owner: ContentView

  init(_ view: ContentView) {
    owner = view
  }

  func call(
    _ call: Call,
    didChangeState args: PropertyChangedEventArgs
  ) {
    owner.message = CallObserver.callStateToString(state: call.state)
    if call.state == .disconnected {
      owner.call = nil
      owner.message = "Left Meeting"
    } else if call.state == .inLobby {
      owner.message = "Waiting in lobby (go let them in!)"
    } else if call.state == .connected {
      owner.message = "Connected"
      owner.connectChat()
    }
  }

  private static func callStateToString(state: CallState) -> String {
    switch state {
    case .connected: return "Connected"
    case .connecting: return "Connecting"
    case .disconnected: return "Disconnected"
    case .disconnecting: return "Disconnecting"
    case .earlyMedia: return "EarlyMedia"
    case .none: return "None"
    case .ringing: return "Ringing"
    case .inLobby: return "InLobby"
    default: return "Unknown"
    }
  }
}

Lasciare la chat

Quando l'utente lascia la riunione del team, si cancellano i messaggi di chat dall'interfaccia utente e si blocca la chiamata. Di seguito è riportato il codice completo.

  func leaveMeeting() {
    if let call = self.call {
      self.chatClient?.unregister(event: .chatMessageReceived)
      self.chatClient?.stopRealTimeNotifications()

      call.hangUp(options: nil) { (error) in
        if let e = error {
          self.message = "Leaving Teams meeting failed: " + e.localizedDescription
        } else {
          self.message = "Leaving Teams meeting was successful"
        }
      }
      self.meetingMessages.removeAll()
    } else {
      self.message = "No active call to hangup"
    }
  }

Ottenere un thread di chat della riunione di Teams per un utente di Servizi di comunicazione

I dettagli delle riunioni di Teams possono essere recuperati usando le API Graph, descritte in dettaglio nella documentazione di Graph. Communication Services Calling SDK accetta un collegamento completo alla riunione di Teams o un ID riunione. Vengono restituiti come parte della onlineMeeting risorsa, accessibili nella joinWebUrl proprietà

Con le API Graph è anche possibile ottenere .threadID La risposta ha un chatInfo oggetto che contiene l'oggetto threadID.

Eseguire il codice

Eseguire l'applicazione.

Per partecipare alla riunione di Teams, immettere il collegamento alla riunione del team nell'interfaccia utente.

Dopo aver eseguito la riunione del team, è necessario ammettere l'utente alla riunione nel client del team. Dopo che l'utente è stato ammesso e ha partecipato alla chat, è possibile inviare e ricevere messaggi.

Screenshot dell'applicazione iOS completata.

Nota

Alcune funzionalità non sono attualmente supportate per gli scenari di interoperabilità con Teams. Altre informazioni sulle funzionalità supportate, vedere Funzionalità delle riunioni di Teams per gli utenti esterni di Teams

In questa guida introduttiva si apprenderà come chattare in una riunione di Teams usando Servizi di comunicazione di Azure Chat SDK per Android.

Codice di esempio

Se si vuole passare direttamente alla fine, è possibile scaricare questa guida introduttiva come esempio in GitHub.

Prerequisiti

Abilitare l'interoperabilità di Teams

Un utente di Servizi di comunicazione che partecipa a una riunione di Teams come utente guest può accedere alla chat della riunione solo dopo essere stato aggiunto alla chiamata della riunione di Teams. Per informazioni su come aggiungere un utente di Servizi di comunicazione a una chiamata di riunione di Teams, vedere la documentazione sull'interoperabilità di Teams.

Per usare questa funzionalità, è necessario essere un membro dell'organizzazione proprietaria di entrambe le entità.

Partecipare alla chat della riunione

Dopo aver abilitato l'interoperabilità di Teams, un utente di Servizi di comunicazione può partecipare alla chiamata di Teams come utente esterno usando l'SDK chiamante. Partecipare alla chiamata li aggiunge anche come partecipante alla chat della riunione, in cui possono inviare e ricevere messaggi con altri utenti nella chiamata. L'utente non ha accesso ai messaggi di chat inviati prima di essere aggiunti alla chiamata. Per partecipare alla riunione e avviare la chat, è possibile seguire i passaggi successivi.

Aggiungere chat all'app per chiamate di Teams

Nel livello build.gradledel modulo aggiungere la dipendenza dall'SDK della chat.

Importante

Problema noto: quando si usa Android Chat e Calling SDK insieme nella stessa applicazione, la funzionalità di notifiche in tempo reale di Chat SDK non funzionerà. Si otterrà un problema di risoluzione delle dipendenze. Mentre si sta lavorando a una soluzione, è possibile disattivare la funzionalità delle notifiche in tempo reale aggiungendo le esclusioni seguenti alla dipendenza di Chat SDK nel file dell'app build.gradle :

implementation ("com.azure.android:azure-communication-chat:2.0.3") {
    exclude group: 'com.microsoft', module: 'trouter-client-android'
}

Aggiungere il layout dell'interfaccia utente di Teams

Sostituire il codice in activity_main.xml con il frammento di codice seguente. Aggiunge input per l'ID thread e per l'invio di messaggi, un pulsante per l'invio del messaggio tipizzato e un layout di chat di base.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/teams_meeting_thread_id"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="20dp"
        android:layout_marginTop="128dp"
        android:ems="10"
        android:hint="Meeting Thread Id"
        android:inputType="textUri"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/teams_meeting_link"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="20dp"
        android:layout_marginTop="64dp"
        android:ems="10"
        android:hint="Teams meeting link"
        android:inputType="textUri"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:id="@+id/button_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:gravity="center"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/teams_meeting_thread_id">

        <Button
            android:id="@+id/join_meeting_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Join Meeting" />

        <Button
            android:id="@+id/hangup_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hangup" />

    </LinearLayout>

    <TextView
        android:id="@+id/call_status_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="40dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <TextView
        android:id="@+id/recording_status_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <ScrollView
        android:id="@+id/chat_box"
        android:layout_width="374dp"
        android:layout_height="294dp"
        android:layout_marginTop="40dp"
        android:layout_marginBottom="20dp"
        app:layout_constraintBottom_toTopOf="@+id/send_message_button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button_layout"
        android:orientation="vertical"
        android:gravity="bottom"
        android:layout_gravity="bottom"
        android:fillViewport="true">

        <LinearLayout
            android:id="@+id/chat_box_layout"
            android:orientation="vertical"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:gravity="bottom"
            android:layout_gravity="top"
            android:layout_alignParentBottom="true"/>
    </ScrollView>

    <EditText
        android:id="@+id/message_body"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="20dp"
        android:layout_marginTop="588dp"
        android:ems="10"
        android:inputType="textUri"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Type your message here..."
        tools:visibility="invisible" />

    <Button
        android:id="@+id/send_message_button"
        android:layout_width="138dp"
        android:layout_height="45dp"
        android:layout_marginStart="133dp"
        android:layout_marginTop="48dp"
        android:layout_marginEnd="133dp"
        android:text="Send Message"
        android:visibility="invisible"
        app:layout_constraintBottom_toTopOf="@+id/recording_status_bar"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.428"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/chat_box" />

</androidx.constraintlayout.widget.ConstraintLayout>

Abilitare i controlli dell'interfaccia utente di Teams

Importare pacchetti e definire le variabili di stato

Nel contenuto di MainActivity.javaaggiungere le importazioni seguenti:

import android.graphics.Typeface;
import android.graphics.Color;
import android.text.Html;
import android.os.Handler;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.List;
import com.azure.android.communication.chat.ChatThreadAsyncClient;
import com.azure.android.communication.chat.ChatThreadClientBuilder;
import com.azure.android.communication.chat.models.ChatMessage;
import com.azure.android.communication.chat.models.ChatMessageType;
import com.azure.android.communication.chat.models.ChatParticipant;
import com.azure.android.communication.chat.models.ListChatMessagesOptions;
import com.azure.android.communication.chat.models.SendChatMessageOptions;
import com.azure.android.communication.common.CommunicationIdentifier;
import com.azure.android.communication.common.CommunicationUserIdentifier;
import com.azure.android.core.rest.util.paging.PagedAsyncStream;
import com.azure.android.core.util.AsyncStreamHandler;

Per la MainActivity classe aggiungere le variabili seguenti:

    // InitiatorId is used to differentiate incoming messages from outgoing messages
    private static final String InitiatorId = "<USER_ID>";
    private static final String ResourceUrl = "<COMMUNICATION_SERVICES_RESOURCE_ENDPOINT>";
    private String threadId;
    private ChatThreadAsyncClient chatThreadAsyncClient;
    
    // The list of ids corresponsding to messages which have already been processed
    ArrayList<String> chatMessages = new ArrayList<>();

Sostituire <USER_ID> con l'ID dell'utente che avvia la chat. Sostituire <COMMUNICATION_SERVICES_RESOURCE_ENDPOINT> con l'endpoint per la risorsa di Servizi di comunicazione.

Inizializzare ChatThreadClient

Dopo aver eseguito la riunione, creare un'istanza di ChatThreadClient e rendere visibili i componenti della chat.

Aggiornare la fine del MainActivity.joinTeamsMeeting() metodo con il codice seguente:

    private void joinTeamsMeeting() {
        ...
        EditText threadIdView = findViewById(R.id.teams_meeting_thread_id);
        threadId = threadIdView.getText().toString();
        // Initialize Chat Thread Client
        chatThreadAsyncClient = new ChatThreadClientBuilder()
                .endpoint(ResourceUrl)
                .credential(new CommunicationTokenCredential(UserToken))
                .chatThreadId(threadId)
                .buildAsyncClient();
        Button sendMessageButton = findViewById(R.id.send_message_button);
        EditText messageBody = findViewById(R.id.message_body);
        // Register the method for sending messages and toggle the visibility of chat components
        sendMessageButton.setOnClickListener(l -> sendMessage());
        sendMessageButton.setVisibility(View.VISIBLE);
        messageBody.setVisibility(View.VISIBLE);
        
        // Start the polling for chat messages immediately
        handler.post(runnable);
    }

Abilitare l'invio di messaggi

Aggiungere il sendMessage() metodo a MainActivity. Usa per ChatThreadClient inviare messaggi per conto dell'utente.

    private void sendMessage() {
        // Retrieve the typed message content
        EditText messageBody = findViewById(R.id.message_body);
        // Set request options and send message
        SendChatMessageOptions options = new SendChatMessageOptions();
        options.setContent(messageBody.getText().toString());
        options.setSenderDisplayName("Test User");
        chatThreadAsyncClient.sendMessage(options);
        // Clear the text box
        messageBody.setText("");
    }

Abilitare il polling per i messaggi e eseguirne il rendering nell'applicazione

Importante

Problema noto: poiché la funzionalità di notifiche in tempo reale di Chat SDK non funziona con l'SDK chiamante, è necessario eseguire il polling dell'API GetMessages a intervalli predefiniti. Nell'esempio verranno usati intervalli di 3 secondi.

È possibile ottenere i dati seguenti dall'elenco dei messaggi restituiti dall'API GetMessages :

  • Messaggi text e html nel thread dopo l'aggiunta
  • Modifiche all'elenco di thread
  • Aggiornamenti all'argomento thread

MainActivity Alla classe aggiungere un gestore e un'attività eseguibile che verrà eseguita a intervalli di 3 secondi:

    private Handler handler = new Handler();
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                retrieveMessages();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // Repeat every 3 seconds
            handler.postDelayed(runnable, 3000);
        }
    };

Si noti che l'attività è già stata avviata alla fine del MainActivity.joinTeamsMeeting() metodo aggiornato nel passaggio di inizializzazione.

Infine, si aggiunge il metodo per eseguire query su tutti i messaggi accessibili nel thread, analizzandoli in base al tipo di messaggio e visualizzandoli html text :

    private void retrieveMessages() throws InterruptedException {
        // Initialize the list of messages not yet processed
        ArrayList<ChatMessage> newChatMessages = new ArrayList<>();
        
        // Retrieve all messages accessible to the user
        PagedAsyncStream<ChatMessage> messagePagedAsyncStream
                = this.chatThreadAsyncClient.listMessages(new ListChatMessagesOptions(), null);
        // Set up a lock to wait until all returned messages have been inspected
        CountDownLatch latch = new CountDownLatch(1);
        // Traverse the returned messages
        messagePagedAsyncStream.forEach(new AsyncStreamHandler<ChatMessage>() {
            @Override
            public void onNext(ChatMessage message) {
                // Messages that should be displayed in the chat
                if ((message.getType().equals(ChatMessageType.TEXT)
                    || message.getType().equals(ChatMessageType.HTML))
                    && !chatMessages.contains(message.getId())) {
                    newChatMessages.add(message);
                    chatMessages.add(message.getId());
                }
                if (message.getType().equals(ChatMessageType.PARTICIPANT_ADDED)) {
                    // Handle participants added to chat operation
                    List<ChatParticipant> participantsAdded = message.getContent().getParticipants();
                    CommunicationIdentifier participantsAddedBy = message.getContent().getInitiatorCommunicationIdentifier();
                }
                if (message.getType().equals(ChatMessageType.PARTICIPANT_REMOVED)) {
                    // Handle participants removed from chat operation
                    List<ChatParticipant> participantsRemoved = message.getContent().getParticipants();
                    CommunicationIdentifier participantsRemovedBy = message.getContent().getInitiatorCommunicationIdentifier();
                }
                if (message.getType().equals(ChatMessageType.TOPIC_UPDATED)) {
                    // Handle topic updated
                    String newTopic = message.getContent().getTopic();
                    CommunicationIdentifier topicUpdatedBy = message.getContent().getInitiatorCommunicationIdentifier();
                }
            }
            @Override
            public void onError(Throwable throwable) {
                latch.countDown();
            }
            @Override
            public void onComplete() {
                latch.countDown();
            }
        });
        // Wait until the operation completes
        latch.await(1, TimeUnit.MINUTES);
        // Returned messages should be ordered by the createdOn field to be guaranteed a proper chronological order
        // For the purpose of this demo we will just reverse the list of returned messages
        Collections.reverse(newChatMessages);
        for (ChatMessage chatMessage : newChatMessages)
        {
            LinearLayout chatBoxLayout = findViewById(R.id.chat_box_layout);
            // For the purpose of this demo UI, we don't need to use HTML formatting for displaying messages
            // The Teams client always sends html messages in meeting chats 
            String message = Html.fromHtml(chatMessage.getContent().getMessage(), Html.FROM_HTML_MODE_LEGACY).toString().trim();
            TextView messageView = new TextView(this);
            messageView.setText(message);
            // Compare with sender identifier and align LEFT/RIGHT accordingly
            // Azure Communication Services users are of type CommunicationUserIdentifier
            CommunicationIdentifier senderId = chatMessage.getSenderCommunicationIdentifier();
            if (senderId instanceof CommunicationUserIdentifier
                && InitiatorId.equals(((CommunicationUserIdentifier) senderId).getId())) {
                messageView.setTextColor(Color.GREEN);
                messageView.setGravity(Gravity.RIGHT);
            } else {
                messageView.setTextColor(Color.BLUE);
                messageView.setGravity(Gravity.LEFT);
            }
            // Note: messages with the deletedOn property set to a timestamp, should be marked as deleted
            // Note: messages with the editedOn property set to a timestamp, should be marked as edited
            messageView.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
            chatBoxLayout.addView(messageView);
        }
    }

I nomi visualizzati dei partecipanti al thread di chat non vengono impostati dal client teams. I nomi vengono restituiti come Null nell'API per elencare i partecipanti, nell'evento participantsAdded e nell'evento participantsRemoved . I nomi visualizzati dei partecipanti alla chat possono essere recuperati dal remoteParticipants campo dell'oggetto call .

Ottenere un thread di chat della riunione di Teams per un utente di Servizi di comunicazione

I dettagli delle riunioni di Teams possono essere recuperati usando le API Graph, descritte in dettaglio nella documentazione di Graph. Communication Services Calling SDK accetta un collegamento completo alla riunione di Teams o un ID riunione. Vengono restituiti come parte della onlineMeeting risorsa, accessibili nella joinWebUrl proprietà

Con le API Graph è anche possibile ottenere .threadID La risposta ha un chatInfo oggetto che contiene l'oggetto threadID.

Eseguire il codice

È ora possibile avviare l'app usando il pulsante "Run App" (Esegui app) sulla barra degli strumenti (MAIUSC+F10).

Per partecipare alla riunione e alla chat di Teams, immettere il collegamento alla riunione del team e l'ID del thread nell'interfaccia utente.

Dopo aver eseguito la riunione del team, è necessario ammettere l'utente alla riunione nel client del team. Dopo che l'utente è stato ammesso e ha partecipato alla chat, è possibile inviare e ricevere messaggi.

Screenshot dell'applicazione Android completata.

Nota

Alcune funzionalità non sono attualmente supportate per gli scenari di interoperabilità con Teams. Altre informazioni sulle funzionalità supportate, vedere Funzionalità delle riunioni di Teams per gli utenti esterni di Teams

Questa guida introduttiva illustra come chattare in una riunione di Teams usando Servizi di comunicazione di Azure Chat SDK per C#.

Codice di esempio

Trovare il codice per questa guida introduttiva in GitHub.

Prerequisiti

Partecipare alla chat della riunione

Un utente di Servizi di comunicazione può partecipare a una riunione di Teams come utente anonimo usando l'SDK chiamante. Partecipare alla riunione li aggiunge anche come partecipante alla chat della riunione, in cui possono inviare e ricevere messaggi con altri utenti nella riunione. L'utente non avrà accesso ai messaggi di chat inviati prima della riunione e non potrà inviare o ricevere messaggi dopo la fine della riunione. Per partecipare alla riunione e avviare la chat, è possibile seguire i passaggi successivi.

Eseguire il codice

È possibile compilare ed eseguire il codice in Visual Studio. Si notino le piattaforme della soluzione supportate: x64,x86 e ARM64.

  1. Aprire un'istanza di PowerShell, Terminale Windows, prompt dei comandi o equivalente e passare alla directory in cui si vuole clonare l'esempio.
  2. git clone https://github.com/Azure-Samples/Communication-Services-dotnet-quickstarts.git
  3. Aprire il progetto ChatTeamsInteropQuickStart/ChatTeamsInteropQuickStart.csproj in Visual Studio.
  4. Installare le versioni dei pacchetti NuGet seguenti (o versioni successive):
Install-Package Azure.Communication.Calling -Version 1.0.0-beta.29
Install-Package Azure.Communication.Chat -Version 1.1.0
Install-Package Azure.Communication.Common -Version 1.0.1
Install-Package Azure.Communication.Identity -Version 1.0.1

  1. Con la risorsa servizi di comunicazione ottenuta nei prerequisiti, aggiungere la stringa di connessione al file ChatTeamsInteropQuickStart/MainPage.xaml.cs .
//Azure Communication Services resource connection string, i.e., = "endpoint=https://your-resource.communication.azure.net/;accesskey=your-access-key";
private const string connectionString_ = "";

Importante

  • Selezionare la piattaforma appropriata dall'elenco a discesa "Piattaforme soluzioni" in Visual Studio prima di eseguire il codice, ad esempio x64
  • Assicurarsi di avere la modalità sviluppatore in Windows 10 abilitata (Developer Impostazioni)

I passaggi successivi non funzioneranno se questa configurazione non è configurata correttamente

  1. Premere F5 per avviare il progetto in modalità di debug.
  2. Incollare un collegamento alla riunione di Teams valido nella casella "Collegamento riunione di Teams" (vedere la sezione successiva)
  3. Premere "Partecipa alla riunione di Teams" per avviare la chat.

Importante

Dopo che l'SDK chiamante stabilisce la connessione con la riunione dei team Vedere Servizi di comunicazione che chiama l'app Windows, le funzioni chiave per gestire le operazioni di chat sono: StartPollingForChatMessages e SendMessageButton_Click. Entrambi i frammenti di codice si trovano in ChatTeamsInteropQuickStart\MainPage.xaml.cs

        /// <summary>
        /// Background task that keeps polling for chat messages while the call connection is stablished
        /// </summary>
        private async Task StartPollingForChatMessages()
        {
            CommunicationTokenCredential communicationTokenCredential = new(user_token_);
            chatClient_ = new ChatClient(EndPointFromConnectionString(), communicationTokenCredential);
            await Task.Run(async () =>
            {
                keepPolling_ = true;

                ChatThreadClient chatThreadClient = chatClient_.GetChatThreadClient(thread_Id_);
                int previousTextMessages = 0;
                while (keepPolling_)
                {
                    try
                    {
                        CommunicationUserIdentifier currentUser = new(user_Id_);
                        AsyncPageable<ChatMessage> allMessages = chatThreadClient.GetMessagesAsync();
                        SortedDictionary<long, string> messageList = new();
                        int textMessages = 0;
                        string userPrefix;
                        await foreach (ChatMessage message in allMessages)
                        {
                            if (message.Type == ChatMessageType.Html || message.Type == ChatMessageType.Text)
                            {
                                textMessages++;
                                userPrefix = message.Sender.Equals(currentUser) ? "[you]:" : "";
                                messageList.Add(long.Parse(message.SequenceId), $"{userPrefix}{StripHtml(message.Content.Message)}");
                            }
                        }

                        //Update UI just when there are new messages
                        if (textMessages > previousTextMessages)
                        {
                            previousTextMessages = textMessages;
                            await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                            {
                                TxtChat.Text = string.Join(Environment.NewLine, messageList.Values.ToList());
                            });

                        }
                        if (!keepPolling_)
                        {
                            return;
                        }

                        await SetInCallState(true);
                        await Task.Delay(3000);
                    }
                    catch (Exception e)
                    {
                        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                        {
                            _ = new MessageDialog($"An error occurred while fetching messages in PollingChatMessagesAsync(). The application will shutdown. Details : {e.Message}").ShowAsync();
                            throw e;
                        });
                        await SetInCallState(false);
                    }
                }
            });
        }
        private async void SendMessageButton_Click(object sender, RoutedEventArgs e)
        {
            SendMessageButton.IsEnabled = false;
            ChatThreadClient chatThreadClient = chatClient_.GetChatThreadClient(thread_Id_);
            _ = await chatThreadClient.SendMessageAsync(TxtMessage.Text);
            
            TxtMessage.Text = "";
            SendMessageButton.IsEnabled = true;
        }

Il collegamento alla riunione di Teams può essere recuperato usando le API Graph, descritto in dettaglio nella documentazione di Graph. Questo collegamento viene restituito come parte della onlineMeeting risorsa, accessibile nella joinWebUrl proprietà .

È anche possibile ottenere il collegamento alla riunione richiesto dall'URL di partecipazione alla riunione nell'invito alla riunione di Teams stesso. Un collegamento a una riunione di Teams ha un aspetto simile al seguente: https://teams.microsoft.com/l/meetup-join/meeting_chat_thread_id/1606337455313?context=some_context_here. Se il collegamento ai team ha un formato diverso, è necessario recuperare l'ID thread usando l'API Graph.

Screenshot dell'applicazione csharp completata.

Nota

Alcune funzionalità non sono attualmente supportate per gli scenari di interoperabilità con Teams. Altre informazioni sulle funzionalità supportate, vedere Funzionalità delle riunioni di Teams per gli utenti esterni di Teams

Pulire le risorse

Se si vuole pulire e rimuovere una sottoscrizione a Servizi di comunicazione, è possibile eliminare la risorsa o il gruppo di risorse. L'eliminazione del gruppo di risorse comporta anche l'eliminazione di tutte le altre risorse associate. Altre informazioni sulla pulizia delle risorse.

Passaggi successivi

Per altre informazioni, vedere gli articoli seguenti: