Szybki start: dołączanie aplikacji czatu do spotkania usługi Teams

Rozpocznij pracę z usługami Azure Communication Services, łącząc rozwiązanie czatu z usługą Microsoft Teams.

W tym przewodniku Szybki start dowiesz się, jak rozmawiać na spotkaniu w usłudze Teams przy użyciu zestawu SDK czatu usług Azure Communication Services dla języka JavaScript.

Przykładowy kod

Znajdź sfinalizowany kod dla tego przewodnika Szybki start w witrynie GitHub.

Wymagania wstępne

Dołączanie do czatu na spotkaniu

Użytkownik usług Communication Services może dołączyć do spotkania usługi Teams jako anonimowy użytkownik przy użyciu zestawu SDK wywołującego. Dołączenie do spotkania powoduje dodanie ich jako uczestnika do czatu na spotkaniu, gdzie mogą wysyłać i odbierać wiadomości innym użytkownikom na spotkaniu. Użytkownik nie będzie miał dostępu do wiadomości czatu, które zostały wysłane przed dołączeniem do spotkania i nie będzie mógł wysyłać ani odbierać wiadomości po zakończeniu spotkania. Aby dołączyć do spotkania i rozpocząć rozmowę, możesz wykonać następne kroki.

Tworzenie nowej aplikacji Node.js

Otwórz terminal lub okno polecenia, utwórz nowy katalog dla aplikacji i przejdź do niego.

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

Uruchom polecenie npm init -y , aby utworzyć plik package.json z ustawieniami domyślnymi.

npm init -y

Instalowanie pakietów czatów

Użyj polecenia , npm install aby zainstalować niezbędne zestawy SDK usług Komunikacyjnych dla języka 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

Opcja --save wyświetla bibliotekę jako zależność w pliku package.json .

Konfigurowanie struktury aplikacji

Ten przewodnik Szybki start używa pakietu WebPack do tworzenia pakietów zasobów aplikacji. Uruchom następujące polecenie, aby zainstalować pakiety Webpack, webpack-cli i webpack-dev-server npm i wyświetlić je jako zależności programistyczne w package.json:

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

Utwórz plik index.html w katalogu głównym projektu. Ten plik służy do konfigurowania podstawowego układu, który umożliwi użytkownikowi dołączenie do spotkania i rozpoczęcie rozmowy.

Dodawanie kontrolek interfejsu użytkownika usługi Teams

Zastąp kod w index.html poniższym fragmentem kodu. Pole tekstowe w górnej części strony będzie używane do wprowadzania kontekstu spotkania usługi Teams. Przycisk "Dołącz do spotkania w aplikacji Teams" służy do dołączania do określonego spotkania. W dolnej części strony zostanie wyświetlone wyskakujące okienko czatu. Może służyć do wysyłania wiadomości w wątku spotkania i wyświetla w czasie rzeczywistym wszystkie komunikaty wysyłane w wątku, gdy użytkownik usług komunikacyjnych jest członkiem.

<!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>

Włączanie kontrolek interfejsu użytkownika usługi Teams

Zastąp zawartość pliku client.js poniższym fragmentem kodu.

