Rövid útmutató: Csatlakozás a csevegőalkalmazáshoz Egy Teams-értekezlethez

Ismerkedjen meg a Azure Communication Services a csevegési megoldás Microsoft Teamshez való csatlakoztatásával.

Ebben a rövid útmutatóban megtudhatja, hogyan cseveghet Teams-értekezleteken a JavaScripthez készült Azure Communication Services Chat SDK használatával.

Példakód

Keresse meg a gitHubon a rövid útmutató véglegesített kódját.

Előfeltételek

Csatlakozás az értekezlet csevegéséhez

A Communication Services-felhasználók névtelen felhasználóként csatlakozhatnak a Teams-értekezletekhez a Hívó SDK használatával. Az értekezlethez való csatlakozás résztvevőként is hozzáadja őket az értekezlet csevegéséhez, ahol üzeneteket küldhetnek és fogadhatnak az értekezlet többi felhasználójával. A felhasználó nem fog tudni hozzáférni az értekezlethez való csatlakozás előtt elküldött csevegőüzenetekhez, és nem tud üzeneteket küldeni vagy fogadni az értekezlet befejezése után. Az értekezlethez való csatlakozáshoz és a csevegés megkezdéséhez kövesse a következő lépéseket.

Új Node.js-alkalmazás létrehozása

Nyissa meg a terminált vagy a parancsablakot, hozzon létre egy új könyvtárat az alkalmazáshoz, és navigáljon hozzá.

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

Futtassa a parancsot npm init -y egy package.json fájl létrehozásához az alapértelmezett beállításokkal.

npm init -y

A csevegőcsomagok telepítése

npm install Az paranccsal telepítheti a JavaScripthez szükséges Communication Services SDK-kat.

npm install @azure/communication-common --save

npm install @azure/communication-identity --save

npm install @azure/communication-signaling --save

npm install @azure/communication-chat --save

npm install @azure/communication-calling --save

A --save beállítás függőségként sorolja fel a tárat a package.json fájlban.

Az alkalmazás-keretrendszer beállítása

Ez a rövid útmutató a Webpack használatával köti össze az alkalmazásegységeket. Futtassa a következő parancsot a Webpack, a webpack-cli és a webpack-dev-server npm csomagok telepítéséhez, és sorolja fel őket fejlesztési függőségként a package.json fájlban:

npm install webpack@4.42.0 webpack-cli@3.3.11 webpack-dev-server@3.10.3 --save-dev

Hozzon létre egy index.html fájlt a projekt gyökérkönyvtárában. Ezzel a fájllal olyan alapszintű elrendezést konfigurálunk, amely lehetővé teszi, hogy a felhasználó bekapcsolódjon egy értekezletbe, és csevegni kezdjen.

A Teams felhasználói felület vezérlőinek hozzáadása

Cserélje le a index.html kódját a következő kódrészletre. A lap tetején található szövegmezők segítségével adhatja meg a Teams-értekezlet környezetét és az értekezlet szálazonosítóját. A "Teams-értekezletbe való bekapcsolódás" gomb a megadott értekezlethez való csatlakozáshoz használható. A lap alján megjelenik egy csevegési előugró ablak. Segítségével üzeneteket küldhet az értekezlet szálán, és valós időben jeleníti meg a szálon küldött üzeneteket, miközben a Communication Services felhasználója tagja.

<!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: 300px;" />
          <input id="thread-id-input" type="text" placeholder="Chat thread id"
        style="margin-bottom:1em; width: 300px;" />
        <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>

A Teams felhasználói felület vezérlőinek engedélyezése

Cserélje le a client.js fájl tartalmát a következő kódrészletre.

A kódrészleten belül cserélje le a

  • SECRET_CONNECTION_STRINGa kommunikációs szolgáltatás kapcsolati sztring
  • ENDPOINT_URL a kommunikációs szolgáltatás végpontjának URL-címével
