Основные возможности Live Share
Пакет Live Share SDK можно добавить в расширения sidePanel
и meetingStage
контексты ваших собраний с минимальными усилиями. Пакет SDK также можно использовать в контекстах чата и каналов content
, таких как настраиваемые вкладки, статические вкладки и представление этапов совместной работы.
Примечание.
Контексты live Share content
в чате и каналах поддерживаются только в классических и веб-клиентах Teams.
В этой статье рассматривается интеграция пакета Live Share SDK в ваше приложение, а также основные возможности пакета SDK.
Предварительные требования
Установка пакета SDK для JavaScript
Пакет SDK Live Share — это пакет JavaScript, опубликованный в npm, который можно скачать через npm или yarn. Необходимо также установить одноранговые зависимости Live Share, в том числе fluid-framework
и @fluidframework/azure-client
. Если вы используете Live Share в приложении вкладки, также необходимо установить @microsoft/teams-js
версию 2.23.0
или более позднюю. Если вы хотите использовать класс для разработки локального TestLiveShareHost
браузера, необходимо установить @fluidframework/test-client-utils
пакеты и start-server-and-test
в .devDependencies
NPM
npm install @microsoft/live-share fluid-framework @fluidframework/azure-client --save
npm install @microsoft/teams-js --save
npm install @fluidframework/test-client-utils start-server-and-test --save-dev
Yarn
yarn add @microsoft/live-share fluid-framework @fluidframework/azure-client
yarn add @microsoft/teams-js
yarn add @fluidframework/test-client-utils -dev
Регистрация разрешений RSC
Чтобы включить пакет SDK Live Share для расширения вкладки, необходимо сначала добавить следующие разрешения RSC в манифест приложения:
{
// ...rest of your manifest here
"configurableTabs": [
{
"configurationUrl": "<<YOUR_CONFIGURATION_URL>>",
"canUpdateConfiguration": true,
"scopes": [
"groupchat",
"team"
],
"context": [
// meeting contexts
"meetingSidePanel",
"meetingStage",
// content contexts
"privateChatTab",
"channelTab",
"meetingChatTab"
]
}
],
"validDomains": [
"<<BASE_URI_ORIGIN>>"
],
"authorization": {
"permissions": {
"resourceSpecific": [
// ...other permissions here
{
"name": "LiveShareSession.ReadWrite.Chat",
"type": "Delegated"
},
{
"name": "LiveShareSession.ReadWrite.Group",
"type": "Delegated"
},
{
"name": "MeetingStage.Write.Chat",
"type": "Delegated"
},
{
"name": "ChannelMeetingStage.Write.Group",
"type": "Delegated"
}
]
}
}
}
Присоединение к сеансу
Выполните действия, чтобы присоединиться к сеансу, связанному с собранием, чатом или каналом пользователя.
- Инициализируйте
LiveShareClient
. - Определение структур данных для синхронизации. Например,
LiveState
илиSharedMap
. - Присоединение к контейнеру.
Пример.
import { LiveShareClient, LiveState } from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
import { SharedMap } from "fluid-framework";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: {
liveState: LiveState,
sharedMap: SharedMap,
},
};
const { container } = await liveShare.joinContainer(schema);
// ... ready to start app sync logic
Это все, что потребовалось для настройки контейнера и присоединения к сеансу, сопоставленного с собранием, чатом или каналом. Теперь давайте рассмотрим различные типы распределенных структур данных, которые можно использовать с Live Share SDK.
Совет
Убедитесь, что пакет SDK для клиента Teams инициализирован перед вызовом LiveShareHost.create()
.
Структуры данных Live Share
Пакет SDK Live Share включает набор новых структур распределенных данных, которые расширяют класс Fluid DataObject
, предоставляя новые типы объектов с отслеживанием состояния и без отслеживания состояния. В отличие от структур данных Fluid, классы Live Share LiveDataObject
не записывают изменения в контейнер Fluid, что обеспечивает более быструю синхронизацию. Кроме того, эти классы были разработаны с нуля для распространенных сценариев в собраниях, чатах и каналах Teams. Распространенные сценарии включают синхронизацию содержимого, которое просматривает выступающий, отображение метаданных для каждого пользователя в сеансе или отображение таймера обратного отсчета.
Динамический объект | Описание |
---|---|
LivePresence | Узнайте, какие пользователи находятся в сети, задайте настраиваемые свойства для каждого пользователя и транслируйте изменения, связанные с их присутствием. |
LiveState | Синхронизация любого сериализуемого state значения JSON. |
LiveTimer | Синхронизация таймера обратного отсчета для заданного интервала. |
LiveEvent | Трансляция отдельных событий с помощью любых настраиваемых атрибутов данных в полезных данных. |
LiveFollowMode | Следите за конкретными пользователями, представляемые всем участникам сеанса, а также запуск или завершение приостановки. |
Пример LivePresence
Класс LivePresence
упрощает отслеживание того, кто находится в сеансе. При вызове .initialize()
методов или .updatePresence()
можно назначить пользовательские метаданные для этого пользователя, такие как изображение профиля, идентификатор просматриваемого содержимого и многое другое. Прослушивая presenceChanged
события, каждый клиент получает последний LivePresenceUser
объект, сворав все обновления присутствия в одну запись для каждого уникального userId
объекта .
Ниже приведено несколько примеров, в которых LivePresence
можно использовать в приложении.
- Получение Microsoft Teams
userId
,displayName
иroles
каждого пользователя в сеансе. - Отображение пользовательских сведений о каждом пользователе, подключенном к сеансу, например URL-адрес изображения профиля.
- Синхронизация координат в трехмерной сцене, где находится аватар каждого пользователя.
- Отчет о положении курсора каждого пользователя в текстовом документе.
- Публикация ответа каждого пользователя на вопрос ледокола во время действия группы.
import {
LiveShareClient,
LivePresence,
PresenceState,
} from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: {
presence: LivePresence,
},
};
const { container } = await liveShare.joinContainer(schema);
const presence = container.initialObjects.presence;
// Register listener for changes to each user's presence.
// This should be done before calling `.initialize()`.
presence.on("presenceChanged", (user, local) => {
console.log("A user presence changed:");
console.log("- display name:", user.displayName);
console.log("- state:", user.state);
console.log("- custom data:", user.data);
console.log("- change from local client", local);
console.log("- change impacts local user", user.isLocalUser);
});
// Define the initial custom data for the local user (optional).
const customUserData = {
picture: "DEFAULT_PROFILE_PICTURE_URL",
readyToStart: false,
};
// Start receiving incoming presence updates from the session.
// This will also broadcast the user's `customUserData` to others in the session.
await presence.initialize(customUserData);
// Send a presence update, in this case once a user is ready to start an activity.
// If using role verification, this will throw an error if the user doesn't have the required role.
await presence.update({
...customUserData,
readyToStart: true,
});
Пользователи, присоединяющиеся к сеансу с одного устройства, имеют одну LivePresenceUser
запись, которая предоставляется всем их устройствам. Чтобы получить доступ к последним data
и state
для каждого из активных подключений, можно использовать getConnections()
API из LivePresenceUser
класса . Возвращается список LivePresenceConnection
объектов. Вы можете увидеть, является ли данный LivePresenceConnection
экземпляр локальным устройством isLocalConnection
, с помощью свойства .
Каждый LivePresenceUser
экземпляр и LivePresenceConnection
имеет state
свойство , которое может иметь значение online
, offline
или away
. Событие presenceChanged
создается при изменении состояния пользователя. Например, если пользователь отключается от сеанса или закрывает приложение, его состояние изменяется на offline
.
Примечание.
Обновление до может занять до 20 секунд LivePresenceUser
state
offline
после отключения пользователя от сеанса.
Пример LiveState
Класс LiveState
позволяет синхронизировать простое состояние приложения для подключенных участников.
LiveState
синхронизирует одно state
значение, что позволяет синхронизировать любое сериализуемое значение JSON, например string
, number
или object
.
Ниже приведено несколько примеров, в которых LiveState
можно использовать в приложении.
- Задание идентификатора пользователя текущего докладчика для создания функции контроля .
- Синхронизация текущего пути маршрута для приложения, чтобы убедиться, что все пользователи находятся на одной странице. Например,
/whiteboard/:whiteboardId
. - Поддержание идентификатора содержимого, просматриваемого текущим выступающим. Например, на
taskId
доске задач. - Синхронизация текущего шага в многокрутном групповом действии. Например, этап угадания во время игры Agile Poker.
- Синхронизация позиции прокрутки для функции отслеживания.
Примечание.
В отличие от SharedMap
, state
значение в LiveState
сбрасывается после отключения всех пользователей от сеанса.
Пример:
import { LiveShareClient, LiveState } from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: { appState: LiveState },
};
const { container } = await liveShare.joinContainer(schema);
const { appState } = container.initialObjects;
// Register listener for changes to the state.
// This should be done before calling `.initialize()`.
appState.on("stateChanged", (planetName, local, clientId) => {
// Update app with newly selected planet.
// See which user made the change (optional)
const clientInfo = await appState.getClientInfo(clientId);
});
// Set a default value and start listening for changes.
// This default value will not override existing for others in the session.
const defaultState = "Mercury";
await appState.initialize(defaultState);
// `.set()` will change the state for everyone in the session.
// If using role verification, this will throw an error if the user doesn't have the required role.
await appState.set("Earth");
Пример LiveEvent
LiveEvent
— это отличный способ отправки простых событий другим подключенным клиентам, которые необходимы только во время доставки. Он полезен для таких сценариев, как отправка уведомлений о сеансе или реализация пользовательских реакций.
import { LiveEvent, LiveShareClient } from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: { customReactionEvent: LiveEvent },
};
const { container } = await liveShare.joinContainer(schema);
const { customReactionEvent } = container.initialObjects;
// Register listener to receive events sent through this object.
// This should be done before calling `.initialize()`.
customReactionEvent.on("received", async (kudosReaction, local, clientId) => {
console.log("Received reaction:", kudosReaction, "from clientId", clientId);
// See which user made the change (optional)
const clientInfo = await customReactionEvent.getClientInfo(clientId);
// Display notification in your UI
});
// Start listening for incoming events
await customReactionEvent.initialize();
// `.send()` will send your event value to everyone in the session.
// If using role verification, this will throw an error if the user doesn't have the required role.
const kudosReaction = {
emoji: "❤️",
forUserId: "SOME_OTHER_USER_ID",
};
await customReactionEvent.send(kudosReaction);
Пример LiveTimer
LiveTimer
предоставляет простой таймер обратного отсчета, который синхронизируется для всех подключенных участников. Он полезен для сценариев с ограничением по времени, таких как таймер групповой медитации или круглый таймер для игры. Его также можно использовать для планирования задач для всех участников сеанса, например для отображения запроса напоминания.
import { LiveShareClient, LiveTimer } from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: { timer: LiveTimer },
};
const { container } = await liveShare.joinContainer(schema);
const { timer } = container.initialObjects;
// Register listeners for timer changes
// This should be done before calling `.initialize()`.
// Register listener for when the timer starts its countdown
timer.on("started", (config, local) => {
// Update UI to show timer has started
});
// Register listener for when a paused timer has resumed
timer.on("played", (config, local) => {
// Update UI to show timer has resumed
});
// Register listener for when a playing timer has paused
timer.on("paused", (config, local) => {
// Update UI to show timer has paused
});
// Register listener for when a playing timer has finished
timer.on("finished", (config) => {
// Update UI to show timer is finished
});
// Register listener for the timer progressed by 20 milliseconds
timer.on("onTick", (milliRemaining) => {
// Update UI to show remaining time
});
// Start synchronizing timer events for users in session
await timer.initialize();
// Start a 60 second timer for users in the session.
// If using role verification, this will throw an error if the user doesn't have the required role.
const durationInMilliseconds = 1000 * 60;
await timer.start(durationInMilliseconds);
// Pause the timer for users in session
// If using role verification, this will throw an error if the user doesn't have the required role.
await timer.pause();
// Resume the timer for users in session
// If using role verification, this will throw an error if the user doesn't have the required role.
await timer.play();
Пример LiveFollowMode
Класс LiveFollowMode
объединяет LivePresence
и LiveState
в один класс, что позволяет легко реализовать режимы подписчиков и выступающих в приложении. Это позволяет реализовать знакомые шаблоны из популярных приложений для совместной работы, таких как PowerPoint Live, Excel Live и Доска. В отличие от общего доступа к экрану, LiveFollowMode
позволяет отображать содержимое с высоким качеством, улучшенными специальными возможностями и повышенной производительностью. Пользователи могут легко переключаться между своими личными представлениями и следить за другими пользователями.
Функцию startPresenting()
можно использовать для управления приложением для всех остальных пользователей в сеансе. Кроме того, можно разрешить пользователям по отдельности выбирать определенных пользователей, за которыми они хотят следовать с помощью followUser()
функции . В обоих сценариях пользователи могут временно войти в закрытое представление с beginSuspension()
функцией или синхронизироваться с выступающим с функцией endSuspension()
. Между тем, update()
функция позволяет локальному пользователю информировать других клиентов в сеансе о своих собственных личных stateValue
данных .
LivePresence
Как и , вы можете прослушивать изменения каждого пользователя stateValue
с помощью presenceChanged
прослушивателя событий.
LiveFollowMode
также предоставляет state
объект , который динамически обновляется в зависимости от пользователя, на который следует локальный пользователь. Например, если локальный пользователь ни за кем не следит, state.value
свойство соответствует последней stateValue
трансляции локального пользователя через update()
. Однако если локальный пользователь следит за выступающим, state.value
свойство соответствует последнему stateValue
. Как и LiveState
, вы можете прослушивать изменения state
значения с помощью stateChanged
прослушивателя событий. Дополнительные сведения об объекте см. в справочнике state
по интерфейсу IFollowModeState.
Ниже приведено несколько примеров, которые можно использовать LiveFollowMode
в приложении:
- Синхронизация позиций камеры в трехмерной сцене для совместного выполнения проверки дизайна.
- Обновите ,
slideId
чтобы открыть в карусели для продуктивных презентаций и обсуждений. - Широковещательный
path
для открытия на маршрутизаторе приложения.
Пример:
import {
LiveShareClient,
LiveFollowMode,
FollowModeType,
} from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: {
followMode: LiveFollowMode,
},
};
const { container } = await liveShare.joinContainer(schema);
const followMode = container.initialObjects.followMode;
// As an example, we will assume there is a button in the application document
const button = document.getElementById("action-button");
// As an example, we will assume there is a div with text showing the follow state
const infoText = document.getElementById("info-text");
// Register listener for changes to the `state` value to use in your app.
// This should be done before calling `.initialize()`.
followMode.on("stateChanged", (state, local, clientId) => {
console.log("The state changed:");
console.log("- state value:", state.value);
console.log("- follow mode type:", state.type);
console.log("- following user id:", state.followingUserId);
console.log(
"- count of other users also following user",
state.otherUsersCount
);
console.log(
"- state.value references local user's stateValue",
state.isLocalValue
);
// Can optionally get the relevant user's presence object
const followingUser = followMode.getUserForClient(clientId);
switch (state.type) {
case FollowModeType.local: {
// Update app to reflect that the user isn't following anyone and there is no presenter.
infoText.innerHTML = "";
// Show a "Start presenting" button in your app.
button.innerHTML = "Start presenting";
button.onclick = followMode.startPresenting;
// Note: state.isLocalValue will be true.
break;
}
case FollowModeType.activeFollowers: {
// Update app to reflect that the local user is being followed by other users.
infoText.innerHTML = `${state.otherUsersCount} users are following you`;
// Does not mean that the local user is presenting to everyone, so you can still show the "Start presenting" button.
button.innerHTML = "Present to all";
button.onclick = followMode.startPresenting;
// Note: state.isLocalValue will be true.
break;
}
case FollowModeType.activePresenter: {
// Update app to reflect that the local user is actively presenting to everyone.
infoText.innerHTML = `You are actively presenting to everyone`;
// Show a "Stop presenting" button in your app.
button.innerHTML = "Stop presenting";
button.onclick = followMode.stopPresenting;
// Note: state.isLocalValue will be true.
break;
}
case FollowModeType.followPresenter: {
// The local user is following a remote presenter.
infoText.innerHTML = `${followingUser?.displayName} is presenting to everyone`;
// Show a "Take control" button in your app.
button.innerHTML = "Take control";
button.onclick = followMode.startPresenting;
// Note: state.isLocalValue will be false.
break;
}
case FollowModeType.suspendFollowPresenter: {
// The local user is following a remote presenter but has an active suspension.
infoText.innerHTML = `${followingUser?.displayName} is presenting to everyone`;
// Show a "Sync to presenter" button in your app.
button.innerHTML = "Sync to presenter";
button.onclick = followMode.endSuspension;
// Note: state.isLocalValue will be true.
break;
}
case FollowModeType.followUser: {
// The local user is following a specific remote user.
infoText.innerHTML = `You are following ${followingUser?.displayName}`;
// Show a "Stop following" button in your app.
button.innerHTML = "Stop following";
button.onclick = followMode.stopFollowing;
// Note: state.isLocalValue will be false.
break;
}
case FollowModeType.suspendFollowUser: {
// The local user is following a specific remote user but has an active suspension.
infoText.innerHTML = `You were following ${followingUser?.displayName}`;
// Show a "Resume following" button in your app.
button.innerHTML = "Resume following";
button.onclick = followMode.endSuspension;
// Note: state.isLocalValue will be true.
break;
}
default: {
break;
}
}
const newCameraPosition = state.value;
// TODO: apply new camera position
});
// Register listener for changes to each user's personal state updates.
// This should be done before calling `.initialize()`.
followMode.on("presenceChanged", (user, local) => {
console.log("A user presence changed:");
console.log("- display name:", user.displayName);
console.log("- state value:", user.data?.stateValue);
console.log("- user id user is following:", user.data?.followingUserId);
console.log("- change from local client", local);
console.log("- change impacts local user", user.isLocalUser);
// As an example, we will assume there is a button for each user in the session.
document.getElementById(`follow-user-${user.userId}-button`).onclick = () => {
followMode.followUser(user.userId);
};
// Update 3D scene to reflect this user's camera position (e.g., orb + display name)
const userCameraPosition = user.data?.stateValue;
});
// Define the initial stateValue for the local user (optional).
const startingCameraPosition = {
x: 0,
y: 0,
z: 0,
};
// Start receiving incoming presence updates from the session.
// This will also broadcast the user's `startingCameraPosition` to others in the session.
await followMode.initialize(startingCameraPosition);
// Example of an event listener for a camera position changed event.
// For something like a camera change event, you should use a debounce function to prevent sending updates too frequently.
// Note: it helps to distinguish changes initiated by the local user (e.g., drag mouse) separately from other change events.
function onCameraPositionChanged(position, isUserAction) {
// Broadcast change to other users so that they have their latest camera position
followMode.update(position);
// If the local user changed the position while following another user, we want to suspend.
// Note: helps to distinguish changes initiated by the local user (e.g., drag mouse) separately from other change events.
if (!isUserAction) return;
switch (state.type) {
case FollowModeType.followPresenter:
case FollowModeType.followUser: {
// This will trigger a "stateChanged" event update for the local user only.
followMode.beginSuspension();
break;
}
default: {
// No need to suspend for other types
break;
}
}
}
В meetingStage
контекстах пользователи синхронно взаимодействуют и представляют презентации, чтобы упростить более продуктивные обсуждения. Когда пользователь представляет содержимое на стадии собрания, необходимо вызвать startPresenting()
API для первоначального докладчика. В content
таких контекстах, как совместное представление этапов, содержимое чаще всего используется асинхронно. В этом случае лучше разрешить пользователям участвовать в совместной работе в режиме реального времени, например с помощью кнопки "Подписаться".
teamsJs.app.getContext()
С помощью API в пакете SDK для JavaScript для Teams можно легко настроить функциональность соответствующим образом.
Пример:
import {
LiveShareClient,
LiveFollowMode,
FollowModeType,
} from "@microsoft/live-share";
import {
app,
meeting,
FrameContexts,
LiveShareHost,
} from "@microsoft/teams-js";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: {
followMode: LiveFollowMode,
},
};
const { container } = await liveShare.joinContainer(schema);
const followMode = container.initialObjects.followMode;
// Get teamsJs context
const context = await app.getContext();
// Take control if in meetingStage context and local user is initial presenter
if (context.page?.frameContext === FrameContexts.meetingStage) {
// Take control if in meetingStage context and local user is initial presenter
meeting.getAppContentStageSharingState((error, state) => {
const isShareInitiator = state?.isShareInitiator;
if (!isShareInitiator) return;
// The user is the initial presenter, so we "take control"
await followMode.startPresenting();
});
}
// TODO: rest of app logic
Проверка ролей для динамических структур данных
Собрания в Teams включают звонки, собрания всех рук и онлайн-классы. Участники собрания могут охватывать различные организации, иметь разные привилегии или иметь разные цели. Следовательно, важно уважать привилегии различных ролей пользователей во время собраний. Динамические объекты предназначены для поддержки проверки ролей, что позволяет определить роли, которым разрешено отправлять сообщения для каждого отдельного динамического объекта. Например, вы выбрали параметр, разрешающий только выступающим и организаторам собраний управлять воспроизведением видео. Однако гости и участники по-прежнему могут запросить следующие видео для просмотра.
Примечание.
При доступе к Live Share из контекста чата content
или канала все пользователи Organizer
будут иметь роли и Presenter
.
В следующем примере, где только выступающие и организаторы могут управлять, LiveState
используется для синхронизации пользователя, являющегося активным выступающим:
import {
LiveShareClient,
LiveState,
UserMeetingRole,
} from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: { appState: LiveState },
};
const { container } = await liveShare.joinContainer(schema);
const { appState } = container.initialObjects;
// Register listener for changes to state
appState.on("stateChanged", (state, local) => {
// Update local app state
});
// Set roles who can change state and start listening for changes
const initialState = {
documentId: "INITIAL_DOCUMENT_ID",
};
const allowedRoles = [UserMeetingRole.organizer, UserMeetingRole.presenter];
await appState.initialize(initialState, allowedRoles);
async function onSelectEditMode(documentId) {
try {
await appState.set({
documentId,
});
} catch (error) {
console.error(error);
}
}
async function onSelectPresentMode(documentId) {
try {
await appState.set({
documentId,
presentingUserId: "LOCAL_USER_ID",
});
} catch (error) {
console.error(error);
}
}
Перед реализацией проверки роли в приложении, особенно роли организатора, выслушайте своих клиентов, чтобы понять их сценарии. Нет никакой гарантии, что организатор собрания будет присутствовать в собрании. Как правило, все пользователи являются организатором или выступающим при совместной работе в организации. Если пользователь является участником, то обычно это осознанное решение, принятое организатором собрания.
В некоторых случаях у пользователя может быть несколько ролей. Например, организатор также является выступающим. Кроме того, участники собрания, которые являются внешними для клиента, в котором размещено собрание, имеют роль гостя , но также могут иметь права докладчика . Это обеспечивает большую гибкость при использовании проверки ролей в приложении.
Примечание.
Пакет SDK Live Share не поддерживается для гостевых пользователей в собраниях каналов.
Гибко распределенные структуры данных
Пакет Live Share SDK поддерживает любую распределенную структуру данных, включенную в Fluid Framework. Эти функции служат набором примитивов, которые можно использовать для создания надежных сценариев совместной работы, таких как обновление списка задач в режиме реального времени или совместное редактирование текста в HTML <textarea>
.
LiveDataObject
В отличие от классов, упомянутых в этой статье, структуры данных Fluid не сбрасываются после закрытия приложения. Это идеально подходит для таких сценариев, как собрания sidePanel
и content
контексты, когда пользователи часто закрывают и повторно открывают приложение.
Fluid Framework официально поддерживает следующие типы распределенных структур данных:
Общий объект | Описание |
---|---|
SharedMap | Распределенное хранилище пары \"ключ -значение\". Задайте любой сериализуемый объект JSON для заданного ключа, чтобы синхронизировать этот объект для всех пользователей, находящихся в сеансе. |
SharedSegmentSequence | Структура данных, подобная списку, для хранения набора элементов (называемых сегментами) в заданных позициях. |
SharedString | Последовательность распределенных строк, оптимизированная для редактирования текста документов или текстовых областей. |
Давайте рассмотрим принцип работы SharedMap
. В этом примере мы использовали SharedMap
для создания функции списка воспроизведения.
import { LiveShareClient } from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
import { SharedMap } from "fluid-framework";
// Join the Fluid container
const host = LiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: { playlistMap: SharedMap },
};
const { container } = await liveShare.joinContainer(schema);
const playlistMap = container.initialObjects.playlistMap;
// Register listener for changes to values in the map
playlistMap.on("valueChanged", (changed, local) => {
const video = playlistMap.get(changed.key);
// Update UI with added video
});
function onClickAddToPlaylist(video) {
// Add video to map
playlistMap.set(video.id, video);
}
Примечание.
Основные объекты Fluid Framework DDS не поддерживают проверку роли собрания. Все участники собрания могут изменять данные, хранящиеся в этих объектах.
Тестирование локального браузера
Вы можете локально протестировать пакет SDK Live Share в браузере TestLiveShareHost
с помощью класса , не устанавливая приложение в Teams. Это полезно для тестирования основных возможностей совместной работы приложения в знакомой localhost
среде.
Пример:
import {
LiveShareClient,
TestLiveShareHost,
LiveState,
} from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
import { SharedMap } from "fluid-framework";
/**
* Detect whether you are in Teams or local environment using your preferred method.
* Options for this include: environment variables, URL params, Teams FX, etc.
*/
const inTeams = process.env.IN_TEAMS;
// Join the Fluid container
const host = inTeams ? LiveShareHost.create() : TestLiveShareHost.create();
const liveShare = new LiveShareClient(host);
const schema = {
initialObjects: {
liveState: LiveState,
sharedMap: SharedMap,
},
};
const { container } = await liveShare.joinContainer(schema);
// ... ready to start app sync logic
Класс TestLiveShareHost
использует tinylicious
тестовый сервер из Fluid Framework, а не рабочую службу Azure Fluid Relay. Для этого необходимо добавить несколько скриптов в свой package.json
, чтобы запустить тестовый сервер. Также необходимо добавить @fluidframework/test-client-utils
пакеты и start-server-and-test
в devDependencies
package.json
.
{
"scripts": {
"start": "start-server-and-test start:server 7070 start:client",
"start:client": "{YOUR START CLIENT COMMAND HERE}",
"start:server": "npx tinylicious@latest"
},
"devDependencies": {
"@fluidframework/test-client-utils": "^1.3.6",
"start-server-and-test": "^2.0.0"
}
}
При запуске приложения таким образом LiveShareClient
объект добавляется #{containerId}
в URL-адрес, если он не существует. Затем можно скопировать и вставить URL-адрес в новое окно браузера, чтобы подключиться к тому же контейнеру Fluid.
Примечание.
По умолчанию все клиенты, подключенные через , TestLiveShareHost
будут иметь presenter
роли и organizer
.
Примеры кода
Название примера | Описание | JavaScript | TypeScript |
---|---|---|---|
Dice Roller | Включение во всех подключенных клиентах возможности прокрутки игральной кости и просмотра результата. | View | View |
Игра в покер по гибкой методике | Включите все подключенные клиенты для игры в покер по гибкой методике.. | View | Н/Д |
Трехмерная модель | Включите все подключенные клиенты для совместного просмотра трехмерной модели. | Н/Д | Просмотр |
Timer | Включите все подключенные клиенты для просмотра таймера обратного отсчета. | Н/Д | Просмотр |
Аватары присутствия | Отображение аватаров присутствия для всех подключенных клиентов. | Н/Д | Просмотр |
Следующий этап
См. также
- Приложения для собраний Teams
- Репозиторий GitHub
- Согласие для определенных ресурсов
- Справочные документы по пакету SDK Live Share
- Справочные документы по пакету SDK мультимедиа Live Share
- Вопросы и ответы о Live Share
- Использование Fluid с Teams
- Создание Agile Poker с помощью пакета SDK для Live Share
- Руководство по коду Dice Roller
Platform Docs