О чем?
В этой статье я расскажу о том, что предлагает нам компания Microsoft в своем Lync SDK для создания «красивых» интерфейсов и новых возможностей для Lync-клиента. Так же подробно остановлюсь на взаимодействии с Lync клиентом в UI Suppression mode, с которым нам очень плотно пришлось иметь дело в процессе разработки собственного корпоративного мессенджера на базе Skype for Business. И, самое главное, постараюсь подробно описать, с какими ограничениями нам пришлось столкнуться.
С чего всё началось?
Весной 2014-го года в нашей компании родилась идея создать корпоративный мессенджер на основе Lync (теперь уже Skype for Business). Вернее, сначала речь о мессенджере не шла, мы просто дорабатывали Lync под себя для более эффективной работы. По сути, мы использовали Lync-клиент в «штатном режиме», а наше приложение было просто дополнением для него, которое управляло контактами. Оно позволяло удобно разместить свои избранные контакты по всей ширине экрана, что было удобно для работы на десктопах, предполагало быстрый доступ к контактам и упорядочивало их по группам. Приложение назвали EasyLy (от «Easy Lync») и распространили среди «своих».
Рисунок 1. Первая версия программы
Постепенно в приложение добавлялись новые функции. Например, переписываться можно было как из Lync, так и из EasyLy, причем в последнем сохранялась история переписки. И в один эпохальный день было принято решение отказаться от интерфейса Lync и реализовать весь его функционал самим, чтобы след Lync остался только в диспетчере задач. То есть мы решили сделать свой собственный, более удобный мессенджер для десктопов на базе Lync. И вроде бы всё начиналось хорошо.
Что мы хотели получить в итоге?
В начале одно из основных неудобств Lync для нас состояло в отсутствии более или менее адекватного механизма сохранения и просмотра истории бесед. Lync, конечно, сохраняет (по истечении определённого времени) свою историю в Outlook, но этим крайне неудобно пользоваться. Помимо этого, история может вообще не сохраниться, если, например, закрыть окно с беседой до того, как произойдёт сохранение.
Что касается usability, мы проповедовали концепцию «One click» для экономии времени пользователя и повышения эффективности его работы и пытались создать приложение максимально простое, понятное и удобное для офисного работника. Целевая группа, которую мы выделили для себя, – это не модные «мобильные сотрудники», бегающие со смартфоном по «полям», а настоящие офисные трудяги, работающие по 8 часов за большим монитором, где всё должно быть эргономично.
Кроме появившейся ранее вкладки «Избранное», появились идеи создать вкладки «Группы», «Диалоги», а также журнал звонков с комментариями, окно проведения онлайн-собраний, возможность отправить сообщение офлайн-абоненту, интеграция с календарями, OneDrive и много других интересных функций. Мы планировали, не отбрасывая имеющийся функционал Lync (а затем и Skype for Business), создать дополнительную ценность для пользователя за счет UI под десктопы, быстрого доступа к имеющимся функциям и создания нового корпоративного функционала.
Рисунок 2. Так выглядит EasyLy сейчас
Разработка
Первое, что было сделано – вкладка “Favorites”, где пользователь мог расположить все свои контакты, да еще и отсортировать их по группам.
Мы приступили к работе и реализовали данную идею без особых проблем с помощью Lync SDK 2013. Все контакты мы сделали в виде карточек, на которых можно посмотреть список собраний и встреч данного пользователя, а также позвонить ему (аудио- и видеозвонки) или написать сообщение. При клике на эти кнопки вызывалось стандартное окно беседы Lync.
Рисунок 3. Иконка контакта при наведении
Это было достаточно просто. Воодушевленные успехом мы начали двигаться дальше и полностью отказались от Lync UI (перевели Lync-клиент в UI Suppression mode). Это дало нам возможность отказаться от стандартных окон бесед, звонков (да и вообще всех окон) и реализовать весь базовый функционал приложения самим.
Не буду рассказывать про авторизацию пользователя, описание можно найти здесь (https://msdn.microsoft.com/en-us/library/office/dn391637.aspx ). Расскажу про нашу вторую и самую главную вкладку «Dialogs», которую мы реализовывали почти год.
Рисунок 4. Вкладка диалогов с включенным режимом мультичата
Начали мы, как полагается, с текстовых бесед. Все шло хорошо, но не очень быстро, потому что, помимо простой отправки и приёма сообщений, нужно было реализовать typing, смайлы, поддержку rtf-форматирования и т.д. Реализацию Lync IM Conversation можно взять отсюда (https://msdn.microsoft.com/en-us/library/office/jj937298.aspx).
Сохранение сообщений и записей о звонках мы реализовали на базе SQLite, которой пользователь может гибко управлять. Также мы внедрили поддержку одновременно нескольких открытых чатов (до 3-х) в одном окне, для еще более скоростного общения с сотрудниками.
Потом мы добавили поддержку аудио-, видеозвонков, шаринга экрана и приложений. Добавление в беседу поддержки Application Sharing (https://code.msdn.microsoft.com/office/Lync-Client-2013-SDK-CU2-02f9292e ) пришлось реализовывать достаточно долго. В обычном режиме Lync показ экрана происходит в самой беседе, а в UI Suppression mode нужно все возможности шаринга реализовывать самому с помощью «линковского» контрола ApplicationSharingView, служащего для отображения расшариваемого ресурса, которому для работы нужен handle родительского окна.
Вот краткий список того, что мы сделали для поддержки шаринга:
• Создали окно для просмотра шаринга, реализовали перерисовывание картинки при изменении размеров родительского окна.
• Сделали вывод списка ресурсов (экран, приложения), которые можно шарить.
• Сделали обводку рамками расшариваемых ресурсов.
• Реализовали дополнительные возможности: например, передачу управления участнику конференции (чтобы он мог водить мышкой и кликать по экрану «шарящего» пользователя).
Шаринг в Lync (в UI Suppression mode) – капризная вещь: любит часто отваливаться по неизвестным причинам, а при переходе на Skype for Business 2016 начал делать это почти постоянно. При просмотре шаринга часто появляется черный экран, и с этим ничего не сделать, так как воспроизведением занимается контрол ApplicationSharingView, про который написано выше. Также на удачный запуск шаринга сильно влияет скорость соединения.
Далее мы перешли к созданию последней вкладки – «Groups», которая бы грузила списки групп из Lync и предоставляла пользователю возможность их полностью редактировать и сортировать в нужном порядке. Данная вкладка должна была перерасти в корпоративную вкладку, в которой бы размещались уже предварительно созданные в Active Directory группы для сотрудников (в Lync они именуются Distribution Groups): например, «Заказать пропуск», «Написать заявление» и т.д. Участниками данных групп являются сотрудники, занимающиеся определёнными вопросами в компании. При нажатии на данную группу открывается чат или аудио звонок с первым участником группы со статусом «онлайн». Редактированием этих групп должен заниматься администратор Lync-сервера.
Конечно, в процессе реализации всех задуманных планов у нас возникали проблемы, которые мы периодически решали. Но была особая группа проблем, связанная с некорректной работой библиотеки Lync SDK в Lync Suppression mode. Мы отправляли их описание в Microsoft и думали, что сможем получить поддержку и найти способ решения.
Проблемы
Как неожиданно выяснилось, в UI Suppression mode пропадает интеграция с Outlook:
• пропадают статусы контактов;
• отсутствует возможность создать беседу из карточки контакта;
• «отвалилась» кнопка «Создать собрание Skype».
Полностью работающие карточки контактов в Outlook нам удалось вернуть, опираясь на вот эту статью (https://msdn.microsoft.com/ru-ru/library/office/jj900715.aspx?f=255&MSPPError=-2147217396#off15_IMIntegration_HowConnect).
Также заработали статусы контактов. Теперь Outlook их получает не от Lync, а от нашего приложения, но обновляет он их каким-то магическим образом, и они постоянно «отваливаются» и перестают синхронизироваться. То есть реально человек уже появился онлайн и «зелёный», а в Outlook – всё ещё в жёлтом статусе «Отошёл». Мы писали в поддержку Microsoft, на что они нам прислали ссылку на эту же статью. Писали также в Yammer Microsoft, на форумах MSDN, Reddit и других площадках… К сожалению, эта проблема так и не решена.
Проблема отвалившейся в Outlook кнопки «Создать собрание Skype» заключается в затирании в режиме UI Suppression mode ключей реестра по пути HCU/Software/Microsoft/Office/15.0/Lync/ConfAddin/мой sip/. Там представлены три ключа: Capabilities, InbandInfo, PublicMeeting. Когда Lync запущен в штатном режиме, при нажатии на кнопку «Создать собрание Skype» Outlook запрашивает у Lync информацию о конференциях, и уже Lync создаёт ключи реестра. В UI Suppresseion mode Lync этого делать не хочет. Средствами Lync SDK 2013 получить нужную информацию от Lync-сервера нельзя. Был найден выход: использовать другую SDK (https://msdn.microsoft.com/en-us/library/office/dn465943.aspx ) для работы непосредственно с сервером. Через UCMA мы смогли получить от сервера информацию о конференциях авторизированного пользователя. Наполнили ключи реестра – и вуаля: в Outlook вернулась возможность создавать собрания. Но в этом способе есть несколько ограничений:
• библиотека UCMA работает только на 64-разрядных ОС, на 32-битных – решения нет;
• компьютер пользователя и сервер должны находиться в одном домене, в противном случае нужно создавать сертификаты на сервере для доверенных приложений. Как это делать, описано тут, но нам данное решение не подходит, так как мы должны реализовывать функционал только на стороне клиента.
Нашлись баги и в самом Lync SDK. Самый критичный: в видеобеседе p2p при добавлении 3-го участника падает сам Lync-клиент, стабильно. Майкрософт сам этот баг подтверждает, но сроков устранения не называет. Были попытки убивать беседу p2p и создавать сразу видеоконференцию на троих, но если 3-го участника добавляет клиент SFB, мы не можем этому помешать. Остановка и возобновление видеоканала тоже ни к чему не привели.
Также проявилась проблема невозможности расшарить экран некоторым пользователям (тем, у кого установлена другая версия Lync-клиента). Проявляется данная проблема следующим образом.
Первый клиент работает в нашем приложении (версия Lync – 2013), второй – в SFB 2016, и у него при открытии беседы с первым кнопка расшаривания экрана недоступна. Если первый клиент заходит в обычный Lync 2013 (не Suppression mode), то у второго кнопка шаринга становится активной. Если у второго установлен также Lync 2013 или наше приложение, шаринг доступен с обеих сторон.
В Lync SDK отсутствует callback о доставке сообщения пользователю. Есть только callback, что сообщение ушло. Но иногда может сложиться ситуация, что мы отправляем сообщение человеку в онлайн, оно уходит без exception, но к моменту прихода собеседник уже офлайн. Следовательно, отправляющий думает, что сообщение пришло, а это не так.
Часто возникает “ItemNotFoundException” при получении фото контактов, следовательно, приходится отображать наше стандартное изображение контакта. Эмпирическим путем мы нашли сколько раз (примерно 3) надо вызвать код получения фото, чтобы Lync его всё-таки вернул. Однако у некоторых контактов этот способ всё равно не срабатывает. Дополнительно мы ввели кэширование фото, чтобы при старте не сыпалась куча эксепшенов, если у пользователя добавлено много контактов.
Есть проблема и с группами пользователя, в частности с «Favorites group». Проблема заключается в том, что у некоторых пользователей при вызове CanInvoke(DeleteGroup) Lync возвращает true, хотя эта стандартная группа Lync, и её нельзя удалить. Тип у этой группы такой же, как и у группы, созданной пользователем (CustomGroup), поэтому скрывание пункта «Удалить группу» из меню приходится делать еще и по дополнительной проверке на имя группы, что является жёстким костылём.
Обнаружились ограничения Lync SDK 2013
• Недоступна одна из важных фич: возможность настройки переадресации вызовов, когда пользователь находится в офлайн. Мы реализовали переадресацию по истечении определённого времени, но только если пользователь не в офлайн.
• При групповом видеозвонке (3 и более участников) поток, который транслирует видео участников, остаётся один (аналог мобильных конференций), то есть Lync сам меняет видеопотоки от разных участников в зависимости от того, кто сейчас говорит в микрофон.
• Передача файлов недоступна в UI Suppression mode. Мы решили эту проблему 2 способами:
-добавили передачу файлов через Outlook в виде аттача к письму;
-внедрили сервис OneDrive для загрузки файлов в облако и автоматической отправки сообщения с URL файла.
• Нельзя использовать контекстные данные беседы (как это делать, описано здесь https://msdn.microsoft.com/en-us/library/office/jj933248.aspx?f=255&MSPPError=-2147217396 ), когда беседа конвертировалась в конференцию и стала существовать на сервере, а не локально. Мы хотели использовать эту возможность для синхронизации различной информации между клиентами.
• Отключена возможность записи в поле «Subject» в конференции (причём и в обычном Lync), зачем-то в Lync 2013 они закрыли эту возможность. Человек на MSDN жаловался, что у него в Lync 2010 около 30 сохраненных конференций, каждая со своим заголовком. С переходом на Lync 2013 у него остались только списки участников в каждой конференции. Теперь отличить одну беседу от другой практически невозможно.
• Еще одна особенность Lync SDK 2013 – поддержка клиентов, начиная с Lync 2013 и новее. Lync 2010 не поддерживается. Однако Lync SDK 2010 работает и с Lync 2010, и с Lync 2013, и выше. Какой логикой руководствуется Microsoft, неизвестно.
Заключение
В процессе разработки мы поняли, что полностью реализовать полноценный аналог Lync, основываясь на Lync SDK + UCMA, не получится. Даже если не брать в расчёт ограничения данных технологий, обидно, что мы не смогли получить поддержку от Microsoft по исправлению ошибок Lync SDK.
На сегодня мы вынуждены отказаться от UI Suppression mode, т.к. в нём невозможно реализовать весь нужный функционал, и ищем варианты обхода проявившихся проблем.
Надеюсь, данная статья поможет начинающим разработчикам приложений на основе Lync/Skype for Business. И, возможно, кто-то из дочитавших до этого места захочет поделиться своими идеями. Пишите!
Автор: EasyLy