Как решить проблему нестабильной работы функции СделатьФотоснимок в мобильном приложении 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Разработка мобильных приложений на платформе 1С:Предприятие часто сталкивается с аппаратными особенностями различных смартфонов. Одной из самых распространенных проблем является нестабильная работа метода СредстваМультимедиа.СделатьФотоснимок. Программисты часто жалуются, что функция срабатывает "через раз", зависает или приводит к аварийному завершению приложения. В этой статье мы подробно разберем причины такого поведения и рассмотрим альтернативные способы получения качественных снимков с заданными параметрами сжатия.

Выясняем причины: почему стандартный метод работает нестабильно

Прежде чем переходить к коду, давайте проанализируем ситуацию. Основная причина "вылетов" мобильного клиента при попытке сделать фото заключается в управлении оперативной памятью в ОС Android. Когда вызывается метод СделатьФотоснимок, 1С обращается к ресурсам камеры. На устройствах с небольшим объемом оперативной памяти или при агрессивной политике энергосбережения система может посчитать фоновое приложение (которым становится 1С в момент открытия интерфейса камеры) "лишним" и закрыть его для освобождения ресурсов. В итоге, когда камера завершает работу, ей некуда возвращать результат.

Вторая причина — различия в реализациях API камеры производителями (Samsung, Xiaomi, Huawei и др.). Штатный метод 1С пытается быть универсальным, но это не всегда удается на специфических прошивках. Поэтому мы рассмотрим несколько путей решения: от настройки параметров до использования низкоуровневых механизмов Android.

Способ 1. Оптимизация параметров штатной функции

Иногда проблему удается решить, не отказываясь от СредстваМультимедиа.СделатьФотоснимок, а лишь правильно ограничив аппетиты системы. Если мы запрашиваем максимальное разрешение, нагрузка на шину данных и память возрастает многократно. Рассмотрим пример правильного вызова с ограничением разрешения:


#Если МобильноеПриложениеКлиент Тогда
    Разрешение = Новый РазрешениеКамерыУстройства;
    // Вместо максимальных значений установим разумный предел для фото 500 Кб
    Разрешение.Высота = 1280; 
    Разрешение.Ширина = 720;
    
    Попытка
        Снимок = СредстваМультимедиа.СделатьФотоснимок(ТипКамерыУстройства.Задняя, Разрешение, 80, Ложь);
        Если Снимок <> Неопределено Тогда
            ДвоичныеДанныеФото = Снимок.ПолучитьДвоичныеДанные();
            // Дальнейшая логика отправки на сервер
        КонецЕсли;
    Исключение
        Сообщить("Ошибка при работе с камерой: " + ОписаниеОшибки());
    КонецПопытки;
#КонецЕсли

Параметр Качество (в примере — 80) напрямую влияет на сжатие Jpeg. Установка значения ниже 100 существенно снижает вес файла, что часто решает проблему нехватки памяти при обработке данных внутри 1С.

Способ 2. Использование Android Intent (IMAGE_CAPTURE)

Если штатный метод продолжает подводить, мы можем воспользоваться механизмом Интентов (Intents). Это прямой вызов системного приложения "Камера", установленного на устройстве по умолчанию. Этот способ считается более надежным, так как операционная система отдает приоритет своей родной камере.

Однако здесь кроется важный технический нюанс. Начиная с Android 7.0, Google запретил передавать пути к файлам через протокол file:// (ошибка FileUriExposedException). Поэтому нам нужно правильно формировать путь. Рассмотрим рабочий код для современных версий платформы:


// Подготавливаем путь к временному файлу
ИмяФайла = "photo_" + Формат(ТекущаяДата(), "ДФ=yyyyMMddHHmmss") + ".jpg";
ПолныйПуть = ОбменССерверомТД.ПолучитьПутьКФайлу(ИмяФайла); // Используем КаталогДокументов()

Запуск = Новый ЗапускПриложенияМобильногоУстройства("android.media.action.IMAGE_CAPTURE");
// Важно: добавляем префикс file:// для корректной интерпретации интентом на многих прошивках
Запуск.ДополнительныеДанные.Добавить("output", "file://" + ПолныйПуть, "Uri");