import { CallClient, CallAgent } 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 threadIdInput = document.getElementById('thread-id-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 lastMessage = '';
var previousMessage = '';

async function init() {
  const connectionString = "<SECRET_CONNECTION_STRING>";
  const endpointUrl = "<ENDPOINT_URL>";

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

callButton.addEventListener("click", async () => {
  // join with meeting link
  call = callAgent.join({meetingLink: meetingLinkInput.value}, {});

  call.on('stateChanged', () => {
      callStateElement.innerText = call.state;
  })
  // toggle button and chat box states
  chatBox.style.display = "block";
  hangUpButton.disabled = false;
  callButton.disabled = true;

  messagesContainer.innerHTML = "";

  console.log(call);

  // 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 (threadIdInput.value != e.threadId) {
      return;
    }

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

  chatThreadClient = await chatClient.getChatThreadClient(threadIdInput.value);
});

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

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

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

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

    // toggle chat states
    chatBox.style.display = "none";
    messages = "";
  });

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

A csevegőszál résztvevőinek megjelenített neveit nem a Teams-ügyfél állítja be. A rendszer null értékként adja vissza a neveket az API-ban a résztvevők listázásakor, az participantsAdded eseményben és az participantsRemoved eseményben. A csevegés résztvevőinek megjelenített nevei lekérhetők az remoteParticipantscall objektum mezőjéből. Ha értesítést kap egy névsor-módosításról, ezzel a kóddal lekérheti a hozzáadott vagy eltávolított felhasználó nevét:

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

Teams-értekezlet csevegési szálának lekérése Egy Communication Services-felhasználó számára

A Teams-értekezlet részletei a Graph API-kkal kérhetők le, amelyek a Graph dokumentációjában találhatók. A Communication Services Calling SDK elfogad egy teljes Teams-értekezlethivatkozást vagy egy értekezlet-azonosítót. Az erőforrás részeként onlineMeeting lesznek visszaadva, amely a joinWebUrl tulajdonság alatt érhető el

A Graph API-kkal a következőt is beszerezheti threadID: . A válasz tartalmaz egy chatInfo objektumot a threadIDkövetkezővel: .

A szükséges értekezletadatokat és a szálazonosítót a Teams-értekezlet-összehívás Bekapcsolódás értekezlet url-címéből is lekérheti. A Teams-értekezletek hivatkozása a következőképpen néz ki: https://teams.microsoft.com/l/meetup-join/meeting_chat_thread_id/1606337455313?context=some_context_here. meeting_chat_thread_id Itt threadId található a hivatkozás. Használat előtt győződjön meg arról, hogy a meeting_chat_thread_id nincs beágyazva. A formátumnak a következőnek kell lennie: 19:meeting_ZWRhZDY4ZGUtYmRlNS00OWZaLTlkZTgtZWRiYjIxOWI2NTQ4@thread.v2

A kód futtatása

A Webpack-felhasználók a webpack-dev-server használatával hozhatják létre és futtathatják az alkalmazást. Futtassa a következő parancsot az alkalmazásgazda helyi webkiszolgálón való kötegeléséhez:

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

Nyissa meg a böngészőt, és keresse meg a következőt: http://localhost:8080/. Az alkalmazásnak az alábbi képernyőképen látható módon kell megjelennie:

Képernyőkép a befejezett JavaScript-alkalmazásról.

Szúrja be a Teams-értekezlet hivatkozását és szálazonosítóját a szövegmezőkbe. A Teams-értekezlethez való csatlakozáshoz nyomja le a Join Teams Meeting (Bekapcsolódás a Teams-értekezletbe ) gombot. Miután a Communication Services-felhasználót beengedték az értekezletbe, cseveghet a Communication Services-alkalmazásból. A csevegés megkezdéséhez lépjen a lap alján található mezőbe. Az egyszerűség kedvéért az alkalmazás csak az utolsó két üzenetet jeleníti meg a csevegésben.

