При разработке мобильных приложений на платформе 1С часто возникает задача подключить сканер штрихкодов. Использование внешней компоненты "1С:Сканер штрихкода" (Native) без полной "Библиотеки подключаемого оборудования" (БПО) кажется логичным упрощением. Однако такой подход часто приводит к неожиданной проблеме: при попытке сканирования мобильное приложение аварийно завершает работу ("вылетает"), а событие со штрихкодом так и не поступает в обработчик ОбработкаВнешнегоСобытия.
В этой статье мы подробно разберем, почему возникает эта критическая ошибка и как ее правильно исправить, обеспечив стабильную работу сканера.
Основная причина вылета приложения кроется в механизме управления памятью платформы 1С, а именно — в работе сборщика мусора. Давайте проанализируем типичный ошибочный код подключения компоненты:
// Пример ошибочного кода, который приводит к вылету
Процедура ПодключитьСканерПриОткрытииФормы()
Если ПодключитьВнешнююКомпоненту("ОбщийМакет.Драйвер1СУстройстваВводаNative", "AddIn", ТипВнешнейКомпоненты.Native) Тогда
// Переменная "Компонента" является ЛОКАЛЬНОЙ
Компонента = Новый ("AddIn.AddIn.InputDevice");
// Настройка параметров...
Компонента.УстановитьПараметр("BluetoothDevice", "BROADCAST");
// ... другие параметры
Компонента.Подключить("Штрихкод");
Иначе
Сообщить("Компонента для сканера штрихкодов не подключена");
КонецЕсли;
КонецПроцедуры // <-- В этот момент переменная "Компонента" уничтожается!
Разберем по шагам, что происходит:
Компонента внутри некоторой процедуры (например, при открытии формы).Именно поэтому приложение вылетает без каких-либо внятных сообщений об ошибке со стороны 1С. Система просто не успевает ничего обработать.
Чтобы избежать уничтожения объекта, его нужно хранить в переменной, которая будет существовать на протяжении всего сеанса работы мобильного приложения. Идеальное место для этого — модуль приложения.
Рассмотрим пошаговую реализацию:
В модуле вашего мобильного приложения объявите экспортную переменную, в которой будет храниться объект компоненты.
// Модуль приложения
Перем глКомпонентаСканера Экспорт;
Создайте процедуру для подключения и настройки сканера и вызовите ее в обработчике события ПриНачалеРаботыСистемы. Важно присвоить созданный объект именно вашей глобальной переменной.
// Модуль приложения
Процедура ПриНачалеРаботыСистемы()
ПодключитьСканерШтрихкода();
КонецПроцедуры
Процедура ПодключитьСканерШтрихкода()
Если НЕ ПодключитьВнешнююКомпоненту("ОбщийМакет.Драйвер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");
// Подключаем устройство
глКомпонентаСканера.Подключить("СканерШК");
Исключение
Сообщить("Ошибка при создании или подключении объекта компоненты: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Теперь, когда объект компоненты живет постоянно, он сможет корректно передавать данные в обработчик ОбработкаВнешнегоСобытия в том же модуле приложения.
// Модуль приложения
Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)
// Проверяем, что событие пришло от нашего сканера
Если Событие = "Штрихкод" Тогда // Имя, которое мы задали в параметре "EventName"
// Здесь ваш код обработки полученного штрихкода
Сообщить("Получен штрихкод: " + Данные);
// Например, можно вызвать метод открытой формы
Форма = ПолучитьТекущуюФорму();
Если Форма <> Неопределено И Форма.Открыта() Тогда
Форма.ОбработатьШтрихкод(Данные);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Функция ПолучитьТекущуюФорму()
Если КлиентскоеПриложение.ПолучитьСписокОкон().Количество() > 0 Тогда
Возврат КлиентскоеПриложение.ПолучитьСписокОкон()[0].ПолучитьСодержимое()[0];
КонецЕсли;
Возврат Неопределено;
КонецФункции
Компонента универсальна, и ее поведение зависит от установленных параметров.
Такие сканеры отправляют данные через широковещательные сообщения Android. Для их настройки ключевыми являются параметры Action и Extra. Эти значения уникальны для каждого производителя и модели ТСД, их нужно искать в документации к устройству.
BluetoothDevice: всегда устанавливается в "BROADCAST".Action: имя намерения (Intent Action).Extra: ключ, по которому передаются данные штрихкода.Примеры значений для популярных моделей:
Для обычных Bluetooth-сканеров, которые подключаются к устройству как внешняя клавиатура, используется другой режим.
BluetoothDevice: устанавливается в "DEV_KEYBOARD".В этом режиме компонента перехватывает ввод именно с физической клавиатуры, позволяя отличить его от ввода с экранной. Также может потребоваться настройка суффикса, который сканер добавляет после штрихкода (часто это символ перевода строки).
// Пример настройки для Bluetooth-сканера
глКомпонентаСканера.УстановитьПараметр("EquipmentType", "УстройствоВвода");
глКомпонентаСканера.УстановитьПараметр("BluetoothDevice", "DEV_KEYBOARD");
// Суффикс Enter (CR+LF). Числовое значение может отличаться.
глКомпонентаСканера.УстановитьПараметр("Suffix", 3338);
Таким образом, главная "магия" стабильной работы внешней компоненты сканера без БПО заключается в правильном управлении временем жизни ее объекта. Сохраняя его в глобальной переменной модуля приложения, вы гарантируете, что он будет существовать в течение всего сеанса и сможет корректно принимать и передавать события от сканера в вашу систему.