// Запускаем и ждем возврата в приложение
Запуск.Запустить(Истина);

// После возврата проверяем наличие файла
ФайлНаДиске = Новый Файл(ПолныйПуть);
Если ФайлНаДиске.Существует() Тогда
    ДвоичныеДанные = Новый ДвоичныеДанные(ПолныйПуть);
    // Файл получен!
КонецЕсли;

Важный совет: При использовании интента настройки качества (Jpeg compression) обычно недоступны программно в самом коде 1С, так как это зависит от настроек стороннего приложения камеры. Однако мы можем обработать полученный файл сразу после съемки.

Способ 3. Сжатие и масштабирование через ОбрабатываемаяКартинка

Выясним, как быть, если фото получилось огромным (например, 5-8 Мб), а нам нужно 500 Кб. Начиная с версии 8.3.14, в 1С появился мощный объект ОбрабатываемаяКартинка. Он доступен на мобильной платформе и позволяет манипулировать изображением без отправки на сервер.

Проанализируем процесс уменьшения размера изображения:


// Допустим, у нас есть ДвоичныеДанные снимка
ИсходнаяКартинка = Новый Картинка(ДвоичныеДанные);
Обработка = Новый ОбрабатываемаяКартинка(ИсходнаяКартинка);

// 1. Уменьшаем физический размер (масштабируем)
// Если ширина больше 1280, пропорционально уменьшаем
Если ИсходнаяКартинка.Ширина() > 1280 Тогда
    Коэффициент = 1280 / ИсходнаяКартинка.Ширина();
    НоваяВысота = ИсходнаяКартинка.Высота() * Коэффициент;
    Обработка.УстановитьРазмер(1280, НоваяВысота);
КонецЕсли;

// 2. Устанавливаем формат и качество сжатия
// Метод УстановитьФормат позволяет задать сжатие Jpeg
Обработка.УстановитьФормат(ФорматКартинки.JPEG);

// Получаем готовую сжатую картинку
СжатаяКартинка = Обработка.ПолучитьКартинку();
ДвоичныеДанныеДляОтправки = СжатаяКартинка.ПолучитьДвоичныеДанные();

// Проверяем размер: если все еще велик, можно применить методы снижения глубины цвета
// Обработка.УстановитьГлубинуЦвета(ГлубинаЦвета.Бит8);

Использование ОбрабатываемаяКартинка — это самый современный и правильный путь. Вы можете сделать снимок любым способом (штатным или через интент), а затем программно привести его к нужному весу и разрешению перед отправкой на сервер.

Дополнительные рекомендации по стабильности

Для того чтобы ваше мобильное приложение работало как часы, рекомендуем обратить внимание на следующие моменты:

  1. Очистка временных файлов: Мобильные устройства имеют ограниченный ресурс памяти. После получения ДвоичныхДанных и записи их в информационную базу, обязательно удаляйте временные файлы с диска с помощью команды УдалитьФайлы().
  2. Права доступа: В современных версиях Android разрешения запрашиваются в момент использования. Убедитесь, что у приложения есть права на "Камеру" и "Хранилище". В 1С это проверяется методом СредстваМультимедиа.ПоддерживаетсяФотоснимок().
  3. Фоновый режим: Посоветуйте пользователям в настройках телефона (особенно на устройствах Xiaomi и Huawei) отключить ограничение фоновой активности для мобильного клиента 1С. Это предотвратит закрытие приложения системой во время работы камеры.
  4. Каталоги хранения: Всегда используйте КаталогДокументов() или КаталогВременныхФайлов() для сохранения промежуточных фото. Попытка записать файл в корень карты памяти или системные папки приведет к ошибке доступа.

Подводя итог, можно сказать: хотя метод СделатьФотоснимок и может капризничать на разном железе, связка из Android Intent (для надежного захвата изображения) и объекта ОбрабатываемаяКартинка (для гарантированного сжатия до 500 Кб) дает стопроцентный результат в мобильной разработке на 1С.

← На главную