Megjegyzés

Bizonyos funkciók jelenleg nem támogatottak a Teamsszel való együttműködési forgatókönyvekben. További információ a támogatott funkciókról: Teams-értekezletek képességei a Teams külső felhasználói számára

Ebben a rövid útmutatóban megtudhatja, hogyan cseveghet Teams-értekezleteken az iOS-hez készült Azure Communication Services Chat SDK használatával.

Előfeltételek

Csatlakozás az értekezlet csevegéséhez

A Communication Services-felhasználók névtelen felhasználóként csatlakozhatnak a Teams-értekezletekhez a Hívó SDK használatával. Az értekezlethez való csatlakozás résztvevőként is hozzáadja őket az értekezlet csevegéséhez, ahol üzeneteket küldhetnek és fogadhatnak az értekezlet többi felhasználójával. A felhasználó nem fog tudni hozzáférni az értekezlethez való csatlakozás előtt elküldött csevegőüzenetekhez, és nem tud üzeneteket küldeni vagy fogadni az értekezlet befejezése után. Az értekezlethez való csatlakozáshoz és a csevegés megkezdéséhez kövesse a következő lépéseket.

Csevegés hozzáadása a Teams-hívó alkalmazáshoz

Törölje a Podfile.lock podfájl tartalmát, és cserélje le a következőre:

platform :ios, '13.0'
use_frameworks!

target 'AzureCommunicationCallingSample' do
  pod 'AzureCommunicationCalling', '~> 1.0.0-beta.12'
  pod 'AzureCommunicationChat', '~> 1.0.0-beta.11'
end

A csevegőcsomagok telepítése

Futtassa a parancsot pod install az AzureCommunicationChat-csomag telepítéséhez. A telepítés után nyissa meg a .xcworkspace fájlt.

Az alkalmazás-keretrendszer beállítása

Importálja az AzureCommunicationChat-csomagot ContentView.swift a következő kódrészlet hozzáadásával:

import AzureCommunicationChat

A Teams felhasználói felület vezérlőinek hozzáadása

Adja ContentView.swift hozzá a következő kódrészletet a meglévő állapotváltozók alá.

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

    let displayName: String = "<YOUR_DISPLAY_NAME_HERE>"

Cserélje le <YOUR_DISPLAY_NAME_HERE> a elemet a csevegésben használni kívánt megjelenítendő névre.

Ezután módosítjuk az űrlapot Section , hogy megjelenítsük a csevegési üzeneteinket, és felhasználói felületi vezérlőket adjunk hozzá a csevegéshez.

Adja hozzá a következő kódrészletet a meglévő űrlaphoz. Közvetlenül a Szöveg nézet Text(recordingStatus)után az állapot rögzítéséhez.

VStack(alignment: .leading) {
    ForEach(meetingMessages, id: \.id) { message in
        let currentUser: Bool = (message.displayName == self.displayName)
        let foregroundColor = currentUser ? Color.white : Color.black
        let background = currentUser ? Color.blue : Color(.systemGray6)
        let alignment = currentUser ? HorizontalAlignment.trailing : HorizontalAlignment.leading
        VStack {
            Text(message.displayName).font(Font.system(size: 10))
            Text(message.content)
        }
        .alignmentGuide(.leading) { d in d[alignment] }
        .padding(10)
        .foregroundColor(foregroundColor)
        .background(background)
        .cornerRadius(10)
    }
}.frame(minWidth: 0, maxWidth: .infinity)
TextField("Enter your message...", text: $chatMessage)
Button(action: sendMessage) {
    Text("Send Message")
}.disabled(chatThreadClient == nil)

Ezután módosítsa a címet a következőre: Chat Teams Quickstart. Módosítsa az alábbi sort ezzel a címmel.

.navigationBarTitle("Chat Teams Quickstart")

A Teams felhasználói felület vezérlőinek engedélyezése