W fragmencie kodu zastąp

  • SECRET_CONNECTION_STRINGz parametry połączenia usługi komunikacyjnej
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}`);
});

Nazwy wyświetlane uczestników wątku czatu nie są ustawiane przez klienta usługi Teams. Nazwy są zwracane jako null w interfejsie API do wyświetlania listy uczestników, w participantsAdded przypadku i w participantsRemoved zdarzeniu. Nazwy wyświetlane uczestników czatu można pobrać z remoteParticipants pola call obiektu. Po otrzymaniu powiadomienia o zmianie listy możesz użyć tego kodu, aby pobrać nazwę użytkownika, który został dodany lub usunięty:

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

Uruchamianie kodu

Użytkownicy pakietu webpack mogą używać elementu webpack-dev-server do kompilowania i uruchamiania aplikacji. Uruchom następujące polecenie, aby utworzyć pakiet hosta aplikacji na lokalnym serwerze internetowym:

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

Otwórz przeglądarkę i przejdź do http://localhost:8080/adresu . Powinna zostać wyświetlona aplikacja uruchomiona, jak pokazano na poniższym zrzucie ekranu:

Zrzut ekranu przedstawiający ukończoną aplikację JavaScript.

Wstaw link do spotkania usługi Teams w polu tekstowym. Naciśnij pozycję Dołącz do spotkania usługi Teams, aby dołączyć do spotkania usługi Teams. Po tym, jak użytkownik usług komunikacyjnych został przyjęty na spotkanie, możesz porozmawiać z poziomu aplikacji usług komunikacyjnych. Przejdź do pola w dolnej części strony, aby rozpocząć rozmowę. Dla uproszczenia aplikacja wyświetla tylko dwa ostatnie komunikaty na czacie.

Uwaga

Niektóre funkcje nie są obecnie obsługiwane w scenariuszach współdziałania z usługą Teams. Dowiedz się więcej o obsługiwanych funkcjach, zobacz Możliwości spotkań usługi Teams dla użytkowników zewnętrznych usługi Teams

W tym przewodniku Szybki start dowiesz się, jak rozmawiać na spotkaniu w usłudze Teams przy użyciu zestawu SDK czatu usług Azure Communication Services dla systemu iOS.

Przykładowy kod

Jeśli chcesz przejść do końca, możesz pobrać ten przewodnik Szybki start jako przykład w usłudze GitHub.

Wymagania wstępne

  • Konto platformy Azure z aktywną subskrypcją. Bezpłatne tworzenie konta
  • Komputer Mac z uruchomionym programem Xcode wraz z prawidłowym certyfikatem dewelopera zainstalowanym w pęku kluczy.
  • Wdrożenie usługi Teams.
  • Token dostępu użytkownika dla usługi Azure Communication Service. Możesz również użyć interfejsu wiersza polecenia platformy Azure i uruchomić polecenie za pomocą parametry połączenia, aby utworzyć użytkownika i token dostępu.
az communication identity token issue --scope voip --connection-string "yourConnectionString"

Aby uzyskać szczegółowe informacje, zobacz Tworzenie tokenów dostępu za pomocą interfejsu wiersza polecenia platformy Azure i zarządzanie nimi.

Konfigurowanie

Tworzenie projektu Xcode

W programie Xcode utwórz nowy projekt systemu iOS i wybierz szablon Aplikacja z jednym widokiem. W tym samouczku jest używana struktura SwiftUI, dlatego należy ustawić język na swift i interfejs użytkownika na swiftUI. Podczas tego przewodnika Szybki start nie utworzysz testów. Możesz usunąć zaznaczenie pola wyboru Uwzględnij testy.

Zrzut ekranu przedstawiający okno Nowy projekt w programie Xcode.

Instalowanie platformy CocoaPods

Skorzystaj z tego przewodnika, aby zainstalować narzędzie CocoaPods na komputerze Mac.

Instalowanie pakietu i zależności za pomocą narzędzia CocoaPods

  1. Aby utworzyć aplikację Podfile dla aplikacji, otwórz terminal i przejdź do folderu projektu i uruchom init zasobnika.

  2. Dodaj następujący kod do obiektu Podfile docelowego i zapisz.

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. Uruchom program pod install.

  2. Otwórz plik za .xcworkspace pomocą programu Xcode.

Żądanie dostępu do mikrofonu

Aby uzyskać dostęp do mikrofonu urządzenia, należy zaktualizować listę właściwości informacji aplikacji za pomocą elementu NSMicrophoneUsageDescription. Skojarzona wartość została ustawiona na string wartość, która została uwzględniona w oknie dialogowym używanym przez system do żądania dostępu od użytkownika.

W obszarze docelowym wybierz kartę Info i dodaj ciąg "Prywatność — opis użycia mikrofonu"

Zrzut ekranu przedstawiający dodawanie użycia mikrofonu w środowisku Xcode.

Wyłączanie piaskownicy skryptu użytkownika

Niektóre skrypty w połączonych bibliotekach zapisują pliki podczas procesu kompilacji. Aby to umożliwić, wyłącz piaskownicę skryptu użytkownika w środowisku Xcode. W obszarze ustawień kompilacji wyszukaj sandbox i ustaw wartość User Script SandboxingNo.

Zrzut ekranu przedstawiający wyłączanie piaskownicy skryptów użytkownika w środowisku Xcode.

Dołączanie do czatu na spotkaniu

Użytkownik usług Communication Services może dołączyć do spotkania usługi Teams jako anonimowy użytkownik przy użyciu zestawu SDK wywołującego. Gdy użytkownik dołączy do spotkania usługi Teams, będzie mógł wysyłać i odbierać wiadomości z innymi uczestnikami spotkania. Użytkownik nie będzie miał dostępu do wiadomości czatu wysyłanych przed dołączeniem ani nie będzie mógł wysyłać ani odbierać wiadomości, gdy nie są w spotkaniu. Aby dołączyć do spotkania i rozpocząć rozmowę, możesz wykonać następne kroki.

Konfigurowanie struktury aplikacji

Zaimportuj pakiety usługi Azure Communication w programie ContentView.swift , dodając następujący fragment kodu:

import AVFoundation
import SwiftUI

import AzureCommunicationCalling
import AzureCommunicationChat

W ContentView.swift pliku dodaj następujący fragment kodu tuż nad deklaracją struct ContentView: View :

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

Zastąp <ADD_YOUR_ENDPOINT_URL_HERE> element punktem końcowym zasobu usług Komunikacyjnych. Zastąp <ADD_YOUR_USER_TOKEN_HERE> element tokenem wygenerowany powyżej za pomocą wiersza polecenia klienta platformy Azure. Dowiedz się więcej na temat tokenów dostępu użytkowników: Token dostępu użytkownika

Zastąp Quickstart User ciąg nazwą wyświetlaną, której chcesz użyć w czacie.

Aby zachować stan, dodaj następujące zmienne do ContentView struktury:

  @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] = []

Teraz dodajmy główną treść var do przechowywania elementów interfejsu użytkownika. Dołączamy logikę biznesową do tych kontrolek w tym przewodniku Szybki start. Dodaj następujący kod do ContentView struktury:

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
    }
  }

Inicjowanie obiektu ChatClient

ChatClient Utwórz wystąpienie powiadomień i włącz powiadomienia o wiadomościach. Do odbierania wiadomości na czacie używamy powiadomień w czasie rzeczywistym.

Po skonfigurowaniu głównej treści dodajmy funkcje do obsługi konfiguracji klientów rozmów i czatów.

onAppear W funkcji dodaj następujący kod, aby zainicjować element CallClient i 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
  }

Dodawanie funkcji dołączania do spotkania

Dodaj następującą funkcję do ContentView struktury, aby obsłużyć dołączanie do spotkania.

  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"
      }
    }
  }

Inicjowanie elementu ChatThreadClient

Zainicjujemy ChatThreadClient element po dołączeniu do spotkania przez użytkownika. Wymaga to sprawdzenia stanu spotkania od delegata, a następnie zainicjowania ChatThreadClient elementu za threadId pomocą elementu po dołączeniu do spotkania.

connectChat() Utwórz funkcję przy użyciu następującego kodu:

  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
    }
  }

Dodaj następującą funkcję pomocnika do ContentViewelementu , używaną do analizowania identyfikatora wątku czatu z linku spotkania zespołu, jeśli jest to możliwe. W przypadku niepowodzenia wyodrębniania użytkownik będzie musiał ręcznie wprowadzić identyfikator wątku czatu przy użyciu interfejsów API programu Graph w celu pobrania identyfikatora wątku.

 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
}

Włączanie wysyłania komunikatów

sendMessage() Dodaj funkcję do ContentView. Ta funkcja używa elementu ChatThreadClient do wysyłania komunikatów od użytkownika.

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?"
    }
  }
}

Włączanie odbierania komunikatów

Aby odbierać komunikaty, implementujemy procedurę obsługi zdarzeń ChatMessageReceived . Po wysłaniu nowych komunikatów do wątku ta procedura obsługi dodaje komunikaty do meetingMessages zmiennej, aby mogły być wyświetlane w interfejsie użytkownika.

Najpierw dodaj następującą strukturę do ContentView.swift. Interfejs użytkownika używa danych w strukturze do wyświetlania naszych wiadomości na czacie.

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
    )
  }
}

Następnie dodaj receiveMessage() funkcję do ContentView. Jest to wywoływane w przypadku wystąpienia zdarzenia obsługi komunikatów. Należy pamiętać, że należy zarejestrować wszystkie zdarzenia, które mają być obsługiwane w instrukcji switch za pośrednictwem chatClient?.register() metody .

  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
    }
  }

Na koniec musimy zaimplementować procedurę obsługi delegatów dla klienta wywołania. Ta procedura obsługi służy do sprawdzania stanu połączenia i inicjowania klienta czatu, gdy użytkownik dołącza do spotkania.

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"
    }
  }
}

Opuść czat

Gdy użytkownik opuści spotkanie zespołu, wyczyścimy wiadomości czatu z interfejsu użytkownika i zawiesimy połączenie. Pełny kod jest pokazany poniżej.

  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"
    }
  }

Pobieranie wątku czatu spotkania usługi Teams dla użytkownika usług Communication Services

Szczegóły spotkania usługi Teams można pobrać przy użyciu interfejsów API programu Graph, szczegółowo opisanych w dokumentacji programu Graph. Zestaw SDK wywołujący usługi Communication Services akceptuje pełny link do spotkania usługi Teams lub identyfikator spotkania. Są one zwracane jako część onlineMeeting zasobu dostępnego w joinWebUrl ramach właściwości

Za pomocą interfejsów API programu Graph można również uzyskać threadIDelement . Odpowiedź zawiera chatInfo obiekt zawierający threadIDelement .

Uruchamianie kodu

Uruchom aplikację.

Aby dołączyć do spotkania usługi Teams, wprowadź link spotkanie zespołu w interfejsie użytkownika.

Po dołączeniu do spotkania zespołu musisz przyznać użytkownika do spotkania w kliencie zespołu. Gdy użytkownik zostanie przyjęty i dołączy do czatu, możesz wysyłać i odbierać wiadomości.

Zrzut ekranu przedstawiający ukończoną aplikację systemu iOS.

Uwaga

Niektóre funkcje nie są obecnie obsługiwane w scenariuszach współdziałania z usługą Teams. Dowiedz się więcej o obsługiwanych funkcjach, zobacz Możliwości spotkań usługi Teams dla użytkowników zewnętrznych usługi Teams

W tym przewodniku Szybki start dowiesz się, jak rozmawiać na spotkaniu w usłudze Teams przy użyciu zestawu SDK czatu usług Azure Communication Services dla systemu Android.

Przykładowy kod

Jeśli chcesz przejść do końca, możesz pobrać ten przewodnik Szybki start jako przykład w usłudze GitHub.

Wymagania wstępne

Włączanie współdziałania usługi Teams

Użytkownik usług Communication Services, który dołącza do spotkania usługi Teams jako użytkownik-gość, może uzyskać dostęp do czatu spotkania tylko wtedy, gdy dołączyli do rozmowy ze spotkaniem usługi Teams. Zapoznaj się z dokumentacją międzyoperajności usługi Teams, aby dowiedzieć się, jak dodać użytkownika usług Communication Services do połączenia konferencyjnego usługi Teams.

Aby korzystać z tej funkcji, musisz być członkiem organizacji, która jest właścicielem obu jednostek.

Dołączanie do czatu na spotkaniu

Po włączeniu współdziałania usługi Teams użytkownik usług Communication Services może dołączyć do wywołania usługi Teams jako użytkownik zewnętrzny przy użyciu zestawu SDK wywołującego. Dołączenie do połączenia powoduje dodanie ich jako uczestnika do czatu spotkania, gdzie mogą wysyłać i odbierać wiadomości innym użytkownikom podczas rozmowy. Użytkownik nie ma dostępu do wiadomości czatu, które zostały wysłane przed dołączeniem do połączenia. Aby dołączyć do spotkania i rozpocząć rozmowę, możesz wykonać następne kroki.

Dodawanie czatu do aplikacji wywołującej teams

Na poziomie build.gradlemodułu dodaj zależność od zestawu SDK czatu.

Ważne

Znany problem: W przypadku używania zestawu Android Chat i Calling SDK razem w tej samej aplikacji funkcja powiadomień w czasie rzeczywistym zestawu SDK czatu nie będzie działać. Otrzymasz problem z rozwiązaniem zależności. Podczas pracy nad rozwiązaniem możesz wyłączyć funkcję powiadomień w czasie rzeczywistym, dodając następujące wykluczenia do zależności zestawu Chat SDK w pliku aplikacji build.gradle :

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

Dodawanie układu interfejsu użytkownika usługi Teams

Zastąp kod w activity_main.xml poniższym fragmentem kodu. Dodaje dane wejściowe dla identyfikatora wątku i wysyłania wiadomości, przycisk wysyłania wpisanej wiadomości i podstawowy układ czatu.

<?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>

Włączanie kontrolek interfejsu użytkownika usługi Teams

Importowanie pakietów i definiowanie zmiennych stanu

Do zawartości MainActivity.javapliku dodaj następujące importy:

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;

MainActivity W klasie dodaj następujące zmienne:

    // 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<>();

Zastąp <USER_ID> element identyfikatorem użytkownika inicjującego czat. Zastąp <COMMUNICATION_SERVICES_RESOURCE_ENDPOINT> element punktem końcowym zasobu usług Komunikacyjnych.

Inicjowanie elementu ChatThreadClient

Po dołączeniu do spotkania utwórz wystąpienie ChatThreadClient elementów i udostępnij składniki czatu.

Zaktualizuj koniec MainActivity.joinTeamsMeeting() metody przy użyciu poniższego kodu:

    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);
    }

Włączanie wysyłania komunikatów

Dodaj metodę sendMessage() do MainActivitymetody . Używa obiektu do ChatThreadClient wysyłania wiadomości w imieniu użytkownika.

    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("");
    }

Włączanie sondowania komunikatów i renderowanie ich w aplikacji

Ważne

Znany problem: ponieważ funkcja powiadomień w czasie rzeczywistym zestawu SDK czatu nie współdziała z zestawami Sdk wywołujących, musimy sondować GetMessages interfejs API w wstępnie zdefiniowanych odstępach czasu. W naszym przykładzie użyjemy 3-sekundowych interwałów.

Możemy uzyskać następujące dane z listy komunikatów zwróconych przez GetMessages interfejs API:

  • Komunikaty text i html w wątku od momentu dołączenia
  • Zmiany w składzie wątku
  • Aktualizacje do tematu wątku

MainActivity W klasie dodaj procedurę obsługi i zadanie, które będzie uruchamiane w 3-sekundowych odstępach czasu:

    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);
        }
    };

Pamiętaj, że zadanie zostało już uruchomione na końcu MainActivity.joinTeamsMeeting() metody zaktualizowanej w kroku inicjowania.

Na koniec dodamy metodę wykonywania zapytań dotyczących wszystkich dostępnych komunikatów w wątku, analizowania ich według typu komunikatu i wyświetlania html elementów i 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);
        }
    }

Nazwy wyświetlane uczestników wątku czatu nie są ustawiane przez klienta usługi Teams. Nazwy są zwracane jako null w interfejsie API do wyświetlania listy uczestników, w participantsAdded przypadku i w participantsRemoved zdarzeniu. Nazwy wyświetlane uczestników czatu można pobrać z remoteParticipants pola call obiektu.

Pobieranie wątku czatu spotkania usługi Teams dla użytkownika usług Communication Services

Szczegóły spotkania usługi Teams można pobrać przy użyciu interfejsów API programu Graph, szczegółowo opisanych w dokumentacji programu Graph. Zestaw SDK wywołujący usługi Communication Services akceptuje pełny link do spotkania usługi Teams lub identyfikator spotkania. Są one zwracane jako część onlineMeeting zasobu dostępnego w joinWebUrl ramach właściwości

Za pomocą interfejsów API programu Graph można również uzyskać threadIDelement . Odpowiedź zawiera chatInfo obiekt zawierający threadIDelement .

Uruchamianie kodu

Teraz można uruchomić aplikację przy użyciu przycisku "Uruchom aplikację" na pasku narzędzi (Shift+F10).

Aby dołączyć do spotkania i czatu w aplikacji Teams, wprowadź link spotkanie zespołu i identyfikator wątku w interfejsie użytkownika.

Po dołączeniu do spotkania zespołu musisz przyznać użytkownika do spotkania w kliencie zespołu. Gdy użytkownik zostanie przyjęty i dołączy do czatu, możesz wysyłać i odbierać wiadomości.

Zrzut ekranu przedstawiający ukończoną aplikację systemu Android.

Uwaga

Niektóre funkcje nie są obecnie obsługiwane w scenariuszach współdziałania z usługą Teams. Dowiedz się więcej o obsługiwanych funkcjach, zobacz Możliwości spotkań usługi Teams dla użytkowników zewnętrznych usługi Teams

Z tego przewodnika Szybki start dowiesz się, jak rozmawiać na spotkaniu w aplikacji Teams przy użyciu zestawu SDK czatu usług Azure Communication Services dla języka C#.

Przykładowy kod

Znajdź kod tego przewodnika Szybki start w witrynie GitHub.

Wymagania wstępne

  • Wdrożenie usługi Teams.
  • Konto platformy Azure z aktywną subskrypcją. Utwórz konto bezpłatnie.
  • Zainstaluj program Visual Studio 2019 przy użyciu obciążenia programistycznego platforma uniwersalna systemu Windows.
  • Wdrożony zasób usług komunikacyjnych. Utwórz zasób usług komunikacyjnych.
  • Link do spotkania w aplikacji Teams.

Dołączanie do czatu na spotkaniu

Użytkownik usług Communication Services może dołączyć do spotkania usługi Teams jako anonimowy użytkownik przy użyciu zestawu SDK wywołującego. Dołączenie do spotkania powoduje dodanie ich jako uczestnika do czatu na spotkaniu, gdzie mogą wysyłać i odbierać wiadomości innym użytkownikom na spotkaniu. Użytkownik nie będzie miał dostępu do wiadomości czatu, które zostały wysłane przed dołączeniem do spotkania i nie będzie mógł wysyłać ani odbierać wiadomości po zakończeniu spotkania. Aby dołączyć do spotkania i rozpocząć rozmowę, możesz wykonać następne kroki.

Uruchamianie kodu

Możesz skompilować i uruchomić kod w programie Visual Studio. Zwróć uwagę na obsługiwane platformy rozwiązań: x64,x86 i ARM64.

  1. Otwórz wystąpienie programu PowerShell, Terminal Windows, wiersza polecenia lub równoważnego i przejdź do katalogu, do którego chcesz sklonować przykład.
  2. git clone https://github.com/Azure-Samples/Communication-Services-dotnet-quickstarts.git
  3. Otwórz projekt ChatTeamsInteropQuickStart/ChatTeamsInteropQuickStart.csproj w programie Visual Studio.
  4. Zainstaluj następujące wersje pakietów NuGet (lub nowsze):
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. W przypadku zasobu usług komunikacyjnych pozyskanych w wymaganiach wstępnych dodaj parametry połączenia do pliku 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_ = "";

Ważne

Następne kroki nie będą działać, jeśli nie jest to poprawnie skonfigurowane

  1. Naciśnij klawisz F5, aby uruchomić projekt w trybie debugowania.
  2. Wklej prawidłowy link do spotkania zespołów w polu "Łącze do spotkania w aplikacji Teams" (zobacz następną sekcję)
  3. Naciśnij pozycję "Dołącz do spotkania w aplikacji Teams", aby rozpocząć rozmowę.

Ważne

Po nawiązaniu połączenia z zespołami , gdy zestaw SDK wywołania wywołań zestawu SDK wywołania systemu Windows, kluczowe funkcje do obsługi operacji czatu to: StartPollingForChatMessages i SendMessageButton_Click. Oba fragmenty kodu znajdują się w kodzie 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;
        }

Link do spotkania usługi Teams można pobrać przy użyciu interfejsów API programu Graph, szczegółowo w dokumentacji programu Graph. Ten link jest zwracany w ramach onlineMeeting zasobu dostępnego w joinWebUrl ramach właściwości .

Możesz również uzyskać wymagany link do spotkania z adresu URL dołączenia do spotkania w zaproszeniu do spotkania usługi Teams. Link do spotkania usługi Teams wygląda następująco: https://teams.microsoft.com/l/meetup-join/meeting_chat_thread_id/1606337455313?context=some_context_here. Jeśli link do aplikacji Teams ma inny format, musisz pobrać identyfikator wątku przy użyciu interfejsu API programu Graph.

Zrzut ekranu przedstawiający ukończoną aplikację csharp.

Uwaga

Niektóre funkcje nie są obecnie obsługiwane w scenariuszach współdziałania z usługą Teams. Dowiedz się więcej o obsługiwanych funkcjach, zobacz Możliwości spotkań usługi Teams dla użytkowników zewnętrznych usługi Teams

Czyszczenie zasobów

Jeśli chcesz wyczyścić i usunąć subskrypcję usług Komunikacyjnych, możesz usunąć zasób lub grupę zasobów. Usunięcie grupy zasobów powoduje również usunięcie wszelkich innych skojarzonych z nią zasobów. Dowiedz się więcej o czyszczeniu zasobów.

Następne kroki

Aby uzyskać więcej informacji, zobacz następujące artykuły: