Разработка мобильных приложений на платформе 1С:Предприятие часто сопряжена с необходимостью глубокого взаимодействия с аппаратными функциями смартфона, такими как камера. Однако при переходе на новые версии операционной системы Android (начиная с 7.0 Nougat и выше) разработчики часто сталкиваются с тем, что ранее стабильно работающий код внезапно вызывает аварийное завершение работы приложения. Одной из самых распространенных ошибок является android.os.FileUriExposedException.
В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем технические ограничения безопасности современных Android-устройств и найдем оптимальное решение, которое позволит вашему мобильному приложению корректно делать снимки на любой версии ОС.
Рассмотрим классическую ситуацию. Разработчик использует объект ЗапускПриложенияМобильногоУстройства, чтобы вызвать штатное системное приложение камеры через действие android.media.action.IMAGE_CAPTURE. Это делается для того, чтобы получить больше контроля над процессом съемки, например, использовать автофокус или вспышку, которые в старых версиях мобильной платформы 1С были недоступны в штатных методах.
Типичный код, который вызывает ошибку на Android 7.0+, выглядит следующим образом:
КаталогКартинок = КаталогДокументов();
ФайлКартинки = КаталогКартинок + "temp.jpg";
НовВз = Новый ЗапускПриложенияМобильногоУстройства("android.media.action.IMAGE_CAPTURE");
НовВз.ДополнительныеДанные.Добавить("output", ФайлКартинки, "Uri");
НовВз.Запустить(Истина);
На устройствах с Android 5.0 или 6.0 этот код работает безупречно. Однако на Android 7.0 система выдает ошибку: android.os.FileUriExposedException: file:///sdcard/MobileData/temp.jpg exposed beyond app through clipdata.item.geturi(). Давайте проанализируем причину этого поведения.
Начиная с API level 24 (Android 7.0), Google ввела политику безопасности StrictMode, которая запрещает передачу именных ссылок на файлы через протокол file:// между различными приложениями. Когда мы передаем в камеру путь к файлу в виде Uri, мы фактически передаем прямой адрес в файловой системе. Если приложение-получатель (в данном случае камера) не имеет явных прав доступа к папке вашего приложения, оно не сможет записать туда файл, а система безопасности Android превентивно блокирует такую передачу, вызывая исключение.
Для корректной передачи файлов в современных ОС Android требуется использовать протокол content:// и специальный компонент FileProvider. Однако в рамках разработки на встроенном языке 1С прямая настройка FileProvider в манифесте приложения и формирование защищенных ссылок крайне затруднены, так как это требует низкоуровневого взаимодействия с Java API.
Многие разработчики использовали внешние интенты (вызовы сторонних приложений) только потому, что штатный метод 1С СредстваМультимедиа.СделатьФотоснимок долгое время имел ограниченный функционал (отсутствие управления вспышкой, разрешением и т.д.). Однако прогресс не стоит на месте.
Проанализируем современные возможности платформы 1С (начиная с версии 8.3.13 и выше). В этих версиях разработчики 1С значительно расширили возможности объекта СредстваМультимедиа. Теперь использование внешних программ камеры становится избыточным и даже вредным из-за проблем с безопасностью Android.
Разберем, как правильно реализовать фотосъемку, используя современные возможности платформы, которые гарантированно работают на Android 7, 8, 10 и выше.
Шаг 1. Проверка разрешений. Перед вызовом камеры убедитесь, что у приложения есть права на использование камеры и запись в хранилище. В новых версиях платформы это происходит автоматически при вызове метода, но в настройках сборщика мобильного приложения эти разрешения должны быть отмечены.
Шаг 2. Использование параметров съемки. Чтобы решить проблему со вспышкой, на которую жаловались многие разработчики, используем объект ПараметрыСнятияФотоснимка. Посмотрим на пример кода:
// Проверим, поддерживается ли фотосъемка на устройстве
Если СредстваМультимедиа.ПоддерживаетсяФотоснимок() Тогда
// Создаем объект параметров
ПараметрыФото = Новый ПараметрыСнятияФотоснимка;
// Устанавливаем использование вспышки
// Доступные значения: Авто, Включена, Выключена
ПараметрыФото.ИспользованиеВспышки = ИспользованиеВспышкиМобильногоУстройства.Авто;
// Устанавливаем разрешение (необязательно)
// Можно выбрать высокое для качественных фото или низкое для экономии трафика
ПараметрыФото.Разрешение = РазрешениеВидеоФотосъемки.Высокое;
// Вызываем метод съемки
ДанныеСнимка = СредстваМультимедиа.СделатьФотоснимок(ПараметрыФото);
Если ДанныеСнимка <> Неопределено Тогда
// Получаем двоичные данные картинки
ДвоичныеДанныеКартинки = ДанныеСнимка.ПолучитьДвоичныеДанные();
// Дальнейшая логика сохранения в базу или файл
КонецЕсли;
КонецЕсли;
FileProvider и формирование правильных content:// ссылок внутри нативного кода. Вам не нужно беспокоиться об ошибке FileUriExposedException.ДанныеМультимедиа сразу в коде.Некоторые разработчики отмечают, что штатный метод СделатьФотоснимок работает медленнее, чем прямое обращение к IMAGE_CAPTURE. Выясним причину: часто задержка возникает не в момент срабатывания затвора, а в момент передачи огромного массива данных из нативного слоя Android во внутреннюю память 1С.
Чтобы ускорить работу, воспользуйтесь следующими советами:
РазрешениеВидеоФотосъемки.Среднее.СделатьФотоснимок параметров сжатия JPEG нет, вы можете обработать полученные ДвоичныеДанные через объект Картинка и метод Преобразовать, чтобы уменьшить размер перед отправкой на сервер.Таким образом, решением проблемы FileUriExposedException является отказ от низкоуровневых манипуляций с интентами в пользу штатных механизмов платформы 1С версии 8.3.13 и выше. Это не только исправляет ошибку, но и делает код более надежным и переносимым между различными моделями смартфонов.