A ChatClient inicializálása

A példányosítás és a ChatClient valós idejű értesítések engedélyezése. Valós idejű értesítéseket használunk a csevegési üzenetek fogadásához.

NavigationView.onAppearA fájlban adja hozzá az alábbi kódrészletet a meglévő kód után, amely inicializálja a fájltCallAgent.

// Initialize the ChatClient
do {
    let endpoint = "COMMUNICATION_SERVICES_RESOURCE_ENDPOINT_HERE>"
    let credential = try CommunicationTokenCredential(token: "<USER_ACCESS_TOKEN_HERE>")

    self.chatClient = try ChatClient(
        endpoint: endpoint,
        credential: credential,
        withOptions: AzureCommunicationChatClientOptions()
    )

    self.message = "ChatClient successfully created"

    // Start real-time notifications
    self.chatClient?.startRealTimeNotifications() { result in
        switch result {
        case .success:
            print("Real-time notifications started")
            // Receive chat messages
            self.chatClient?.register(event: ChatEventId.chatMessageReceived, handler: receiveMessage)
        case .failure:
            print("Failed to start real-time notifications")
            self.message = "Failed to enable chat notifications"
        }
    }
} catch {
    print("Unable to create ChatClient")
    self.message = "Please enter a valid endpoint and Chat token in source code"
    return
}

Cserélje le a elemet <COMMUNICATION_SERVICES_RESOURCE_ENDPOINT_HERE> a Communication Services-erőforrás végpontjára. Cserélje le a elemet <USER_ACCESS_TOKEN_HERE> egy csevegési hatókörrel rendelkező hozzáférési jogkivonatra.

További információ a felhasználói hozzáférési jogkivonatokról: Felhasználói hozzáférési jogkivonat

A ChatThreadClient inicializálása

A meglévő joinTeamsMeeting() függvényen belül inicializáljuk azt ChatThreadClient , miután a felhasználó csatlakozott az értekezlethez.

A hívás self.callAgent?.join()befejezési kezelőjének belsejében adja hozzá a kódot a megjegyzés // Initialize the ChatThreadClientalá. A teljes kód alább látható.

self.callAgent?.join(with: teamsMeetingLinkLocator, joinCallOptions: joinCallOptions) { (call, error) in
    if (error == nil) {
        self.call = call
        self.callObserver = CallObserver(self)
        self.call!.delegate = self.callObserver
        self.message = "Teams meeting joined successfully"

        // Initialize the ChatThreadClient
        do {
            guard let threadId = getThreadId(from: self.meetingLink) else {
                self.message = "Failed to join meeting chat"
                return
            }
            self.chatThreadClient = try chatClient?.createClient(forThread: threadId)
            self.message = "Joined meeting chat successfully"
        } catch {
            print("Failed to create ChatThreadClient")
            self.message = "Failed to join meeting chat"
            return
        }
    } else {
        print("Failed to join Teams meeting")
    }
}

Adja hozzá a következő segédfüggvényt a ContentView() függvényhez, amellyel lekérheti a csevegési szál azonosítóját a csapat értekezlet-hivatkozásáról.

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

Üzenetek küldésének engedélyezése

Adja hozzá a sendMessage() függvényt a következőhöz: ContentView. Ez a függvény a ChatThreadClient használatával küld üzeneteket a felhasználótól.

func sendMessage() {
    let message = SendChatMessageRequest(
        content: self.chatMessage,
        senderDisplayName: self.displayName
    )
    
    self.chatThreadClient?.send(message: message) { result, _ in
        switch result {
        case .success:
            print("Chat message sent")
        case .failure:
            print("Failed to send chat message")
        }

        self.chatMessage = ""
    }
}

Üzenetek fogadásának engedélyezése

