Snabbstart: Ansluta din chattapp till ett Teams-möte
Kom igång med Azure Communication Services genom att ansluta din chattlösning till Microsoft Teams.
I den här snabbstarten får du lära dig hur du chattar i ett Teams-möte med hjälp av Azure Communication Services Chat SDK för JavaScript.
Exempelkod
Hitta den färdiga koden för den här snabbstarten på GitHub.
Förutsättningar
- En Teams-distribution.
- En fungerande chattapp.
Ansluta till möteschatten
En Communication Services-användare kan ansluta till ett Teams-möte som en anonym användare med hjälp av den anropande SDK:t. När de ansluter till mötet läggs de också till som deltagare i möteschatten, där de kan skicka och ta emot meddelanden med andra användare i mötet. Användaren har inte åtkomst till chattmeddelanden som skickades innan de gick med i mötet och de kommer inte att kunna skicka eller ta emot meddelanden när mötet har avslutats. Om du vill ansluta till mötet och börja chatta kan du följa nästa steg.
Skapa ett nytt Node.js-program
Öppna terminalen eller kommandofönstret, skapa en ny katalog för din app och navigera till den.
mkdir chat-interop-quickstart && cd chat-interop-quickstart
Kör npm init -y
för att skapa en package.json fil med standardinställningar.
npm init -y
Installera chattpaketen
npm install
Använd kommandot för att installera nödvändiga Communication Services-SDK:er för 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
Alternativet --save
visar biblioteket som ett beroende i din package.json-fil .
Konfigurera appramverket
Den här snabbstarten använder Webpack för att paketera programtillgångarna. Kör följande kommando för att installera npm-paketen Webpack, webpack-cli och webpack-dev-server och lista dem som utvecklingsberoenden i din package.json:
npm install webpack@5.89.0 webpack-cli@5.1.4 webpack-dev-server@4.15.1 --save-dev
Skapa en index.html fil i rotkatalogen för projektet. Vi använder den här filen för att konfigurera en grundläggande layout som gör att användaren kan ansluta till ett möte och börja chatta.
Lägga till teams användargränssnittskontroller
Ersätt koden i index.html med följande kodfragment. Textrutan överst på sidan används för att ange möteskontexten för Teams. Knappen Anslut till Teams-möte används för att ansluta till det angivna mötet. Ett popup-fönster för chatt visas längst ned på sidan. Den kan användas för att skicka meddelanden i mötestråden och visas i realtid alla meddelanden som skickas i tråden medan Communication Services-användaren är medlem.
<!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>
Aktivera Teams användargränssnittskontroller
Ersätt innehållet i client.js-filen med följande kodfragment.
I kodfragmentet ersätter du
SECRET_CONNECTION_STRING
med kommunikationstjänstens anslutningssträng
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}`);
});
Visningsnamn för chatttrådsdeltagarna anges inte av Teams-klienten. Namnen returneras som null i API:et för att visa deltagare, i participantsAdded
händelsen och i participantsRemoved
händelsen. Visningsnamnen för chattdeltagarna kan hämtas från remoteParticipants
objektets call
fält. När du får ett meddelande om en ändring av listan kan du använda den här koden för att hämta namnet på den användare som lades till eller togs bort:
var displayName = call.remoteParticipants.find(p => p.identifier.communicationUserId == '<REMOTE_USER_ID>').displayName;
Kör koden
Webpack-användare kan använda webpack-dev-server
för att skapa och köra din app. Kör följande kommando för att paketera programvärden på en lokal webbserver:
npx webpack-dev-server --entry ./client.js --output bundle.js --debug --devtool inline-source-map
Öppna din webbläsare och gå till http://localhost:8080/
. Du bör se att appen startas enligt följande skärmbild:
Infoga teams-möteslänken i textrutan. Tryck på Anslut till Teams-möte för att ansluta till Teams-mötet. När Communication Services-användaren har blivit antagen till mötet kan du chatta inifrån ditt Communication Services-program. Gå till rutan längst ned på sidan för att börja chatta. För enkelhetens skull visar programmet bara de två sista meddelandena i chatten.
Kommentar
Vissa funktioner stöds för närvarande inte för samverkansscenarier med Teams. Läs mer om de funktioner som stöds i Teams mötesfunktioner för externa Teams-användare
I den här snabbstarten får du lära dig hur du chattar i ett Teams-möte med hjälp av Azure Communication Services Chat SDK för iOS.
Exempelkod
Om du vill gå vidare till slutet kan du ladda ned den här snabbstarten som ett exempel på GitHub.
Förutsättningar
- Ett Azure-konto med en aktiv prenumeration. Skapa ett konto kostnadsfritt
- En Mac som kör Xcode, tillsammans med ett giltigt utvecklarcertifikat installerat i nyckelringen.
- En Teams-distribution.
- En användaråtkomsttoken för azure-kommunikationstjänsten. Du kan också använda Azure CLI och köra kommandot med din anslutningssträng för att skapa en användare och en åtkomsttoken.
az communication user-identity token issue --scope voip chat --connection-string "yourConnectionString"
Mer information finns i Använda Azure CLI för att skapa och hantera åtkomsttoken.
Konfigurera
Skapa Xcode-projektet
I Xcode skapar du ett nytt iOS-projekt och väljer mallen Enkel vyapp. I den här självstudien används SwiftUI-ramverket, så du bör ange Språket till Swift och användargränssnittet till SwiftUI. Du kommer inte att skapa tester under den här snabbstarten. Avmarkera Inkludera tester.
Installera CocoaPods
Använd den här guiden för att installera CocoaPods på din Mac.
Installera paketet och beroenden med CocoaPods
Om du vill skapa en
Podfile
för ditt program öppnar du terminalen och navigerar till projektmappen och kör podd-init.Lägg till följande kod
Podfile
under målet och spara.
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
Kör
pod install
..xcworkspace
Öppna filen med Xcode.
Begär åtkomst till mikrofonen
För att få åtkomst till enhetens mikrofon måste du uppdatera appens informationsegenskapslista med en NSMicrophoneUsageDescription
. Du anger det associerade värdet till en string
som ingick i den dialogruta som systemet använder för att begära åtkomst från användaren.
Under målet väljer du fliken Info
och lägger till en sträng för "Sekretess – Beskrivning av mikrofonanvändning"
Inaktivera sandbox-miljö för användarskript
Några av skripten i de länkade biblioteken skriver filer under byggprocessen. Om du vill tillåta detta inaktiverar du sandbox-miljön för användarskript i Xcode.
Under bygginställningarna söker sandbox
du efter och anger User Script Sandboxing
till No
.
Ansluta till möteschatten
En Communication Services-användare kan ansluta till ett Teams-möte som en anonym användare med hjälp av den anropande SDK:t. När en användare har anslutit till Teams-mötet kan de skicka och ta emot meddelanden med andra mötesdeltagare. Användaren kommer inte att ha åtkomst till chattmeddelanden som skickats före anslutningen, och de kommer inte heller att kunna skicka eller ta emot meddelanden när de inte är med i mötet. Om du vill ansluta till mötet och börja chatta kan du följa nästa steg.
Konfigurera appramverket
Importera Azure Communication-paketen genom ContentView.swift
att lägga till följande kodfragment:
import AVFoundation
import SwiftUI
import AzureCommunicationCalling
import AzureCommunicationChat
Lägg ContentView.swift
till följande kodfragment precis ovanför deklarationen struct ContentView: View
:
let endpoint = "<ADD_YOUR_ENDPOINT_URL_HERE>"
let token = "<ADD_YOUR_USER_TOKEN_HERE>"
let displayName: String = "Quickstart User"
Ersätt <ADD_YOUR_ENDPOINT_URL_HERE>
med slutpunkten för din Communication Services-resurs.
Ersätt <ADD_YOUR_USER_TOKEN_HERE>
med den token som genererades ovan via Azure-klientkommandoraden.
Läs mer om användaråtkomsttoken: Användaråtkomsttoken
Ersätt Quickstart User
med det visningsnamn som du vill använda i chatten.
Om du vill lagra tillståndet lägger du till följande variabler i structen ContentView
:
@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] = []
Nu ska vi lägga till huvudtexten var för att lagra användargränssnittselementen. Vi kopplar affärslogik till dessa kontroller i den här snabbstarten. Lägg till följande kod i structen ContentView
:
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
}
}
Initiera ChatClient
Instansiera ChatClient
och aktivera meddelandemeddelanden. Vi använder realtidsmeddelanden för att ta emot chattmeddelanden.
Med huvudtexten konfigurerad lägger vi till funktionerna för att hantera konfigurationen av samtals- och chattklienter.
onAppear
I funktionen lägger du till följande kod för att initiera CallClient
och 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
}
Lägg till möteskopplingsfunktion
Lägg till följande funktion i structen ContentView
för att hantera anslutningen till mötet.
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"
}
}
}
Initiera ChatThreadClient
Vi initierar ChatThreadClient
när användaren har anslutit till mötet. Detta kräver att vi kontrollerar mötesstatusen från ombudet och sedan initierar ChatThreadClient
med när det är anslutet threadId
till mötet.
connectChat()
Skapa funktionen med följande kod:
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
}
}
Lägg till följande hjälpfunktion i , ContentView
som används för att parsa chatttråds-ID:t från teamets möteslänk, om möjligt. Om den här extraheringen misslyckas måste användaren manuellt ange chatttråds-ID:t med graph-API:er för att hämta tråd-ID:t.
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
}
Aktivera sändning av meddelanden
Lägg till funktionen i sendMessage()
ContentView
. Den här funktionen använder ChatThreadClient
för att skicka meddelanden från användaren.
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?"
}
}
}
Aktivera mottagande meddelanden
För att ta emot meddelanden implementerar vi hanteraren för ChatMessageReceived
händelser. När nya meddelanden skickas till tråden lägger den här hanteraren till meddelandena i variabeln meetingMessages
så att de kan visas i användargränssnittet.
Lägg först till följande struct i ContentView.swift
. Användargränssnittet använder data i struct för att visa våra chattmeddelanden.
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
)
}
}
Lägg sedan till funktionen i receiveMessage()
ContentView
. Detta anropas när en meddelandehändelse inträffar. Observera att du måste registrera dig för alla händelser som du vill hantera i -instruktionen switch
chatClient?.register()
via -metoden.
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
}
}
Slutligen måste vi implementera ombudshanteraren för anropsklienten. Den här hanteraren används för att kontrollera samtalsstatusen och initiera chattklienten när användaren ansluter till mötet.
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"
}
}
}
Lämna chatten
När användaren lämnar teamets möte rensar vi chattmeddelandena från användargränssnittet och lägger på samtalet. Den fullständiga koden visas nedan.
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"
}
}
Hämta en Teams-möteschatttråd för en Communication Services-användare
Mötesinformationen för Teams kan hämtas med graph-API:er, som beskrivs i Graph-dokumentationen. Communication Services Calling SDK accepterar en fullständig Teams-möteslänk eller ett mötes-ID. De returneras som en del av resursenonlineMeeting
, som är tillgänglig under egenskapen joinWebUrl
Med Graph-API:erna kan du också hämta threadID
. Svaret har ett chatInfo
objekt som innehåller threadID
.
Kör koden
Kör programmet.
Om du vill ansluta till Teams-mötet anger du din teams möteslänk i användargränssnittet.
När du har anslutit till teamets möte måste du släppa in användaren till mötet i teamets klient. När användaren är antagen och har anslutit till chatten kan du skicka och ta emot meddelanden.
Kommentar
Vissa funktioner stöds för närvarande inte för samverkansscenarier med Teams. Läs mer om de funktioner som stöds i Teams mötesfunktioner för externa Teams-användare
I den här snabbstarten får du lära dig hur du chattar i ett Teams-möte med hjälp av Azure Communication Services Chat SDK för Android.
Exempelkod
Om du vill gå vidare till slutet kan du ladda ned den här snabbstarten som ett exempel på GitHub.
Förutsättningar
- En Teams-distribution.
- En app för arbetssamtal.
Aktivera Teams-samverkan
En Communication Services-användare som ansluter till ett Teams-möte som gästanvändare kan endast komma åt mötets chatt när de har anslutit till Teams-mötessamtalet. Se Teams interop-dokumentationen för att lära dig hur du lägger till en Communication Services-användare i ett Teams-mötessamtal.
Du måste vara medlem i den ägande organisationen för båda entiteterna för att kunna använda den här funktionen.
Ansluta till möteschatten
När Teams-samverkan har aktiverats kan en Communication Services-användare ansluta teams-anropet som en extern användare med hjälp av Calling SDK. När du ansluter till samtalet läggs de också till som deltagare i möteschatten, där de kan skicka och ta emot meddelanden med andra användare i samtalet. Användaren har inte åtkomst till chattmeddelanden som skickades innan de anslöt till samtalet. Om du vill ansluta till mötet och börja chatta kan du följa nästa steg.
Lägg till chatt i Teams-samtalsappen
På modulnivån build.gradle
lägger du till beroendet för chatt-SDK:n.
Viktigt!
Känt problem: När du använder Android Chat och Calling SDK tillsammans i samma program fungerar inte funktionen för chatt-SDK:ns realtidsaviseringar. Du får ett problem med beroendelösning. När vi arbetar med en lösning kan du inaktivera funktionen för realtidsaviseringar genom att lägga till följande undantag i Chat SDK-beroendet i appens build.gradle
fil:
implementation ("com.azure.android:azure-communication-chat:2.0.3") {
exclude group: 'com.microsoft', module: 'trouter-client-android'
}
Lägga till teams användargränssnittslayout
Ersätt koden i activity_main.xml med följande kodfragment. Den lägger till indata för tråd-ID:t och för att skicka meddelanden, en knapp för att skicka det inskrivna meddelandet och en grundläggande chattlayout.
<?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>
Aktivera Teams användargränssnittskontroller
Importera paket och definiera tillståndsvariabler
Lägg till följande importer i innehållet MainActivity.java
i :
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;
Lägg till följande variabler i MainActivity
klassen:
// 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<>();
Ersätt <USER_ID>
med ID:t för användaren som initierar chatten.
Ersätt <COMMUNICATION_SERVICES_RESOURCE_ENDPOINT>
med slutpunkten för din Communication Services-resurs.
Initiera ChatThreadClient
När du har anslutit till mötet instansierar ChatThreadClient
du och gör chattkomponenterna synliga.
Uppdatera slutet av MainActivity.joinTeamsMeeting()
metoden med koden nedan:
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);
}
Aktivera sändning av meddelanden
Lägg till metoden i sendMessage()
MainActivity
. Den använder ChatThreadClient
för att skicka meddelanden för användarens räkning.
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("");
}
Aktivera avsökning för meddelanden och återge dem i programmet
Viktigt!
Känt problem: Eftersom chatt-SDK:ns realtidsaviseringar inte fungerar tillsammans med anropande SDK:er måste vi avsöka API:et GetMessages
med fördefinierade intervall. I vårt exempel använder vi 3-sekundersintervall.
Vi kan hämta följande data från meddelandelistan som returneras av API:et GetMessages
:
- Meddelandena
text
ochhtml
i tråden sedan anslutningen - Ändringar i trådlistan
- Uppdateringar till trådavsnittet
MainActivity
I klassen lägger du till en hanterare och en körningsbar uppgift som ska köras med 3 sekunders intervall:
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);
}
};
Observera att aktiviteten redan har startats i slutet av MainActivity.joinTeamsMeeting()
metoden som uppdaterades i initieringssteget.
Slutligen lägger vi till metoden för att köra frågor mot alla tillgängliga meddelanden i tråden, parsa dem efter meddelandetyp och visa och html
text
:
private void retrieveMessages() throws InterruptedException {
// Initialize the list of messages not yet processed
ArrayList<ChatMessage> newChatMessages = new ArrayList<>();
// Retrieve all messages accessible to the user
PagedAsyncStream<ChatMessage> messagePagedAsyncStream
= this.chatThreadAsyncClient.listMessages(new ListChatMessagesOptions(), null);
// Set up a lock to wait until all returned messages have been inspected
CountDownLatch latch = new CountDownLatch(1);
// Traverse the returned messages
messagePagedAsyncStream.forEach(new AsyncStreamHandler<ChatMessage>() {
@Override
public void onNext(ChatMessage message) {
// Messages that should be displayed in the chat
if ((message.getType().equals(ChatMessageType.TEXT)
|| message.getType().equals(ChatMessageType.HTML))
&& !chatMessages.contains(message.getId())) {
newChatMessages.add(message);
chatMessages.add(message.getId());
}
if (message.getType().equals(ChatMessageType.PARTICIPANT_ADDED)) {
// Handle participants added to chat operation
List<ChatParticipant> participantsAdded = message.getContent().getParticipants();
CommunicationIdentifier participantsAddedBy = message.getContent().getInitiatorCommunicationIdentifier();
}
if (message.getType().equals(ChatMessageType.PARTICIPANT_REMOVED)) {
// Handle participants removed from chat operation
List<ChatParticipant> participantsRemoved = message.getContent().getParticipants();
CommunicationIdentifier participantsRemovedBy = message.getContent().getInitiatorCommunicationIdentifier();
}
if (message.getType().equals(ChatMessageType.TOPIC_UPDATED)) {
// Handle topic updated
String newTopic = message.getContent().getTopic();
CommunicationIdentifier topicUpdatedBy = message.getContent().getInitiatorCommunicationIdentifier();
}
}
@Override
public void onError(Throwable throwable) {
latch.countDown();
}
@Override
public void onComplete() {
latch.countDown();
}
});
// Wait until the operation completes
latch.await(1, TimeUnit.MINUTES);
// Returned messages should be ordered by the createdOn field to be guaranteed a proper chronological order
// For the purpose of this demo we will just reverse the list of returned messages
Collections.reverse(newChatMessages);
for (ChatMessage chatMessage : newChatMessages)
{
LinearLayout chatBoxLayout = findViewById(R.id.chat_box_layout);
// For the purpose of this demo UI, we don't need to use HTML formatting for displaying messages
// The Teams client always sends html messages in meeting chats
String message = Html.fromHtml(chatMessage.getContent().getMessage(), Html.FROM_HTML_MODE_LEGACY).toString().trim();
TextView messageView = new TextView(this);
messageView.setText(message);
// Compare with sender identifier and align LEFT/RIGHT accordingly
// Azure Communication Services users are of type CommunicationUserIdentifier
CommunicationIdentifier senderId = chatMessage.getSenderCommunicationIdentifier();
if (senderId instanceof CommunicationUserIdentifier
&& InitiatorId.equals(((CommunicationUserIdentifier) senderId).getId())) {
messageView.setTextColor(Color.GREEN);
messageView.setGravity(Gravity.RIGHT);
} else {
messageView.setTextColor(Color.BLUE);
messageView.setGravity(Gravity.LEFT);
}
// Note: messages with the deletedOn property set to a timestamp, should be marked as deleted
// Note: messages with the editedOn property set to a timestamp, should be marked as edited
messageView.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
chatBoxLayout.addView(messageView);
}
}
Visningsnamn för chatttrådsdeltagarna anges inte av Teams-klienten. Namnen returneras som null i API:et för att visa deltagare, i participantsAdded
händelsen och i participantsRemoved
händelsen. Visningsnamnen för chattdeltagarna kan hämtas från remoteParticipants
objektets call
fält.
Hämta en Teams-möteschatttråd för en Communication Services-användare
Mötesinformationen för Teams kan hämtas med graph-API:er, som beskrivs i Graph-dokumentationen. Communication Services Calling SDK accepterar en fullständig Teams-möteslänk eller ett mötes-ID. De returneras som en del av resursenonlineMeeting
, som är tillgänglig under egenskapen joinWebUrl
Med Graph-API:erna kan du också hämta threadID
. Svaret har ett chatInfo
objekt som innehåller threadID
.
Kör koden
Appen kan nu startas med knappen "Kör app" i verktygsfältet (Skift+F10).
Om du vill ansluta till Teams-mötet och chatten anger du din teams möteslänk och tråd-ID:t i användargränssnittet.
När du har anslutit till teamets möte måste du släppa in användaren till mötet i teamets klient. När användaren är antagen och har anslutit till chatten kan du skicka och ta emot meddelanden.
Kommentar
Vissa funktioner stöds för närvarande inte för samverkansscenarier med Teams. Läs mer om de funktioner som stöds i Teams mötesfunktioner för externa Teams-användare
I den här snabbstarten lär du dig att chatta i ett Teams-möte med hjälp av Azure Communication Services Chat SDK för C#.
Exempelkod
Hitta koden för den här snabbstarten på GitHub.
Förutsättningar
- En Teams-distribution.
- Ett Azure-konto med en aktiv prenumeration. Skapa ett konto utan kostnad.
- Installera Visual Studio 2019 med Universell Windows-plattform utvecklingsarbetsbelastning.
- En distribuerad Communication Services-resurs. Skapa en Communication Services-resurs.
- En möteslänk för Teams.
Ansluta till möteschatten
En Communication Services-användare kan ansluta till ett Teams-möte som en anonym användare med hjälp av den anropande SDK:t. När de ansluter till mötet läggs de också till som deltagare i möteschatten, där de kan skicka och ta emot meddelanden med andra användare i mötet. Användaren har inte åtkomst till chattmeddelanden som skickades innan de gick med i mötet och de kommer inte att kunna skicka eller ta emot meddelanden när mötet har avslutats. Om du vill ansluta till mötet och börja chatta kan du följa nästa steg.
Kör koden
Du kan skapa och köra koden i Visual Studio. Observera de lösningsplattformar som vi stöder: x64
,x86
och ARM64
.
- Öppna en instans av PowerShell, Windows-terminal, Kommandotolken eller motsvarande och navigera till den katalog som du vill klona exemplet till.
git clone https://github.com/Azure-Samples/Communication-Services-dotnet-quickstarts.git
- Öppna projektet ChatTeamsInteropQuickStart/ChatTeamsInteropQuickStart.csproj i Visual Studio.
- Installera följande NuGet-paketversioner (eller senare):
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
- När Communication Services-resursen anskaffas i förhandskraven lägger du till anslutningssträngen i filen 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_ = "";
Viktigt!
- Välj rätt plattform i listrutan "Lösningsplattformar" i Visual Studio innan du kör koden, d.v.s.
x64
- Kontrollera att utvecklarläget i Windows 10 är aktiverat (developer Inställningar)
Nästa steg fungerar inte om detta inte är korrekt konfigurerat
- Tryck på F5 för att starta projektet i felsökningsläge.
- Klistra in en giltig möteslänk för teams i rutan Möteslänk för Teams (se nästa avsnitt)
- Tryck på "Join Teams meeting" (Anslut till Teams-mötet) för att börja chatta.
Viktigt!
När den anropande SDK:n upprättar anslutningen till teammötet Se Kommunikationstjänster som anropar Windows-appen är de viktigaste funktionerna för att hantera chattåtgärder: StartPollingForChatMessages och SendMessageButton_Click. Båda kodfragmenten finns i 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;
}
Hämta en Teams-möteslänk
Teams möteslänk kan hämtas med graph-API:er, som beskrivs i Graph-dokumentationen. Den här länken returneras som en del av resursen onlineMeeting
som är tillgänglig under egenskapenjoinWebUrl
.
Du kan också hämta den nödvändiga möteslänken från URL:en för att ansluta till mötet i själva Teams-mötesbjudningen.
En Teams-möteslänk ser ut så här: https://teams.microsoft.com/l/meetup-join/meeting_chat_thread_id/1606337455313?context=some_context_here
.
Om din teams-länk har ett annat format än detta måste du hämta tråd-ID:t med hjälp av Graph-API:et.
Kommentar
Vissa funktioner stöds för närvarande inte för samverkansscenarier med Teams. Läs mer om de funktioner som stöds i Teams mötesfunktioner för externa Teams-användare
Rensa resurser
Om du vill rensa och ta bort en Communication Services-prenumeration kan du ta bort resursen eller resursgruppen. Om du tar bort resursgruppen tas även alla andra resurser som är associerade med den bort. Läs mer om att rensa resurser.
Nästa steg
Mer information finns i följande artiklar:
- Kolla in vårt chatthjälteexempel
- Läs mer om hur chatt fungerar