При разработке мобильных рабочих мест и кроссплатформенных решений на платформе «1С:Предприятие 8» часто возникает задача разделения интерфейса. Для обычного компьютера (тонкого клиента) нам требуется детальная, функциональная и насыщенная реквизитами форма. Для мобильного клиента или мобильного приложения необходима совершенно иная форма — облегченная, адаптированная под небольшие сенсорные экраны и вертикальную ориентацию.
Казалось бы, задача простая: достаточно перехватить открытие формы и подменить её имя. Однако начинающие разработчики часто сталкиваются с техническими нюансами работы клиент-серверной архитектуры платформы. В этой статье мы подробно разберем, почему простой и очевидный код с директивами препроцессора не работает, как правильно определить тип клиента на сервере и какие архитектурные решения считаются наиболее правильными («по феншую»).
Рассмотрим типичную ошибку. Разработчик пытается использовать обработчик модуля менеджера ОбработкаПолученияФормы и пишет следующий код:
#Если МобильноеПриложениеКлиент ИЛИ МобильныйКлиент Тогда
ВыбраннаяФорма = "ФормаДокументаМобильная";
#Иначе
ВыбраннаяФорма = "ФормаДокумента";
#КонецЕсли
При запуске системы данный код игнорирует мобильные устройства, переменная ВыбраннаяФорма остается пустой (или принимает значение по умолчанию), а система выдает ошибку. Выясним причину такого поведения.
Процедура ОбработкаПолученияФормы выполняется строго на сервере. Директивы препроцессора, такие как #Если МобильныйКлиент или #Если ТонкийКлиент, предназначены исключительно для компиляции клиентского кода. Когда компилятор платформы подготавливает серверный модуль менеджера к выполнению, все эти условия принудительно принимают значение Ложь. Для сервера не существует понятия «клиент» в контексте компиляции кода — сервер компилирует один общий код для всех сеансов.
Поскольку все условия препроцессора на сервере обратились в Ложь, переменная ВыбраннаяФорма не инициализируется нужным значением. Проанализируем рабочие и правильные варианты решения этой задачи.
Если ваша конфигурация разработана на базе БСП (или содержит её элементы), вам не нужно изобретать сложные алгоритмы. БСП уже берет на себя задачу определения параметров окружения и кэширования их на сервере.
Для определения мобильного клиента на сервере достаточно вызвать готовую функцию общего назначения. Изменим наш обработчик в модуле менеджера:
Процедура ОбработкаПолученияФормы(ВидФормы, Параметры, ВыбраннаяФорма, ДополнительнаяИнформация, СтандартнаяОбработка)
Если ВидФормы = "ФормаОбъекта" Тогда
// Используем стандартный функционал БСП для определения мобильного клиента
Если ОбщегоНазначения.ЭтоМобильныйКлиент() Тогда
ВыбраннаяФорма = "Документ.НашДокумент.Форма.ФормаДокументаМобильная";
СтандартнаяОбработка = Ложь;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важное примечание: при указании имени формы в параметре ВыбраннаяФорма всегда пишите полный путь к метаданным (например, "Документ.НашДокумент.Форма.ФормаДокументаМобильная"), а не просто её имя в конфигураторе. Это гарантирует стабильную работу платформы при вызове из различных контекстов.
Если вы работаете в абсолютно «чистой» самописной конфигурации, где БСП отсутствует, нам придется определить тип клиента самостоятельно. Сделать это напрямую на сервере через директивы нельзя, но мы можем проанализировать активное соединение текущего сеанса.
Каждое клиентское приложение при подключении к серверу передает свой идентификатор. Мы можем получить список активных сеансов информационной базы, найти среди них наше текущее соединение и прочитать его свойство ИмяПриложения.
Рассмотрим, какие значения свойства ИмяПриложения соответствуют разным клиентам:
1CV8C — Тонкий клиент (ThinClient).WebClient — Веб-клиент.MobileClient — Мобильный клиент.MobileAppClient — Мобильное приложение (автономный клиент).1CV8 — Толстый клиент.Напишем функцию для определения типа клиента и применим её в обработчике получения формы в модуле менеджера:
Функция ПолучитьТипТекущегоКлиента() Экспорт
ТекущийКлиент = "НеизвестныйКлиент";
НомерСоединения = НомерСоединенияИнформационнойБазы();
СеансыИБ = ПолучитьСеансыИнформационнойБазы();
Для Каждого Сеанс Из СеансыИБ Цикл
Если Сеанс.НомерСоединения = НомерСоединения Тогда
ТекущийКлиент = Сеанс.ИмяПриложения;
Прервать;
КонецЕсли;
КонецЦикла;
Возврат ТекущийКлиент;
КонецФункции
Процедура ОбработкаПолученияФормы(ВидФормы, Параметры, ВыбраннаяФорма, ДополнительнаяИнформация, СтандартнаяОбработка)
Если ВидФормы = "ФормаОбъекта" Тогда
ТипКлиента = ПолучитьТипТекущегоКлиента();
Если ТипКлиента = "MobileClient" Или ТипКлиента = "MobileAppClient" Тогда
ВыбраннаяФорма = "Документ.НашДокумент.Форма.ФормаДокументаМобильная";
СтандартнаяОбработка = Ложь;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Внимание: метод ПолучитьСеансыИнформационнойБазы() требует наличия административных прав у пользователя в некоторых старых версиях платформы или может выполняться с задержкой в высоконагруженных базах данных с тысячами активных сеансов. Если производительность критична, рекомендуется использовать кэширование типа клиента в параметрах сеанса при начале работы системы.
Чтобы избежать постоянного сканирования сеансов информационной базы при каждом открытии формы, мы можем зафиксировать тип клиента один раз — при старте системы.
Разберем этот метод по шагам:
ТекущийКлиент (тип — строка или соответствующий перечисление).ПередНачаломРаботыСистемы определим тип клиента с помощью клиентских директив препроцессора и передадим это значение на сервер для записи в параметр сеанса.Пример кода в модуле управляемого приложения:
Процедура ПередНачаломРаботыСистемы(Отказ)
// Определяем тип клиента на клиенте с помощью препроцессора
ИмяКлиента = "ТонкийКлиент";
#Если МобильныйКлиент Тогда
ИмяКлиента = "МобильныйКлиент";
#ИначеЕсли МобильноеПриложениеКлиент Тогда
ИмяКлиента = "МобильноеПриложение";
#ИначеЕсли ВебКлиент Тогда
ИмяКлиента = "ВебКлиент";
#КонецЕсли
// Записываем значение в параметры сеанса через серверный вызов
УстановитьПараметрСеансаКлиента(ИмяКлиента);
КонецПроцедуры
Для записи параметра сеанса используем общий модуль с установленным флагом «Вызов сервера»:
Процедура УстановитьПараметрСеансаКлиента(ЗначениеКлиента) Экспорт
ПараметрыСеанса.ТекущийКлиент = ЗначениеКлиента;
КонецПроцедуры
Теперь в модуле менеджера нашего документа мы можем моментально и без потери производительности получать тип клиента напрямую из параметров сеанса:
Процедура ОбработкаПолученияФормы(ВидФормы, Параметры, ВыбраннаяФорма, ДополнительнаяИнформация, СтандартнаяОбработка)
Если ВидФормы = "ФормаОбъекта" Тогда
Если ПараметрыСеанса.ТекущийКлиент = "МобильныйКлиент"
Или ПараметрыСеанса.ТекущийКлиент = "МобильноеПриложение" Тогда
ВыбраннаяФорма = "Документ.НашДокумент.Форма.ФормаДокументаМобильная";
СтандартнаяОбработка = Ложь;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Платформа 1С предоставляет встроенные свойства разделения интерфейсов, о которых разработчики часто забывают. У каждой управляемой формы в конфигураторе есть палитра свойств. Рассмотрим ключевые свойства формы:
Если для основной формы документа (ФормаДокумента) снять флаг «Мобильный клиент», а для мобильной формы (ФормаДокументаМобильная) оставить этот флаг активным и сделать её основной для мобильного использования, платформа 1С в большинстве стандартных сценариев автоматически подберет нужную форму без написания какого-либо программного кода в модуле менеджера.
Используйте этот вариант, если формы кардинально отличаются и вам не нужно прописывать сложную дополнительную логику инициализации параметров при открытии.