Az üzenetek fogadásához implementáljuk a kezelőt az eseményekhez ChatMessageReceived . Amikor a rendszer új üzeneteket küld a szálnak, a kezelő hozzáadja az üzeneteket a meetingMessages változóhoz, hogy azok megjelenjenek a felhasználói felületen.

Először adja hozzá a következő strukturát a következőhöz ContentView.swift: . A felhasználói felület a struktúrában szereplő adatokat használja a csevegőüzenetek megjelenítéséhez.

struct MeetingMessage {
    let id: String
    let content: String
    let displayName: String
}

Ezután adja hozzá a függvényt a receiveMessage() következőhöz: ContentView. Ez az a kezelő, amelyet minden alkalommal meghívnak, amikor egy ChatMessageReceived esemény bekövetkezik.

func receiveMessage(response: Any, eventId: ChatEventId) {
    let chatEvent: ChatMessageReceivedEvent = response as! ChatMessageReceivedEvent

    let displayName: String = chatEvent.senderDisplayName ?? "Unknown User"
    let content: String = chatEvent.message.replacingOccurrences(of: "<[^>]+>", with: "", options: String.CompareOptions.regularExpression)

    self.meetingMessages.append(
        MeetingMessage(
            id: chatEvent.id,
            content: content,
            displayName: displayName
        )
    )
}

Kilépés a csevegésből

Amikor a felhasználó elhagyja a csapat értekezletét, töröljük a csevegést a felhasználói felületről. A teljes kód alább látható.

func leaveMeeting() {
    if let call = call {
        call.hangUp(options: nil, completionHandler: { (error) in
            if error == nil {
                self.message = "Leaving Teams meeting was successful"
                // Clear the chat
                self.meetingMessages.removeAll()
            } else {
                self.message = "Leaving Teams meeting failed"
            }
        })
    } else {
        self.message = "No active call to hanup"
    }
}

Teams-értekezlet csevegési szálának lekérése Egy Communication Services-felhasználó számára

A Teams-értekezlet részletei a Graph API-kkal kérhetők le, amelyek a Graph dokumentációjában találhatók. A Communication Services Calling SDK elfogad egy teljes Teams-értekezlethivatkozást vagy egy értekezlet-azonosítót. A rendszer az erőforrás részeként adja vissza őket, amely a onlineMeetingjoinWebUrl tulajdonság alatt érhető el

A Graph API-kkal a következőt is beszerezheti threadID: . A válasz egy chatInfo objektummal rendelkezik, amely a következőt threadIDtartalmazza: .

A szükséges értekezletadatokat és a szálazonosítót a Teams-értekezlet-összehívás Bekapcsolódás értekezlet url-címéből is lekérheti. A Teams-értekezletek hivatkozása a következőképpen néz ki: https://teams.microsoft.com/l/meetup-join/meeting_chat_thread_id/1606337455313?context=some_context_here. meeting_chat_thread_id Itt threadID található a hivatkozás. Használat előtt győződjön meg arról, hogy a meeting_chat_thread_id nincs beágyazva. A formátumnak a következőnek kell lennie: 19:meeting_ZWRhZDY4ZGUtYmRlNS00OWZaLTlkZTgtZWRiYjIxOWI2NTQ4@thread.v2

A kód futtatása

Futtassa az alkalmazást.

A Teams-értekezlethez való csatlakozáshoz írja be a csapat értekezletére mutató hivatkozást a felhasználói felületen.

Miután csatlakozott a csapat értekezletéhez, be kell fogadnia a felhasználót az értekezletbe a csapat ügyfélprogramjában. Miután a felhasználót beengedték, és csatlakozott a csevegéshez, küldhet és fogadhat üzeneteket.

Képernyőkép a befejezett iOS-alkalmazásról.

Megjegyzés

Bizonyos funkciók jelenleg nem támogatottak a Teamsszel való együttműködési forgatókönyvekben. További információ a támogatott funkciókról: Teams-értekezletek képességei a Teams külső felhasználói számára

