Как мы писали под Android. Часть первая.
Все совпадения неслучайны, персонажи не вымышлены, некоторые из них настолько близки, что они — это вы.
Если я не хочу это читать. Скажите, что вы такое сделали!
Хорошее решение. Поэтому для вас мы кратко объясним назначение написанного приложения.
Данное приложение предназначено для передачи сканированных штрихкодов с терминалов сбора данных (ТСД), работающих в системе Android, на удаленный TCP сервер. Применяться может тогда, когда с ТСД выполняется подключение к учётной системе напрямую, через RDP клиент. При этом могут возникать проблемы передачи длинных штрихкодов в режиме эмуляции клавиатуры. Примером такой ситуации может являться сканирование акцизных марок алкогольной продукции (длиной 68 и 150 символов), передача нажатия клавиш которых может генерировать задержки нажатий (даже при хорошем WI-FI) и неверно интерпретироваться драйвером клавиатурного сканера.
В некоторых случаях производители ТСД выпускают свои решения для обхода данной проблемы, но, как правило, они недостаточно эффективны и есть не у всех производителей. Например, утилита BServer от производителя Urovo построена по обратной технологии, когда сервером является ТСД, к которому подключается компонента торгового оборудования 1С и забирает отсканированный штрихкод, что заставляет ТСД находиться в той же локальной сети, что и RDP-сервер (что не всегда возможно, если у вас склад находится в Подмосковье, а учётная система где-нибудь в Крыму). Утилита от Motorola — IPDataWedge реализует прямую технологию (клиент ТСД — сервер RDP), однако её серверная часть представляет собой отдельное приложение, которое эмулирует клавиатурный ввод и требует постоянного активного окна 1С. Кроме того, IPDataWedge разработан для ОС Windows Phone, аналоги для Android нам неизвестны.
Также данное приложение может использоваться как сервис транслирующий отсканированные штрихкоды и нажатые аппаратные клавиши в Мобильный Клиент 1С.
Кроме того, мы подготовили ссылку на архив (.zip, 15.3 Мб) с материалами, содержащими:
- ScanCodeTransport.apk — само приложение под Android для передачи штрихкодов;
- WIFITestServer.exe — TCP сервер тестирования передачи штрихкода с ТСД на компьютер;
- Демонстрационная Конфигурация Алкосфера — Транспорт Штрихкодов.cf — файл конфигурации с примерами кода работы с приложением в Тонком и Мобильном клиентах;
- Документация к приложению «Алкосфера — Транспорт штрихкодов«.docx — документация к приложению.
Также доступна ссылка на приложение в Google Play, пока в тестовом режиме. Чтобы получить приложение на мобильном ТСД, необходимо открыть в браузере ссылку под Google-аккаутом ТСД и согласиться на бета-тестирование:
Они на деревьях, Джонни (немного флешбэков)
Когда только-только зарождалось сканирование марок, году в 2016м писали мы заполнение марками «Акты постановки на баланс». Времена были тёмные, Мобильными Клиентами (далее МК) из коробки от 1С ещё и не пахло, а на складах с подачи высших сил контролирующих организаций господствовал ТСД Motorola MC65 (ценой от 50 ₽, так и не пригодившийся).
ТСД — символ эпохи ЕГАИСа, вошедший в историю, грустно пылящийся и поныне на балансе предприятий — тысячи их! Но мы отвлеклись. Результатом разработки были формы под RDP-клиента, формы обычные, 1С, которые просто отображаются на ТСД в сеансе RDP и более никак с ним не взаимодействуют. Отсканированные штрихкоды передавались в режиме эмуляции клавиатуры и всё было хорошо оттестировано, до первого промышленного документа в 200 марок. От складовщиков пошли замечания, что нет-нет, но иногда возникает ситуация, когда штрихкод передается битым — пропадают символы, либо добавляются новые. После изучения проблемы был сделан вывод, что даже самый скоростной канал WIFI добавляет микрозадержки между передачей символов, которые неверно воспринимаются драйверами сканеров ТО (было перепробовано несколько драйверов).
Срочно был начат поиск решения и оно было найдено в виде ПО Motorola IPDataWedge, передающего штрихкоды через стороннее TCP соединение, на сервере эмулирующее нажатия клавиш. И, хотя, настройка этого ПО было делом непростым (это был ад), 1С на RDP сервере не должна была терять фокус ввода, а написанная нами инструкция по настройке занимала 12 страниц, решение было признано удовлетворительным и как-то работало.
Не только лишь все могут смотреть в завтрашний день
Внимание! Раздел полон мэром Киева чуть менее чем полностью.
Продолжение этой проблемы всплыло в начале 2018. Мы разрабатывали подсистему ТСД под наш (и не только наш) помарочный учёт, всё шло хорошо, и настало время выбора ТСД для тестирования. Побродив по рынку, мы столкнулись с совершенно другой картиной. На смену дорогих ТСД под платформу Microsoft пришло множество новых современных ТСД под Android, с гораздо меньшей стоимостью, среди которых мы выбрали ТСД Urovo 6200i по причине демократичности цены, совместимости с 1С и желания просто потыкаться в Android ТСД. В процессе тестирования пришло понимание, что для RDP-клиента под Android (любой — от Microsoft, Parallels, прочие) точно также актуальна проблема потерь сканированных символов. Посмотрев в завтрашний день, мы поняли, что проблема усугубляется еще и тем, что теперь нет единого ТСД, рекомендованного свыше (как Motorola MC65), и, поэтому необходимо универсальное решение передачи штрихкодов. И мы пошли готовиться к земле его искать.
Если что-то хочется, но нельзя — то немного можно
Поиск решения привел меня к понимаю, что всё в принципе просто. Ответственные разработчики ТСД в свои сборки Android-а добавляют рассылку широковещательных сообщений, содержащих отсканированный штрихкод, который можно легко получать, подписавшись на них. Для подписки было необходимо знать Intent сканера и поле, в котором передается штрихкод. Все эти данные — разные для разных ТСД, поэтому эти поля мы будем хранить в настройках, а в программу добавим кнопку «Тест» для проверки параметров ТСД путем сканирования штрихкода без его отправки на сервер с выводом на экран. Получив штрихкод — мы можем легко отправить его куда-нибудь туда, например на сервер RDP, где работает основная 1С, также сохранив адрес сервера и номер порта в настройках. Так как у нас основной программой на ТСД является RDP-клиент, который не может запускать сторонние приложения (в Android это так) — нам нужен автозапуск нашей утилиты, либо пользователю придется отдельно запускать и ее, а ведь он обязательно забудет и будет звонить мне. Поэтому программа должна автозапускаться и поддерживать это опционально. Для выяснения, кто прав, кто виноват, программа должна вести лог файл действий пользователя — и лог файл опциональный. Таким образом, необходимо реализовать:
- Возможность настройки Intent сканера и поля с данными;
- Возможность выполнять тестовое сканирование без отправки ШК на сервер с выводом ШК на экран;
- Возможность настройки адреса и порта сервера;
- Опциональный автозапуск приложения;
- Опциональное ведение лог файла.
Первые 3 пункта были выполнены в рекордно короткие 2 недели первичного знакомства с платформой Android и средствами разработки, хранение настроек было реализовано через SharedPreferences, а потом начались проблемы.
Никогда такого не было и вот — опять
Эта хрень никак не хотела автозапускаться. Сотни перезагрузок реального ТСД (я вот только потом понял, что можно было перезапускать виртуальный девайс, но так как изначально тестировал на реальном ТСД сканирование — продолжал отладку полностью на нем), убитые нервы, искалеченные судьбы некормленых котов — вот это всё пришлось мне пережить.
Всё осложнялось еще и тем, что русскоязычных форумов с такими проблемами просто не было — наши ребята не парятся и сложнее конструирования Intent-ов ничего не обсуждают. Помощь пришла с буржуйского форума, спасибо тебе неизвестный чувак, имя которого останется неизвестным, так как я уже забыл адрес треда.
В результате, решение проблемы бы в создании своего java-класса — наследника BroadcastReceiver, который считывал настройки автозапуска из SharedPreferences, и, в случае необходимости автозапуска — запускал наше приложение. При этом, данный класс должен был быть прописан в AndroidManifest.xml как получатель события «android.intent.action.BOOT_COMPLETED» из категории «android.intent.category.DEFAULT» и дополнительным правом «android.permission.RECEIVE_BOOT_COMPLETED». Само приложение должно иметь дополнительное право «android.permission.RECEIVE_BOOT_COMPLETED» и вы можете увидеть его в Google Play, когда будете устанавливать его:
Храни тебя двоичный код, неизвестный англоязычный парень. Покойтесь с миром мои 2 недели томных вечером и ночей.
Нельзя просто взять и не переписать приложение
Мы переписываем приложение, полностью, практически с нуля. Коварный Android показал нам мать Кузьмы и не думает останавливаться. Наше прекрасное приложение прекрасно работает в тестовом режиме и никак не работает в боевом сеансе RDP. Причина — банальна. Классические приложения Android работают только на переднем фоне. Как только приложение уходит в фоновый режим — оно останавливается. В фоновом режиме работают только сервисы, который мы и будем сейчас срочно реализовывать, перенося логику программы в сервис, а в основном приложении оставим интерфейс и средства обмена с сервисом.
На удивление, всё проходит гладко и через неделю доработок мы готовы к тебе, о дивный новый мир.
Если друг — оказался вдруг (мы переписываем приложение v2)
Всю мою сознательную жизнь я любил протокол UDP. Мне казалось, что он — мой бро. Вот TCP — не бро, его муторно программировать, я еще помню тот ад многопоточных асинхронных TCP серверов (и хотя тут такого не будет, но — флешбэки, флэшбэки), не, он — точно не бро.
Так думал я, когда впиливал обмен с сервером RDP через UDP протокол и всё было нормально в пределах локальной сети, пока мы не начали внедрение на предприятии, сервер RDP которых (вместе с производством и учётной 1С) находился в Крыму, а оптовый склад с ТСД — в Московской области. Почти сразу же стали пропадать отправки штрихкодов, причем пакет пропадал полностью. Подозрение пало на UDP протокол, причем я даже порадовался — наконец то наступил тот мифический случай недоставки пакетов и теперь то я впилю свое подтверждение доставки и повторную отправку прямо как…. в TCP. «Ах ты чертов ублюдок, а ну иди сюда, мать твою»….
То есть — мы переписываем приложение под TCP протокол. Минус 2 дня.
Я их в дверь — они в окно
Вообще, погружение во враждебную среду Android напоминало мне борьбу с гидрой — я ее в дверь — она в окно. Исправив ситуацию в одном месте или доработав приложение — что-то отваливалось в другом. Поэтому периодически приходилось заливать проект напалмом рефакторинга —полностью, с нуля.
Я реально 3 раза начинал заново проект, это было проще и удобнее, чем переписывать блоки кода. Вот и теперь, выделив основную логику работы в отдельный сервис я получил отказ автозапуска сервиса. Никаких ошибок он не выдавал, а просто отказывался запускаться при запуске, в тоже время исправно работая из основного приложения. Особая изюминка в торте была в том, что на этапе автозапуска невозможно подключиться к сервису для отладки.
Причина отказа в запуске сервиса — извращенное понимание Android-ом безопасности, при котором все неявно запускаемые сервисы должны иметь уведомление в области шторки, чтобы пользователь видел, что у него тут что-то функционирует непонятное, а при нажатии на уведомление — открыл основную программу. Для этого сервис был модифицирован до Foreground-сервиса и автозагрузка заработала. Еще 3 дня моей жизни.
В сухом остатке
На этом мы прервемся на время, будет еще вторая часть, в которой мы расскажем про то, как мы переписывали наше приложение, про главную интригу и про то, как мы переписывали приложение еще раз. Также будет про публикацию на Google Play, мои восторги и радости от этой среды и впечатления. Ну и в конце будет мой взгляд на внутренности Android, сравнение с Windows и что со всем этим делать. Оставайтесь с нами, ваш Ежов Дмитрий.