Новое в релизе 1.3.3
Исправлена ошибка повторной генерации внешнего события при использовании XML формата.
Новое в релизе 1.3.2
В сообщение внешнего события о получении широковещательного сообщения добавлена возможность вывода данных в формате json (см. параметр OutputFormat). В более ранних релизах использовался xml, который иногда не читался (по отзывам отдельных пользователей) средствами 1С (ЧтениеXML) из-за представления некоторых символов в виде &...;.
Новое в релизе 1.3
- Теперь все компоненты сборки поддерживают стандарт 1С требований по разработке драйверов 3.3 поскольку фирма 1С выпустила библиотеку подключаемого оборудования для мобильных приложений, поддерживающую этот стандарт. Изменения коснулись, в основном, общих требований к разрабатываемым драйверам. Удален метод ПолучитьНомерВерсии. Вместо него необходимо использовать ПолучитьРевизиюИнтерфейса. Метод ПолучитьОписание содержит только один параметр, который возвращает структуру xml (см. здесь). Состав и параметры общих методов мобильных драйверов приведены к аналогичному составу и параметрам драйверов для стационарной платформы.
- Интерфейс компоненты буфера переработан с целью приближения к стандарту устройства ввода. Удалены свойство СодержимоеБуфера и метод УстановитьСодержимое. Вместо них следует использовать параметр Content и дополнительные действия GetClipboard и PutInClipboard.
- Добавлена компонента работы с bluetooth: поиск и подключение устройств, взаимодействие по протоколу последовательного доступа (com over bluetooth).
- Демострационная конфигурация сделана более наглядной. Теперь для показа работы каждой компоненты используется отдельная форма:
Новое в релизе 1.3.4
С момента публикации прошло несколько лет. Чтобы поддержать новые выпуски ОС Андроид выпущен этот релиз компоненты. Никаких функциональных изменений он не содержит, код просто перекомпилирован новыми инструментами и сделаны косметические изменения для удовлетворения измененным стандартам API Андроида. Рекомендуется новым пользователям или у кого есть проблемы после перехода на новые версии Андроида.
Замечание об архитектуре
Стандарт подключаемых драйверов 1С требует, чтобы поставка драйвера отдельным архивом содержала только один драйвер и, соответственно, один объект AddIn. Цитата из документации: "Внешняя компонента для работы с подключаемым оборудованием должна содержать только один объект, реализующий расширение встроенного языка". В моей практике создания мобильных приложений такой подход часто приводил к катастофическому разрастанию размера приложения. Добавление функциональности к существующей компоненте обычно увеличается ее суммарный размер (apk+so файлы) на 10-20%, в то время как следование правилам стандарта приводит к линейному росту от числа компонент. Исходя из этого, данная разработка нарушает стандарт для удобства применения и развертывания приложений с представленной компонентой.
Широковещательные оповещения
Продолжение статьи автора о внешних компонентах для мобильных приложений, в которой представлен развернутый пример компоненты получения широковещательных оповещений в андроиде (broadcasts). Идею ее создания подсказала работа //infostart.ru/public/587908/, в которой был предложен универсальный получатель сообщений от сканеров, но решение выполнено через сервис, хотя ничто не мешает оформить его в виде компоненты. Архитектурный выигрыш несомненный, но главные удобства получает пользователь, которому нужно будет установить только приложение 1С без дополнительного ПО.
Для подключения компоненты используем стандартный код:
// Component - имя макета, в котором находится компонента
ПодключитьВнешнююКомпоненту("ОбщийМакет.Component", "Broadcasts", ТипВнешнейКомпоненты.Native);
Компонента = Новый("AddIn.Broadcasts.UniversalBroadcast");
Так как решение полностью выполнена по стандарту 1С (устройство ввода), установка параметров выполняется методом "УстановитьПараметр", включение и выключение - "Подключить" и "Отключить" соответственно. Параметр, который обязательно нужно установить - "FilterName", это имя оповещения. Для сканеров его необходимо взять из документации. Также можно использовать любые системные броадкасты, например отсюда. В примере конфигурации к статье представлен способ получения информации о батарее устройства. Следующий важный параметр - "CaptureData". В него следует передать XML строку с описанием извлекаемых дополнительных данных оповещения. Для удобства ее можно получить, вызвав метод "ПолучитьШаблонОписанияДанных", который возвращает строку:
<?xml version="1.0" encoding="utf-8"?>
<dataExtra name="%1" arrayToString="%2" dataType="%3" />
Она содержит три параметра в формате %n, чтобы ее было удобно использовать в методе "ПодставитьПараметрыВСтроку" из БСП. Первый параметр - имя дополнительных данных. Второй должен иметь значения true или false и используется только для обработки массива байт или символов (см. ниже). Третий параметр - число, тип извлекаемых данных в соответствии с таблицей:
Значение параметра | Тип данных |
---|---|
0 | строка |
1 | массив строк |
2 | short |
3 | массив типов short |
4 | long |
5 | массив типов long |
6 | int |
7 | массив типов int |
8 | float |
9 | массив типов float |
10 | double |
11 | массив типов double |
12 | символ |
13 | массив символов |
14 | байт |
15 | массив байтов |
16 | булево |
17 |
массив типов булево |
|
|
|
(Типы последних двух строк могут возвращаться, если параметр CaptureData не задан, об этом режиме работы см. ниже).
Для массивов типов байт или символ параметр attayToString может быть установлен в true. В этом случает при получении дополнительных значений, они будут преобразовываться в строку. Это может пригодится для работы с некоторыми сканерами, которые возвращают результат в виде набора байтов. Покажем код установки параметров перед включением компоненты:
ШаблонДанных = Компонента.ПолучитьШаблонОписанияДанных();
health = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонДанных,"health",XMLСтрока(Ложь),XMLСтрока(6));
Компонента.УстановитьПараметр("CaptureData",health);
tech = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонДанных,"technology",XMLСтрока(Ложь),XMLСтрока(0));
Компонента.УстановитьПараметр("CaptureData",tech);
present = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонДанных,"present",XMLСтрока(Ложь),XMLСтрока(16));
Компонента.УстановитьПараметр("CaptureData",present);
level = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонДанных,"level",XMLСтрока(Ложь),XMLСтрока(6));
Компонента.УстановитьПараметр("CaptureData",level);
Какие данные необходимо получить мы определяем последовательными вызовами установки параметра CaptureData. Удалить или изменить этот набор после установки невозможно, для этого необходимо пересоздать объект компоненты.
Параметр "Category" позволяет добавить к намерению отбор по категориям. Его также можно устанавливать перед стартом отслеживания броадкастов несколько раз, если требуется отбор по нескольким категориям. Очистка набора категорий возможна только при пересоздании объекта компоненты.
Параметр "OutputFormat" управляет форматом вывода данных внешнего события, информирующего о приеме оповещения. Он числовой и может принимать значения: 0 - вывод в виде xml (значение по умолчанию) или 1 - json.
После включения компонента, как и любое устройство ввода, возвращает данные через внешнее событие 1С. Первый параметр события - серийный номер устройства, второй параметр имеет значение "UniversalBroadcastEvent", а третий - строка в выбранном формате. Вывод в XML имеет примерно такой вид:
<?xml version="1.0" encoding="utf-8"?>
<MessageData>
<FilterName>Имя оповещения, заданного параметром FilterName</FilterName>
<FilterData name="имя очередного параметра CaptureData">Значение дополнительных данных</FilterData>
<FilterData name="имя очередного параметра CaptureData">
<ArrayValue>элемент 1 массива данных</ArrayValue>
<ArrayValue>элемент 2 массива данных</ArrayValue>
</FilterData>
</MessageData>
Пример аналогичного вывода в формате JSON:
{
"FilterName":"Имя оповещения, заданного параметром FilterName",
"FilterData":
[{"имя очередного параметра CaptureData":"Значение дополнительных данных"},
{"имя очередного параметра CaptureData":["элемент 1 массива данных","элемент 2 массива данных"]}]
}
Как можно догадаться из примера, значения одиночных дополнительных данных возвращаются в тексте элемента <FilterData>, а массивов элементами <ArrayValue>.
Начиная с релиза 1.1.4 компонента поддерживает автоматическое определение всех возможных фильтров и возвращаемых типов данных. Чтобы включить такой режим, необходимо оставить параметр CaptureData пустым. В демонстрационном приложении перейдите на закладку "Фильтры событий" и оставьте категорию пустой. При возникновении события xml тэг MessageData не будет возвращать значений, но будет включать числовой атрибут datatype в соответствии с приведенной выше таблицей. Если событие будет иметь данные с пустым значением, тип которого невозможно определить, атрибут будет равен 19. Сложным типам, необрабатываемым компонентой, будет присвоен индекс 18.
<?xml version="1.0" encoding="utf-8"?>
<MessageData>
<FilterName>Имя оповещения, заданного параметром FilterName</FilterName>
<FilterData name="имя очередного параметра CaptureData" datatype="число - индекс типа из таблицы"/>
<!-- любое число тэгов FilterData -->
</MessageData>
{
"FilterName":"Имя оповещения, заданного параметром FilterName",
"FilterData":
[{"name":"имя очередного параметра CaptureData","datatype":число - индекс типа из таблицы},
...
]}
Приведем пример xml, возвращаемого батареей (android.intent.action.BATTERY_CHANGED) в режиме определения фильтров:
И в режиме определения заряда батареи:
Пользователи могут использовать конфигурацию из статьи для определения значений фильтров любых событий, если вручную отредактируют имя намерения и вызовут событие.
Буфер обмена
В версии 1.1 компоненты добавлена работа с буфером обмена Андроида (clipboard). Буфер позволяет выполнять операции вставки и извлечения (Copy/Paste) и может содержать данные типов текст, гиперссылка и намерение. Компонента содержит следующие параметры и дополнительные действия:
Для помещения текста в буфер обмена установите параметры Content и Label и вызовите дополнительный метод PutInClipboard. Компонента также в состоянии передать в 1С оповещение об изменении буфера любой программой или службой.
Подключение объекта буфера:
КомпонентаБуфер = Новый("AddIn.Broadcasts.Clipboard");
Объект Clipboard реализован по стандарту устройства ввода. Соответственно, имеет методы Подключить и Отключить. Получение содержимого буфера выполняется с помощью дополнительного действия GetClipboard. Сразу после его вызова компонента порождает внешнее событие ClipboardEvent. В третьем параметре оповещения находится текст из буфера обмена.
Работа с Bluetooth
Драйвер поддерживает следующие операции:
- программное включение bluetooth, получение списка подключенных устройств, обнаружение доступных неподключенных устройств и их подключение;
- работу с устройствами через последовательные чтение/запись (com over bluetooth). Чтение данных может выполняться синхронно, в этом случае приложение ожидает данные, пока они не появятся от устройства, а приложение останавливается. Либо асинхронно в двух режимах - по запросу и в фоне. В первом случае компонента проверяет наличие данных и если их нет, возвращает ошибку, во втором ответ от устройства проверяется постоянно в отдельном потоке и при появлении данных в 1С возникает внешнее событие. Последний режим удобен для работы со сканерами, например такими. Работа с блютуз добавлена в представленную компоненту, чтобы расширить область ее применения в отношение сканеров.
Рассмотрим сценарии использования bluetooth драйвера. Подключение объекта выполняется стандартно:
КомпонентаBluetooth = Новый("AddIn.Broadcasts.BluetoothCommunication");
Включение или выключение булевого параметра DiscoveryMode определяет в каком режиме мы будем подключать компоненту. Вначале рассмотрим режим поиска устройств (DiscoveryMode = Истина). В этом режиме после вызова метода Подключить компонента в фоновом процессе будет выполнять поиск всех доступных устройств и при их обнаружении передавать внешнее событие с именем DeviceDiscovered:
Данные об устройстве возвращаются в строке xml вида:
<BluetoothDevice Name="Any device" Address="01:01:01:01:01:01"/>
содержащей имя и mac-адрес устройства. О включении и завершении режима поиска дополнительно сигнализируют внешние события DiscoveringStarted и DiscoveringStopped. Когда DiscoveryMode установлен в Истина, прочие параметры не оказывают возвдействие на работу компоненты, кроме одного - AutoEnable. Он также содержит булево значение. Если его включить, а в настройках вашего устройства блютуз окажется выключенным, компонента попытается его включить, запросив разрешение у пользователя через стандартный диалог. Аналогичным образом блютуз может включатся и в режиме обмена данными.
Примечание: К сожалению, архитектура внешних компонент 1С для Андроид не позволяет оповещать мобильное приложение об ответах пользователя в стандартных диалогах. В данной работе это относится как к упомянутому диалогу активации блютуз, так и к выводимым компонентой запросам на дополнительное права администратора блютуз и диалогам на сопряжения устройств. В таких случаях компонента в методе Подключить возвращает ошибки с кодом 2001 или 1002. Разработчик мобильного приложения должен будет предложить пользователю подключиться повторно или реализовать какой-нибуть цикл с задержкой для повторной проверки результата подключения.
При работе драйвера в режиме коммуникации (DiscoveryMode=False) обязательна установка параметра Device (строка). Это может быть как mac-адрес, так и имя устройства. Несопряженные устройства при подключении будут вызывать стандартный системный диалог:
После подтверждения пользователя устройство будет добавлено в список сопряженных и подключено. Разрабочик мобильного приложения может также воспользоваться списком сопряженных устройств, который читается и возвращается в 1С при получении параметров (метод ПолучитьПараметры) в подчиненных элементах ChoiceList элемента Parameter с именем Device. Если устройство доступно и поддерживает коммуникацию по com-протоколу, после вызова метода Подключить, драйвер открывает потоки на запись и чтение.
Для записи (передачи данных) от мобильного приложения на устройство разработчик может воспользоваться
- подходом, соответствующим стандарту внешних компонент: данные записываются в параметр InputData в формате строки Base64; передача происходит при вызове дополнительного действия SendData
- более быстрым способом: вызвать метод ЗаписатьДанные (WriteData), который принимает два аргумента - номер устройства (возвращаемый при вызове Подключить, строка) и сами данные для записи с типом 1С ДвоичныеДанные. При частой коммуникации, понятно, что в этом случае скорость достигается за счет экономии в преобразованиях из base64 и обратно
Чтение данных, как было упомянуто выше, может выполняться в трех режимах, определяемых установкой параметра ReadMode. Если он равен 0, компонента будет ожидать данные от устройства бесконечно долго, и если их нет, блокировать основной поток. Если он равен 1, компонента проверяет наличие данных в потоке чтения. Если они есть, данные читаются, если нет - возвращается ошибка 2013 (в методе ReadData). Установка параметра в значение 2 включает асинхронный режим чтения, когда появление данных будет вызывать внешнее событие DataReceived, а сами данные возвращатся в третьем параметре события в виде строки base64. В асинхронном режиме последовательность чтения и записи не определена, то есть невозможно гарантировать, что данные, отправленные на устройство окажутся там раньше или позже прочитанных данных. Технически чтение инициализируется методом ПрочитатьДанные (ReadData). Первый параметр, как обычно, логический номер устройства, во второй возвращаются данные в виде двоичных данных 1С. Добавленные в платформу в последних релизах мощные средства работы с двоичными данными в виде потоков, позволят разработчику перекодировать их в строки с любыми кодировками при необходимости. Параметр DirectRead (булево) во включенном состоянии указывает драйверу порождать внешние события DataReceived при каждом получении данных. Понятно, что он имеет смысл для режимов 0 и 1. В асинхронном режиме внешнее событие возникает в любом случае. Его установка как и при чтении немного замедляет работу драйвера, если Вы работаете с синхронным устройством в режиме 0, внешние события будут лишними. Для режима 0 используется еще один параметр BufferSize. Это число - размер буфера чтения в байтах. Если размер данных превышает установленный размер буфера, чтение будет успешно выполнено несколько раз до исчерпания данных.
В режиме последовательной коммуникации (ReadMode=0), с помощью этой компоненты можно запрограммировать работу многих синхронных устройств, например, кассовых аппаратов. В моем багаже имееется несколько компонент для мобильной платформы 1С, предназначенных для ККМ, поддерживающих технологию блютуз. Командный протокол для них "зашит" в код самой компоненты, но я не вижу препятствий для реализации команд устройств, используя саму 1С платформу и эту внешнюю компоненту.
О примере
Макет компоненты из конфигурации, прилагаемой, к статье не содержит дополнительных разрешений (permissioms). Если они требуются для получения конкретных оповещений, их можно добавить в архив макета компоненты (включить файл android_manifest_permissions.xml) и собрать приложение.
Конфигурация и внешняя компонента предназначены для работы с релизом мобильной платформы не ниже 8.3.15.59. Допускается также работа с релизами, начиная с 13-го, но для этого необходимо вручную отредактировать манифест компоненты в архиве и удалить поддержку 64-битный платформ.