Ebben a rövid útmutatóban megtudhatja, hogyan cseveghet Teams-értekezleteken az Android Azure Communication Services Chat SDK használatával.

Előfeltételek

A Teams együttműködési lehetőségeinek engedélyezése

A Teams-értekezletekhez vendégfelhasználóként csatlakozó Communication Services-felhasználók csak akkor férhetnek hozzá az értekezlet csevegéséhez, ha csatlakoztak a Teams-értekezlethíváshoz. Tekintse meg a Teams interop dokumentációját, amelyből megtudhatja, hogyan vehet fel Egy Communication Services-felhasználót egy Teams-értekezlethívásba.

A funkció használatához mindkét entitás tulajdonos szervezetének tagja kell lennie.

Csatlakozás az értekezlet csevegéséhez

A Teams együttműködési funkciójának engedélyezése után a Communication Services-felhasználók külső felhasználóként csatlakozhatnak a Teams-híváshoz a Hívó SDK használatával. A híváshoz való csatlakozás résztvevőként is hozzáadja őket az értekezlet csevegéséhez, ahol üzeneteket küldhetnek és fogadhatnak a hívásban részt vevő többi felhasználóval. A felhasználó nem fog hozzáférni a híváshoz való csatlakozás előtt elküldött csevegőüzenetekhez. Az értekezlethez való csatlakozáshoz és a csevegés megkezdéséhez kövesse a következő lépéseket.

Csevegés hozzáadása a Teams-hívó alkalmazáshoz

A modul szintjén build.gradleadja hozzá a függőséget a csevegési sdk-hez.

Fontos

Ismert probléma: Ha az Android Chat és a Calling SDK együttes használatát ugyanabban az alkalmazásban használja, a CsevegésI SDK valós idejű értesítési funkciója nem fog működni. Függőségfeloldási problémát fog kapni. Miközben egy megoldáson dolgozunk, kikapcsolhatja a valós idejű értesítések funkciót, ha hozzáadja a következő kivételeket az alkalmazás fájljában build.gradle található CsevegésI SDK-függőséghez:

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

A Teams felhasználói felületének elrendezésének hozzáadása

Cserélje le a activity_main.xml kódját a következő kódrészletre. Bemeneteket ad hozzá a szálazonosítóhoz és az üzenetek küldéséhez, egy gombot a beírt üzenet küldéséhez és egy egyszerű csevegési elrendezést.

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

A Teams felhasználói felület vezérlőinek engedélyezése

Csomagok importálása és állapotváltozók definiálása

A tartalomhoz MainActivity.javaadja hozzá a következő importálást:

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

Adja hozzá az MainActivity osztályhoz a következő változókat:

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

Cserélje le a elemet <USER_ID> a csevegést kezdeményező felhasználó azonosítójára. Cserélje le a elemet <COMMUNICATION_SERVICES_RESOURCE_ENDPOINT> a Communication Services-erőforrás végpontjára.

A ChatThreadClient inicializálása

Miután csatlakozott az értekezlethez, példányosítsa a ChatThreadClient csevegőösszetevőket, és tegye láthatóvá a csevegési összetevőket.

Frissítse a metódus végét MainActivity.joinTeamsMeeting() az alábbi kóddal:

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

Üzenetek küldésének engedélyezése

Adja hozzá a metódust a sendMessage() következőhöz: MainActivity. A használatával ChatThreadClient üzeneteket küld a felhasználó nevében.

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

Üzenetek lekérdezésének engedélyezése és megjelenítése az alkalmazásban

Fontos

Ismert probléma: Mivel a Csevegő SDK valós idejű értesítési funkciója nem működik együtt a hívó SDK-kkal, előre meghatározott időközönként le kell kérdeznünk az GetMessages API-t. A mintánkban 3 másodperces időközöket használunk.

