Почему вылетает мобильное приложение 1С при сканировании штрихкода и как это исправить?

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

При разработке мобильных приложений на платформе 1С часто возникает задача подключить сканер штрихкодов. Использование внешней компоненты "1С:Сканер штрихкода" (Native) без полной "Библиотеки подключаемого оборудования" (БПО) кажется логичным упрощением. Однако такой подход часто приводит к неожиданной проблеме: при попытке сканирования мобильное приложение аварийно завершает работу ("вылетает"), а событие со штрихкодом так и не поступает в обработчик ОбработкаВнешнегоСобытия.

В этой статье мы подробно разберем, почему возникает эта критическая ошибка и как ее правильно исправить, обеспечив стабильную работу сканера.

Ключевая причина проблемы: сборка мусора и время жизни объекта

Основная причина вылета приложения кроется в механизме управления памятью платформы 1С, а именно — в работе сборщика мусора. Давайте проанализируем типичный ошибочный код подключения компоненты:


// Пример ошибочного кода, который приводит к вылету
Процедура ПодключитьСканерПриОткрытииФормы()
    
    Если ПодключитьВнешнююКомпоненту("ОбщийМакет.Драйвер1СУстройстваВводаNative", "AddIn", ТипВнешнейКомпоненты.Native) Тогда
        // Переменная "Компонента" является ЛОКАЛЬНОЙ
        Компонента = Новый ("AddIn.AddIn.InputDevice"); 
        
        // Настройка параметров...
        Компонента.УстановитьПараметр("BluetoothDevice", "BROADCAST");
        // ... другие параметры
        
        Компонента.Подключить("Штрихкод");
    Иначе
        Сообщить("Компонента для сканера штрихкодов не подключена");
    КонецЕсли;

КонецПроцедуры // <-- В этот момент переменная "Компонента" уничтожается!

Разберем по шагам, что происходит:

  1. Вы создаете объект внешней компоненты и сохраняете его в локальную переменную Компонента внутри некоторой процедуры (например, при открытии формы).
  2. Компонента инициализируется и успешно подписывается на системные события Android, ожидая данные от сканера.
  3. Процедура, в которой была создана компонента, завершает свою работу.
  4. Сборщик мусора 1С видит, что на объект компоненты больше нет ссылок (так как локальная переменная вышла из области видимости), и уничтожает его, освобождая память.
  5. Вы сканируете штрихкод. Система Android, как и договаривались, пытается передать данные в вашу компоненту.
  6. Происходит сбой. Система обращается по адресу в памяти, где раньше был объект компоненты, но теперь там ничего нет. Это приводит к критической ошибке Segmentation Fault, и операционная система аварийно закрывает ваше приложение.

Именно поэтому приложение вылетает без каких-либо внятных сообщений об ошибке со стороны 1С. Система просто не успевает ничего обработать.

Правильное решение: храним экземпляр компоненты в глобальной переменной

Чтобы избежать уничтожения объекта, его нужно хранить в переменной, которая будет существовать на протяжении всего сеанса работы мобильного приложения. Идеальное место для этого — модуль приложения.

Рассмотрим пошаговую реализацию:

Шаг 1. Объявление глобальной переменной

В модуле вашего мобильного приложения объявите экспортную переменную, в которой будет храниться объект компоненты.


// Модуль приложения
Перем глКомпонентаСканера Экспорт;

Шаг 2. Инициализация компоненты при старте системы

Создайте процедуру для подключения и настройки сканера и вызовите ее в обработчике события ПриНачалеРаботыСистемы. Важно присвоить созданный объект именно вашей глобальной переменной.


// Модуль приложения

Процедура ПриНачалеРаботыСистемы()
    ПодключитьСканерШтрихкода();
КонецПроцедуры

Процедура ПодключитьСканерШтрихкода()
    
    Если НЕ ПодключитьВнешнююКомпоненту("ОбщийМакет.Драйвер1ССканерШтрихкода", "InputDevice", ТипВнешнейКомпоненты.Native) Тогда
        Сообщить("Не удалось подключить внешнюю компоненту сканера.");
        Возврат;
    КонецЕсли;
    
    Попытка
        // Создаем объект и сохраняем его в ГЛОБАЛЬНУЮ переменную
        глКомпонентаСканера = Новый("AddIn.InputDevice.InputDevice");
        
        // Далее идет настройка параметров в зависимости от типа вашего сканера
        // Пример для встроенного сканера ТСД (Broadcast)
        глКомпонентаСканера.УстановитьПараметр("BluetoothDevice", "BROADCAST");
        глКомпонентаСканера.УстановитьПараметр("Action", "nlscan.action.SCANNER_RESULT"); // Зависит от модели ТСД
        глКомпонентаСканера.УстановитьПараметр("Extra", "SCAN_BARCODE1"); // Зависит от модели ТСД
        глКомпонентаСканера.УстановитьПараметр("EventName", "Штрихкод"); // Имя события для перехвата
        
        // Включаем логирование для отладки (очень полезно!)
        глКомпонентаСканера.УстановитьПараметр("LogType", 0); // 0 - логировать в файл
        глКомпонентаСканера.УстановитьПараметр("LogFilePath", "/storage/emulated/0/Download/scan_log.txt");
        
        // Подключаем устройство
        глКомпонентаСканера.Подключить("СканерШК");
        
    Исключение
        Сообщить("Ошибка при создании или подключении объекта компоненты: " + ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры

Шаг 3. Обработка внешнего события

Теперь, когда объект компоненты живет постоянно, он сможет корректно передавать данные в обработчик ОбработкаВнешнегоСобытия в том же модуле приложения.


// Модуль приложения

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

Функция ПолучитьТекущуюФорму()
    Если КлиентскоеПриложение.ПолучитьСписокОкон().Количество() > 0 Тогда
        Возврат КлиентскоеПриложение.ПолучитьСписокОкон()[0].ПолучитьСодержимое()[0];
    КонецЕсли;
    Возврат Неопределено;
КонецФункции

Настройка параметров для разных типов сканеров

Компонента универсальна, и ее поведение зависит от установленных параметров.

Встроенные сканеры ТСД (режим Broadcast)

Такие сканеры отправляют данные через широковещательные сообщения Android. Для их настройки ключевыми являются параметры Action и Extra. Эти значения уникальны для каждого производителя и модели ТСД, их нужно искать в документации к устройству.

Примеры значений для популярных моделей:

Внешние Bluetooth-сканеры (режим эмуляции клавиатуры HID)

Для обычных Bluetooth-сканеров, которые подключаются к устройству как внешняя клавиатура, используется другой режим.

В этом режиме компонента перехватывает ввод именно с физической клавиатуры, позволяя отличить его от ввода с экранной. Также может потребоваться настройка суффикса, который сканер добавляет после штрихкода (часто это символ перевода строки).


// Пример настройки для Bluetooth-сканера
глКомпонентаСканера.УстановитьПараметр("EquipmentType", "УстройствоВвода");
глКомпонентаСканера.УстановитьПараметр("BluetoothDevice", "DEV_KEYBOARD");
// Суффикс Enter (CR+LF). Числовое значение может отличаться.
глКомпонентаСканера.УстановитьПараметр("Suffix", 3338); 

Таким образом, главная "магия" стабильной работы внешней компоненты сканера без БПО заключается в правильном управлении временем жизни ее объекта. Сохраняя его в глобальной переменной модуля приложения, вы гарантируете, что он будет существовать в течение всего сеанса и сможет корректно принимать и передавать события от сканера в вашу систему.

← На главную