При разработке мобильных приложений или интеграции мобильного клиента с существующими конфигурациями 1С разработчики часто сталкиваются с неожиданными ошибками компиляции. Одна из наиболее распространенных проблем возникает при использовании общих модулей с установленными флагами вызова как на клиенте, так и на сервере. Яркий пример — ошибка «Переменная не определена (РежимВосстановленияПутейФайловZIP)», возникающая при закрытии или запуске мобильного приложения.
В этой статье мы подробно разберем причины возникновения этой ошибки, проанализируем механизмы работы компилятора 1С и рассмотрим несколько надежных способов ее устранения.
Для начала проанализируем, что представляет собой РежимВосстановленияПутейФайловZIP. Это системное перечисление платформы «1С:Предприятие», которое управляет поведением объекта ЧтениеZipФайла при извлечении файлов из архива с помощью метода ИзвлечьВсе(). Оно имеет два стандартных значения: Восстанавливать (для воссоздания исходной структуры папок) и НеВосстанавливать.
Основная сложность заключается в ограничении доступности этого перечисления на разных типах клиентов. Давайте обратимся к синтакс-помощнику. Объект ЧтениеZipФайла и связанное с ним перечисление РежимВосстановленияПутейФайловZIP имеют ограниченную доступность. Они гарантированно доступны на сервере, в толстом клиенте и при внешнем соединении.
Исторически (вплоть до версии платформы 8.3.21) работа с ZIP-архивами вообще не поддерживалась в веб-клиенте, тонком клиенте, а также на мобильной платформе и в мобильном клиенте. Когда мы переводим конфигурацию на более старый режим совместимости (например, 8.3.7), платформа принудительно эмулирует ограничения старых релизов, даже если физически запуск происходит на новой версии платформы.
Давайте разберем, как ведет себя компилятор 1С при проверке общего модуля (например, ФайловыеФункцииСлужебныйКлиентСервер):
РежимВосстановленияПутейФайловZIP), компилятор выдает ошибку «Переменная не определена», прерывая работу приложения.Даже если ошибочный участок кода обернут в директиву #Если Не ВебКлиент Тогда, для мобильного приложения этого оказывается недостаточно. Мобильный клиент — это самостоятельный тип клиента, отличный от веб-клиента, и директива его пропускает, вызывая крах компиляции.
Самый простой и быстрый способ решить проблему без кардинального изменения архитектуры модуля — это расширить препроцессорную директиву исключения. Нам необходимо явно перечислить все среды, в которых системные функции работы с ZIP-архивами недоступны.
Давайте посмотрим на исходный проблемный код процедуры:
Функция ИзвлечьТекстOpenDocument(ПутьКФайлу, Отказ)
ИзвлеченныйТекст = "";
#Если Не ВебКлиент Тогда
ВременнаяПапкаДляРазархивирования = ПолучитьИмяВременногоФайла("");
ВременныйZIPФайл = ПолучитьИмяВременногоФайла("zip");
КопироватьФайл(ПутьКФайлу, ВременныйZIPФайл);
Файл = Новый Файл(ВременныйZIPФайл);
Файл.УстановитьТолькоЧтение(Ложь);
Попытка
Архив = Новый ЧтениеZipФайла();
Архив.Открыть(ВременныйZIPФайл);
Архив.ИзвлечьВсе(ВременнаяПапкаДляРазархивирования, РежимВосстановленияПутейФайловZIP.Восстанавливать);
Архив.Закрыть();
ЧтениеXML = Новый ЧтениеXML();
ЧтениеXML.ОткрытьФайл(ВременнаяПапкаДляРазархивирования + "/content.xml");
ИзвлеченныйТекст = ИзвлечьТекстИзContentXML(ЧтениеXML);
ЧтениеXML.Закрыть();
Исключение
Отказ = Истина;
ИзвлеченныйТекст = "";
КонецПопытки;
УдалитьФайлы(ВременнаяПапкаДляРазархивирования);
УдалитьФайлы(ВременныйZIPФайл);
#КонецЕсли
Возврат ИзвлеченныйТекст;
КонецФункции
Чтобы компилятор мобильного приложения (и тонкого клиента) успешно пропустил этот участок кода, мы заменим директиву #Если Не ВебКлиент Тогда на более строгую фильтрацию:
#Если Не ТонкийКлиент И Не ВебКлиент И Не МобильныйКлиент И Не МобильноеПриложениеКлиент Тогда
// Здесь располагается код работы с ZIP-архивом
#КонецЕсли
Благодаря этому изменению компилятор мобильного устройства просто проигнорирует тело условия при сборке клиентского кода, и ошибка «Переменная не определена» исчезнет.
Несмотря на работоспособность первого способа, стандарты разработки фирмы «1С» и библиотеки стандартных подсистем (БСП) рекомендуют использовать другой подход. Любые ресурсоемкие операции с файловой системой (такие как чтение и распаковка ZIP-архивов) крайне нежелательно выполнять на стороне каких-либо клиентов — это замедляет работу интерфейса и расходует ресурсы клиентского устройства.
Правильным архитектурным решением будет явное ограничение компиляции кода только для серверного контекста и безопасных толстых клиентов. Давайте проанализируем такое условие:
#Если Сервер Или ВнешнееСоединение Или ТолстыйКлиентОбычноеПриложение Или ТолстыйКлиентУправляемоеПриложение Тогда
// Данный код скомпилируется только там, где гарантированно есть объект ЧтениеZipФайла
Архив = Новый ЧтениеZipФайла();
Архив.Открыть(ВременныйZIPФайл);
Архив.ИзвлечьВсе(ВременнаяПапкаДляРазархивирования, РежимВосстановленияПутейФайловZIP.Восстанавливать);
Архив.Закрыть();
#КонецЕсли
Использование директивы #Если Сервер... гарантирует, что ни один из существующих или будущих видов легких клиентов (включая любые мобильные платформы, веб-клиенты или новые типы автономных клиентов) не споткнется об этот фрагмент кода при обновлении платформы.
Давайте сделаем небольшое отступление и рассмотрим, как развивается платформа «1С:Предприятие». Начиная с версии 8.3.21, разработчики фирмы «1С» добавили полноценную поддержку работы с ZIP-архивами непосредственно в мобильную платформу и мобильный клиент.
Если ваше приложение работает на актуальных версиях платформы без режима совместимости (или с режимом совместимости 8.3.21 и выше), объекты ЧтениеZipФайла и перечисление РежимВосстановленияПутейФайловZIP станут доступны на мобильных устройствах «из коробки».
Однако, если в свойствах вашей конфигурации установлен режим совместимости «8.3.7» (или любой другой ниже 8.3.21), платформа принудительно отключает новые возможности для обеспечения обратной совместимости. В этом случае использование препроцессорных директив, описанных в Способе 1 и Способе 2, остается единственным и обязательным решением проблемы.