Az API által GetMessages visszaadott üzenetlistából a következő adatokat szerezhetjük be:

  • A text és html az üzenetek a szálon a csatlakozás óta
  • A szálnévsor módosítása
  • Frissítések a tématémakörhöz

MainActivity Az osztályhoz adjon hozzá egy kezelőt és egy futtatható feladatot, amely 3 másodperces időközönként lesz futtatva:

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

Vegye figyelembe, hogy a feladat már el lett indítva az MainActivity.joinTeamsMeeting() inicializálási lépésben frissített metódus végén.

Végül hozzáadjuk a metódust a szál összes akadálymentes üzenetének lekérdezéséhez, az üzenettípus alapján történő elemzéshez és a és text az html üzenet megjelenítéséhez:

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

A csevegőszál résztvevőinek megjelenített neveit a Teams-ügyfél nem állítja be. A rendszer null értékként adja vissza a neveket az API-ban a résztvevők listázásakor, az participantsAdded eseményben és az participantsRemoved eseményben. A csevegés résztvevőinek megjelenített nevei lekérhetők az remoteParticipantscall objektum mezőjéből.

Teams-értekezlet csevegési szálának lekérése Egy Communication Services-felhasználó számára

A Teams-értekezlet részletei a Graph API-kkal kérhetők le, amelyek a Graph dokumentációjában találhatók. A Communication Services Calling SDK elfogad egy teljes Teams-értekezlethivatkozást vagy egy értekezlet-azonosítót. A rendszer az erőforrás részeként adja vissza őket, amely a onlineMeetingjoinWebUrl tulajdonság alatt érhető el

A Graph API-kkal a következőt is beszerezheti threadID: . A válasz egy chatInfo objektummal rendelkezik, amely a következőt threadIDtartalmazza: .

A szükséges értekezletadatokat és a szálazonosítót a Teams-értekezlet-összehívás Bekapcsolódás értekezlet url-címéből is lekérheti. A Teams-értekezletek hivatkozása a következőképpen néz ki: https://teams.microsoft.com/l/meetup-join/meeting_chat_thread_id/1606337455313?context=some_context_here. meeting_chat_thread_id Itt threadId található a hivatkozás. Használat előtt győződjön meg arról, hogy a meeting_chat_thread_id nincs beágyazva. A formátumnak a következőnek kell lennie: 19:meeting_ZWRhZDY4ZGUtYmRlNS00OWZaLTlkZTgtZWRiYjIxOWI2NTQ4@thread.v2

A kód futtatása

Az alkalmazás most már elindítható az eszköztár "Alkalmazás futtatása" gombjával (Shift+F10).

Ha csatlakozni szeretne a Teams-értekezlethez és a csevegéshez, adja meg a csapat értekezlet-hivatkozását és a szálazonosítót a felhasználói felületen.

Miután csatlakozott a csapat értekezletéhez, be kell fogadnia a felhasználót az értekezletbe a csapat ügyfélprogramjában. Miután a felhasználót beengedték, és csatlakozott a csevegéshez, küldhet és fogadhat üzeneteket.

Képernyőkép a befejezett Android-alkalmazásról.

Megjegyzés

Bizonyos funkciók jelenleg nem támogatottak a Teamsszel való együttműködési forgatókönyvekben. További információ a támogatott funkciókról: Teams-értekezletek képességei a Teams külső felhasználói számára

Ebből a rövid útmutatóból megtudhatja, hogyan cseveghet Teams-értekezleteken a C# Azure Communication Services Chat SDK használatával.

Mintakód

Keresse meg a rövid útmutató kódját a GitHubon.

Előfeltételek

Csatlakozás az értekezlet csevegéséhez

