Разработка для мобильных платформ часто преподносит сюрпризы, связанные с различиями в версиях операционных систем и архитектурой самой платформы 1С. Одной из распространенных проблем является внезапный отказ стабильно работавшего кода при переходе на новые устройства или обновлении версии Android. В этой статье мы подробно разберем ситуацию, когда мобильное приложение 1С выдает ошибку «Файл не обнаружен» при попытке создания XML-документа, проанализируем причины этого поведения и найдем эффективные способы решения.
Рассмотрим типичную ситуацию. Имеется самописное мобильное приложение, в котором реализован механизм обмена данными через XML. Код для инициализации записи файла выглядит следующим образом:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
Попытка
ЗаписьXML.ОткрытьФайл(ПутьОбмена + ИмяФайла);
Исключение
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка открытия файла для записи: " + ПутьОбмена + ИмяФайла);
КонецПопытки;
При выполнении этого фрагмента на планшете с Android 13 всё проходит успешно. Однако на телефоне с Android 10 приложение выбрасывает исключение с текстом: «К сожалению, возникла ошибка при работе с файлом. Файл не обнаружен '/data/user/0/(Идентификатор приложения)/cache/(имя файла)'». При этом все разрешения на доступ к памяти устройства в настройках телефона предоставлены. Проанализируем, почему стандартные пути, такие как КаталогДокументов() или КаталогВременныхФайлов(), перестают работать в определенных условиях.
Для начала выясним важную особенность мобильной платформы 1С:Предприятие. Несмотря на то что приложение работает на одном физическом устройстве, платформа эмулирует разделение на клиентскую и серверную части.
Проанализируем разницу:
Как показывает практика, именно вызов метода ОткрытьФайл() в контексте &НаСервере часто становится источником проблем на ОС Android 10 и выше. Платформа 1С может некорректно транслировать права доступа или пути к файловой системе из серверного потока в операционную систему. В результате Android блокирует попытку создания файла, считая, что к нему обращается процесс без соответствующих привилегий, и возвращает ошибку «Файл не обнаружен».
Разберем технические изменения в безопасности Android. Начиная с 10-й версии (API 29), компания Google ввела механизм Scoped Storage (изолированное хранилище). Теперь приложения имеют жестко ограниченный доступ к файловой системе:
Когда мы используем метод КаталогВременныхФайлов(), мы получаем путь вида /data/user/0/.../cache/. Если попытка записи по этому адресу происходит в серверном контексте мобильной платформы, система безопасности Android может не распознать этот запрос как легитимный запрос от владельца папки.
Самым простым и эффективным решением, как показала практика, является перенос процедур работы с файлами в клиентский контекст. Рассмотрим, как изменить структуру кода. Вместо того чтобы формировать файл на сервере, мы делаем это &НаКлиенте.
Пример исправленного подхода:
&НаКлиенте
Процедура ВыполнитьЭкспортДанных()
ПутьОбмена = КаталогВременныхФайлов();
ИмяФайла = "export.xml";
ПолныйПуть = ПутьОбмена + ИмяФайла;
ЗаписьXML = Новый ЗаписьXML;
Попытка
// На клиенте доступ к файловой системе наиболее стабилен
ЗаписьXML.ОткрытьФайл(ПолныйПуть);
// Здесь логика записи данных в XML
ЗаписьXML.ЗаписатьОбъявлениеXML();
// ... заполнение данными ...
ЗаписьXML.Закрыть();
Сообщить("Файл успешно создан: " + ПолныйПуть);
Исключение
Сообщить("Ошибка при создании файла: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Важный момент: если данные для XML-файла необходимо собрать из базы данных (что требует серверного контекста), не следует пытаться записывать их в файл прямо на сервере. Лучше собрать данные в структуру или таблицу, передать их на клиент и там сформировать файл.
Если логика формирования XML слишком сложна для клиента, разберем альтернативный метод. Рассмотрим вариант использования Временного хранилища. Этот метод позволяет сформировать содержимое файла на сервере в виде строки или потока, а затем «приземлить» его на файловую систему уже на стороне клиента.
Выполним следующие шаги:
ЗаписьXML.ЗаписьXML.УстановитьСтроку() вместо открытия файла.ЗаписьXML.Закрыть().ДвоичныеДанные и передаем их на клиент.ДвоичныеДанные.Записать().Посмотрим на пример кода:
&НаСервере
Функция СформироватьXMLНаСервере()
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку("UTF-8");
// Логика формирования XML
// ...
СтрокаXML = ЗаписьXML.Закрыть();
// Помещаем данные во временное хранилище или возвращаем как двоичные данные
Возврат Новый ДвоичныеДанные(СтрокаXML); // Внимание: проверьте кодировку при преобразовании
КонецФункции
&НаКлиенте
Процедура СохранитьФайл()
ДанныеФайла = СформироватьXMLНаСервере();
ПутьСохранения = КаталогДокументов() + "data_exchange.xml";
ДанныеФайла.Записать(ПутьСохранения);
КонецПроцедуры
Выясним основные правила, которые помогут избежать ошибок в будущем:
Файл, ЗаписьXML, ЗаписьТекста в контексте &НаКлиенте. Это гарантирует использование прав текущего пользователя и корректное взаимодействие с ОС Android.КаталогВременныхФайлов(), для постоянных данных приложения — КаталогДокументов(). Избегайте «хардкода» путей.ОткрытьФайл() и Записать() в блоки Попытка...Исключение, выводя подробное ОписаниеОшибки(), так как системные сообщения Android могут дать ключ к разгадке (например, указать на отсутствие прав READ_EXTERNAL_STORAGE или WRITE_EXTERNAL_STORAGE).Проанализировав ситуацию, мы видим, что проблема «Файл не обнаружен» в мобильном приложении часто является не отсутствием самого файла, а невозможностью его создания из-за ограничений серверного потока. Следуя принципу разделения подготовки данных (на сервере) и записи в файловую систему (на клиенте), вы обеспечите стабильную работу вашего приложения на любых версиях Android.