A Communication Services-felhasználók névtelen felhasználóként csatlakozhatnak a Teams-értekezletekhez a Hívó SDK használatával. Ha csatlakozik az értekezlethez, résztvevőként is hozzáadja őket az értekezlet csevegéséhez, ahol üzeneteket küldhetnek és fogadhatnak az értekezlet többi felhasználójával. A felhasználónak nem lesz hozzáférése az értekezlethez való csatlakozás előtt elküldött csevegőüzenetekhez, és nem tud üzeneteket küldeni vagy fogadni az értekezlet befejezése után. Az értekezlethez való csatlakozáshoz és a csevegés megkezdéséhez kövesse a következő lépéseket.

A kód futtatása

A kódot a Visual Studióban hozhatja létre és futtathatja. Jegyezze fel a és a megoldásplatformokat.x64x86ARM64

  1. Nyisson meg egy PowerShell-példányt, Windows terminál, parancssort vagy azzal egyenértékűt, és keresse meg azt a könyvtárat, amelybe klónozni szeretné a mintát.
  2. git clone https://github.com/Azure-Samples/Communication-Services-dotnet-quickstarts.git
  3. Nyissa meg a ChatTeamsInteropQuickStart/ChatTeamsInteropQuickStart.csproj projektet a Visual Studióban.
  4. Telepítse a következő NuGet-csomagok (vagy újabb) verzióit:
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. Ha a Communication Services-erőforrás előfeltételként van beszerzve, adja hozzá a connectionstring elemet a ChatTeamsInteropQuickStart/MainPage.xaml.cs fájlhoz.
//Azure Communication Services resource connection string i.e = "endpoint=https://your-resource.communication.azure.net/;accesskey=your-access-key";
private const string connectionString_ = "";

Fontos

  • A kód futtatása előtt válassza ki a megfelelő platformot a Visual Studio Megoldásplatformok legördülő listájából. Azaz x64
  • Győződjön meg arról, hogy a "Fejlesztői mód" engedélyezve van Windows 10 (Fejlesztői beállítások)

A következő lépések nem fognak működni, ha ez nincs megfelelően konfigurálva

  1. Nyomja le az F5 billentyűt a projekt hibakeresési módban való elindításához.
  2. Illessze be a Teams-értekezlet érvényes hivatkozását a "Teams-értekezlet hivatkozása" mezőbe (lásd a következő szakaszt)
  3. A csevegés megkezdéséhez nyomja le a "Csatlakozás Teams-értekezlethez" gombot.

Fontos

Miután a hívó SDK kapcsolatot létesített a teams-értekezlettel Lásd: A Kommunikációs szolgáltatások meghívják a Windows alkalmazást, a csevegési műveletek kezeléséhez szükséges fő funkciók a következők: StartPollingForChatMessages és SendMessageButton_Click. Mindkét kódrészlet a ChatTeamsInteropQuickStart\MainPage.xaml.cs fájlban található.

        /// <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 ocurred 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;
        }

A Teams-értekezlet hivatkozása a Graph API-kkal kérhető le, amely a Graph dokumentációjában található. Ez a hivatkozás az erőforrás részeként jelenik meg, amely a onlineMeetingjoinWebUrl tulajdonság alatt érhető el.

A szükséges értekezlethivatkozást a Teams-értekezlet-összehívás bekapcsolódás url-címéről is beszerezheti. A Teams-értekezlet hivatkozása így néz ki: https://teams.microsoft.com/l/meetup-join/meeting_chat_thread_id/1606337455313?context=some_context_here.

Képernyőkép a befejezett csharp-alkalmazásról.

Megjegyzés

Bizonyos funkciók jelenleg nem támogatottak a Teamsszel való együttműködési forgatókönyvekben. További információ a támogatott funkciókról: Teams-értekezletek képességei a Teams külső felhasználói számára

Az erőforrások eltávolítása

Ha törölni és eltávolítani szeretne egy Communication Services-előfizetést, törölheti az erőforrást vagy az erőforráscsoportot. Az erőforráscsoport törlése a hozzá társított egyéb erőforrásokat is törli. További információ az erőforrások eltávolításáról.

Következő lépések

További információért tekintse át a következő cikkeket: