ВК имеет следующие функции:
1. Перехват широковещательных сообщений ОС андроид по заданному фильтру и ключу данных (extras).
2. Получать ИД устройства (с 10 версии ОС это не аппаратный ИД - https://developer.android.com/training/articles/user-data-ids).
3. Получать архитектуру процессора устройства (ABI - в терминологии ОС Android).
4. Сжимать (и разжимать обратно:)) двоичные данные (Deflate).
5. Сжимать файлы (Deflate).
6. Распознавать штрихкод с картинки (zxing).
7. Изменять разрешение и качество картинки.
8. Работать с файловой системой средствами ядра linux.
8.1. Возвращать массив объектов в заданной директории
8.2. Проверять, директория-ли объект файловой системы
8.3. Удалять объект файловой системы
8.4. Создавать файл
8.5. Создавать директорию
8.6. Писать двоичные данные в файл
8.7. Читать двоичные данные из файла
8.8. Переименовывать объект файловой системы
8.9. Проверять на существование объекта файловой системы
9. HTTP - сервер. (Прием входящих POST и PUT запросов и обработка запросов на стороне 1с (через внешнее событие). Ответ на запрос формируется в коде 1с).
10. Отображать производителя и модель устройства.
11. Получать геоданные устройства.
12.Работать с внешней СУБД sqlite3
13. Получать состав каталога по smb-протоколу (aka linux samba)
14. Получать содержимое файлов в двоичном виде по smb-протоколу (aka linux samba)
15. Записывать файлы в сетевой каталог по smb-протоколу
16. Работа с regEx. Пытается сопоставить регулярное выражение с последовательностью символов (regex_match). Подгруппы тоже ищутся и выводятся в массив результата.
17. Работа с regEx. Заменяет вхождения регулярного выражения форматированным замещающим текстом (regex_replace).
18. QR-code генератор. Функция поглощает строку и длину стороны картинки (квадрат), а выдает BASE64-строку, в которой завернуты двоичные данные картинки QR-кода. См. пример.
19.JSON-валидатор.
Тестирование производилось на платформах 8.3.19.51, 8.3.18.60, 8.3.20.40.
Работа компоненты на версиях OS и архитектурах:
ARM | >=API 22 |
x86 | >=API 22 |
ARM64 | не поддерживается |
x86_64 | не поддерживается |
Описание функций.
//--------Установка компоненты--------//
УстановитьВнешнююКомпоненту("ОбщийМакет.TestPro");
ПодключитьВнешнююКомпоненту("ОбщийМакет.TestPro", "Component", ТипВнешнейКомпоненты.Native);
ВК = Новый("AddIn.Component.Hermes");
//---------------------------------------------------------------------------//
//ЗапуститьПерехватБроадкастов//
//Может перехватывать любой броадкаст с известным фильтром и ключом данных //
//---------------------------------------------------------------------------//
Процедура Запустить()
м = новый массив;
М.Добавить(новый структура("filter, extra",
"com.xcheng.scanner.action.BARCODE_DECODING_BROADCAST",
"EXTRA_BARCODE_DECODING_DATA"));
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, М);
Джейсон = ЗаписьJSON.Закрыть();
Рез = ВК.ЗапуститьПерехватБроадкастов(Джейсон);
Если Рез = "ok_en" тогда
Предупреждение("Перехват установлен")
иначе
Предупреждение(Рез);
КонецЕсли;
КонецПроцедуры
Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)
Если стрСравнить(СокрЛП(Источник),"Hermes") = 0 тогда
Если стрСравнить(СокрЛП(Событие),"BroadcastCatched") = 0 тогда
Попытка
локДанные = РазобратьJSON(Данные);
action = Неопределено;
_key = Неопределено;
Data = Неопределено;
локДанные.Свойство("action",action);
локДанные.Свойство("key",_key);
локДанные.Свойство("Data",Data);
Если стрСравнить(сокрлп(action),"com.xcheng.scanner.action.BARCODE_DECODING_BROADCAST") = 0 тогда
Если стрСравнить(сокрлп(_key),"EXTRA_BARCODE_DECODING_DATA") = 0 тогда
Оповестить(Событие, новый структура("Данные, Тип", СокрЛП(Data), "hell_sighn"), Источник);
КонецЕсли;
КонецЕсли;
исключение
ОШ = ОписаниеОшибки();
Предупреждение(ОШ);
КонецПопытки;
иначеЕсли СтрСравнить(СокрЛП(Событие), "http_request") = 0 тогда
J = РазобратьJSON(СокрЛП(Данные));
J.data = "qwerqwerqwerqwer";
ВК.HTTPСервер_Ответить(СформироватьJSON_(J));
КонецЕсли;
Возврат;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Данные, Источник)
Если стрСравнить(Источник,"TestPro")=0 тогда
Если стрСравнить(ИмяСобытия,"BroadcastCatched")=0 Тогда
Если СтрСравнить(Данные.тип,"hell_sighn")=0 тогда
штрихкод = Данные.Данные;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ОстановитьПерехватБроадкастов//
//---------------------------------------------------------------------------//
Рез = ВК.ОстановитьПерехватБроадкастов();
Если Рез = "ok_en" тогда
Предупреждение("Перехват снят")
иначе
Предупреждение(Рез);
КонецЕсли;
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//=============================ИДУстройства==================================//
//Это не настоящий DeviceID, а некий синтетический идентификатор, выдаваемый //
//ОС вызывающему приложению при вызове метода //
//Settings.Secure.getString(m_Activity.getContentResolver(), //
//Settings.Secure.ANDROID_ID), //
//преобразованный к формату GUID //
//(Начиная с 10 Андроида доступ "обычных" приложений к аппаратным //
//идентификаторам устройства ограничен.) //
//---------------------------------------------------------------------------//
ИД = ВК.ИДУстройства();
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//АндроидИД//
//То-же самое, что и ИДУстройства, только передаваемый в 1с "как есть", //
//т.е. без приведения к виду GUID //
//---------------------------------------------------------------------------//
ИД = ВК.АндроидИД();
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//Архитектура//
//Возвращает архитектуру процессора устройства (ABI - в терминологии Андроид)//
//---------------------------------------------------------------------------//
Арх = ВК.Архитектура();
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//HTTPСервер_Запустить//
//---------------------------------------------------------------------------//
//Запускает локальный http-сервер на базе Nano, который принимает входящие //
//POST/PUT-запросы. Каждый запрос обрабатывается в своем потоке и ему //
//(запросу)присваевается ThreadID. После этого поток синхронно отправляет //
//данные запроса в 1с - как внешнее событие. 1с должна в течение 60 секунд //
//обработать запрос и вернуть ответ в компоненту. //
//Если ответ 1с'ом не возвращен, то клиент получит 500 ответ с описанием //
//ошибки = "SERVER INTERNAL ERROR: превышено ожидаемое время обработки //
//запроса на стороне 1с." //
//Есть нюанс работы: если сервер долго не принимает запросов, а приложение, в//
//контексте которого он запущен, свернуто, то ОС через некоторое время //
//останавливает поток сервера и его приходится перезапускать //
//---------------------------------------------------------------------------//
Порт = 8086;
Ответ = ВК.HTTPСервер_Запустить(Порт);
Если СтрСравнить(сокрЛП(Ответ),"ok_en") = 0 тогда
Предупреждение("HTTP сервер запущен на порту: " + Строка(Порт));
иначе
Предупреждение("Ошибка: " + ответ);
КонецЕсли;
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//HTTPСервер_Остановить//
//---------------------------------------------------------------------------//
//Останавливает локальный http-сервер //
//---------------------------------------------------------------------------//
Ответ = ВК.HTTPСервер_Остановить();
Если СтрСравнить(сокрЛП(Ответ),"ok_en") <> 0 тогда
Предупреждение(Ответ);
иначе
Предупреждение("HTTP сервер остановлен");
КонецЕсли;
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//HTTPСервер_Ответить//
//---------------------------------------------------------------------------//
//Выполняется в контексте обработчика внешнего события глобального модуля. //
//Возвращает в http-сервер ответ, котрый будет переправлен клиенту. //
//---------------------------------------------------------------------------//
Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)
Если стрСравнить(СокрЛП(Источник),"Hermes") = 0 тогда
Если стрСравнить(СокрЛП(Событие),"BroadcastCatched") = 0 тогда
Попытка
локДанные = РазобратьJSON(Данные);
action = Неопределено;
_key = Неопределено;
Data = Неопределено;
локДанные.Свойство("action",action);
локДанные.Свойство("key",_key);
локДанные.Свойство("Data",Data);
Если стрСравнить(сокрлп(action),"com.xcheng.scanner.action.BARCODE_DECODING_BROADCAST") = 0 тогда
Если стрСравнить(сокрлп(_key),"EXTRA_BARCODE_DECODING_DATA") = 0 тогда
Оповестить(Событие, новый структура("Данные, Тип", СокрЛП(Data), "hell_sighn"), Источник);
КонецЕсли;
КонецЕсли;
исключение
ОШ = ОписаниеОшибки();
Предупреждение(ОШ);
КонецПопытки;
иначеЕсли СтрСравнить(СокрЛП(Событие), "http_request") = 0 тогда
J = РазобратьJSON(СокрЛП(Данные));
J.data = "qwerqwerqwerqwer";
ВК.HTTPСервер_Ответить(СформироватьJSON_(J));
КонецЕсли;
Возврат;
КонецЕсли;
КонецПроцедуры
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ZLIB_Архивировать//
//Архивирует двоичные данные алгоритмом Deflate
//---------------------------------------------------------------------------//
масМарки = новый массив;
джМарки = JSON.СформироватьJSON(масМарки);
ДД = ПолучитьДвоичныеДанныеИзСтроки(джМарки);
ДДАрх = ВК.ZLIB_Архивировать(ДД);
Если ТипЗнч(ДДАрх) = Тип("ДвоичныеДанные") тогда
ДДРазарх = ВК.ZLIB_Разархивировать(ДДАрх, ДД.Размер());
КонецЕсли;
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ZLIB_Разархивировать//
//Разархивирует двоичные данные, заархивированные алгоритмом Deflate
//---------------------------------------------------------------------------//
масМарки = новый массив;
джМарки = JSON.СформироватьJSON(масМарки);
ДД = ПолучитьДвоичныеДанныеИзСтроки(джМарки);
ДДАрх = ВК.ZLIB_Архивировать(ДД);
Если ТипЗнч(ДДАрх) = Тип("ДвоичныеДанные") тогда
ДДРазарх = ВК.ZLIB_Разархивировать(ДДАрх, ДД.Размер());
КонецЕсли;
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ZLIB_АрхивироватьФайл//
//Архивирует файл алгоритмом Deflate
//---------------------------------------------------------------------------//
ДДист = ПолучитьДвоичныеДанныеИзСтроки("Какие-нибудь данные");
ИВФИст = ПолучитьИмяВременногоФайла("dat");
ИВФНазн = ПолучитьИмяВременногоФайла("dat");
ДДист.Записать(ИВФИст);
Р = ВК.ZLIB_АрхивироватьФайл(ИВФИст, ИВФНазн);
ДДАрх = новый ДвоичныеДанные(ИВФНазн);
УдалитьФайлы(ИВФИст);
Р1 = ВК.ZLIB_РазархивироватьФайл(ИВФНазн, ИВФИст);
ДД1 = новый ДвоичныеДанные(ИВФИст);
УдалитьФайлы(ИВФИст);
УдалитьФайлы(ИВФНазн);
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ZLIB_РазархивироватьФайл//
//Разархивирует файл, сжатый алгоритмом Deflate
//---------------------------------------------------------------------------//
ДДист = ПолучитьДвоичныеДанныеИзСтроки("Какие-нибудь данные");
ИВФИст = ПолучитьИмяВременногоФайла("dat");
ИВФНазн = ПолучитьИмяВременногоФайла("dat");
ДДист.Записать(ИВФИст);
Р = ВК.ZLIB_АрхивироватьФайл(ИВФИст, ИВФНазн);
ДДАрх = новый ДвоичныеДанные(ИВФНазн);
УдалитьФайлы(ИВФИст);
Р1 = ВК.ZLIB_РазархивироватьФайл(ИВФНазн, ИВФИст);
ДД1 = новый ДвоичныеДанные(ИВФИст);
УдалитьФайлы(ИВФИст);
УдалитьФайлы(ИВФНазн);
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//PHOTO_ИзменитьКартинку//
//Изменяет разрешение и качество картинки. Под качеством подразумевается //
//величина, обратная степени сжатия картинки алгоритмом JPEG //
//---------------------------------------------------------------------------//
ФайлКартинки = КаталогДокументов()+"MobileFoto.jpg";
ФайлКартинки = СтрЗаменить(ФайлКартинки,"\","/");
ФайлКартинки = "file://" + ФайлКартинки;
НовВз = Новый ЗапускПриложенияМобильногоУстройства(
"android.media.action.IMAGE_CAPTURE");
НовВз.ДополнительныеДанные.Добавить("output",ФайлКартинки,"Uri");
Если НовВз.Запустить(Истина) <> 0 Тогда
ИВФВых = ПолучитьИмяВременногоФайла("jpg");
Р = ВК.PHOTO_ИзменитьКартинку(ФайлКартинки,
ИВФВых,
ЭтаФорма.РазрешениеХ,
ЭтаФорма.РазрешениеУ,
ЭтаФорма.Какчество);
ДД = новый ДвоичныеДанные(ИВФВых);
ОтобразитьКартинку(ДД);
КонецЕсли;
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//Версия//
//Возвращает версию компоненты
//---------------------------------------------------------------------------//
Сообщить(ВК.Версия());
//---------------------------------------------------------------------------//
//-----------------------------------------------------------------------------//
//ZXING_РаспознатьШтрихкод//
//Пытается прочитать любой 1- и 2-мерный штрихкод.
//Функция имеет 2 перегрузки: //
//1. в качестве параметра принимается строка - имя файла картинки с штрихкодом //
//2. в качестве параметра принимаются двоичные данные картинки //
//-----------------------------------------------------------------------------//
&НаКлиенте
Процедура РаспознатьQRCodeСКартинки(Команда)
//1.Вариант с чтением картинки из файла
Картинка = ЗаписатьКартинкуВФайл(КаталогДокументов());
стр = ВК.ZXING_РаспознатьШтрихкод(Картинка);
стк = JSON.РазобратьJSON(стр);
Если стк.status тогда
УдалитьФайлы(Картинка);
Предупреждение(стк.data);
иначе
Предупреждение(стк.description);
КонецЕсли;
//2.Вариант с чтением картинки из ДД
стр = ВК.ZXING_РаспознатьШтрихкод(ПолучитьДДКартинки());
стк = JSON.РазобратьJSON(стр);
Если стк.status тогда
Предупреждение(стк.data);
иначе
Предупреждение(стк.description);
КонецЕсли;
Данные = СредстваМультимедиа.СделатьФотоснимок(ТипКамерыУстройства.Задняя,
новый РазрешениеКамерыУстройства(800, 600),
100,
,
ТипПодсветкиКамеры.Выключена);
Если Данные <> неопределено тогда
стр = ВК.ZXING_РаспознатьШтрихкод(Данные.ПолучитьДвоичныеДанные());
стк = JSON.РазобратьJSON(стр);
Если стк.status тогда
Предупреждение(стк.data);
иначе
Предупреждение(стк.description);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция ЗаписатьКартинкуВФайл(КаталогДокументов)
ИВФ = КаталогДокументов + "MobileFoto.png";
ПолучитьДДКартинки().Записать(ИВФ);
ИВФ = СтрЗаменить(ИВФ,"\","/");
ИВФ = "file://" + ИВФ;
Возврат ИВФ;
КонецФункции
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ФС_ПрочитатьКаталог//
//Возвращает массив объектов каталога файловой системы - если у приложения //
//в этот каталог есть соответствующий доступ. //
//---------------------------------------------------------------------------//
&НаКлиенте
Функция УдалитьФсеФСОРекурсивно(вхКаталог, ВК)
Если РазобратьJSON(ВК.ФС_ОбъектФССуществует(вхКаталог)).Status тогда
сткРез = РазобратьJSON(ВК.ФС_ПрочитатьКаталог(вхКаталог));
Если сткРез.Status тогда
сткРез0 = РазобратьJSON(сткРез.Data);
Для каждого эстк из сткРез0 Цикл
Если эстк.Значение = ".." или эстк.Значение = "." тогда
продолжить
КонецЕсли;
П = вхКаталог + ?(прав(вхКаталог,1)="/","","/") +
эстк.Значение;
сткЭтоДиректорияСтатус =
РазобратьJSON(ВК.ФС_ЭтоДиректория(П));
Если сткЭтоДиректорияСтатус.Status тогда
Если РазобратьJSON(сткЭтоДиректорияСтатус.Data).
IsDirectory тогда
УдалитьФсеФСОРекурсивно(П, ВК);
КонецЕсли;
КонецЕсли;
ВК.ФС_УдалитьФайлИлиКаталог(П);
КонецЦикла;
КонецЕсли;
КонецЕсли;
ВК.ФС_УдалитьФайлИлиКаталог(?(прав(вхКаталог,1)="/",
Лев(вхКаталог,стрДлина(вхКаталог)-1), вхКаталог));
КонецФункции
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ФС_ЭтоДиректория//
//Проверяет: объект файловой системы - директория или файл.
//---------------------------------------------------------------------------//
сткЭтоДиректорияСтатус = РазобратьJSON(ВК.ФС_ЭтоДиректория(П));
Если сткЭтоДиректорияСтатус.Status тогда
Если РазобратьJSON(сткЭтоДиректорияСтатус.Data).IsDirectory тогда
УдалитьФсеФСОРекурсивно(П, ВК);
КонецЕсли;
КонецЕсли;
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ФС_УдалитьФайлИлиКаталог//
//Удаляет объект файловой системы.
//---------------------------------------------------------------------------//
Ответ = ВК.ФС_УдалитьФайлИлиКаталог(
"/data/data/com.e1c.mobile/files/1C/1cem/test/test.txt");
стк = РазобратьJSON(Ответ);
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ФС_СоздатьФайл//
//Создает файл
//---------------------------------------------------------------------------//
Ответ = ВК.ФС_СоздатьФайл(
"/data/data/com.e1c.mobile/files/1C/1cem/test/test.txt");
стк = РазобратьJSON(Ответ);
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ФС_СоздатьКаталог//
//Создает каталог
//---------------------------------------------------------------------------//
Ответ = ВК.ФС_СоздатьКаталог(
"/data/data/com.e1c.mobile/files/1C/1cem/test", 511);
стк = РазобратьJSON(Ответ);
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ФС_ПереименоватьФайлИлиКаталог//
//переименовывает файл или каталог
//---------------------------------------------------------------------------//
Ответ = ВК.ФС_ПереименоватьФайлИлиКаталог(
"/data/data/com.e1c.mobile/files/1C/1cem/test/test.txt",
"/data/data/com.e1c.mobile/files/1C/1cem/test/test1.txt");
стк = РазобратьJSON(Ответ);
Если стк.Status тогда
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ФС_ЗаписатьДанныеВФайл//
//Пишет двоичные данные в файл //
//---------------------------------------------------------------------------//
Ответ = ВК.ФС_ЗаписатьДанныеВФайл(
"/data/data/com.e1c.mobile/files/1C/1cem/test/test.txt",
ПолучитьДвоичныеДанныеИзСтроки("СтрокаДляДД"));
стк = РазобратьJSON(Ответ);
Если стк.Status тогда
Ответ = ВК.ФС_ПрочитатьДанныеИзФайла(
"/data/data/com.e1c.mobile/files/1C/1cem/test/test.txt");
Если ТипЗнч(Ответ) = тип("ДвоичныеДанные") тогда
стр = ПолучитьСтрокуИзДвоичныхДанных(Ответ);
КонецЕсли;
КонецЕсли;
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ФС_ПрочитатьДанныеИзФайл//
//---------------------------------------------------------------------------//
Ответ = ВК.ФС_ЗаписатьДанныеВФайл(
"/data/data/com.e1c.mobile/files/1C/1cem/test/test.txt",
ПолучитьДвоичныеДанныеИзСтроки("СтрокаДляДД"));
стк = РазобратьJSON(Ответ);
Если стк.Status тогда
Ответ = ВК.ФС_ПрочитатьДанныеИзФайла(
"/data/data/com.e1c.mobile/files/1C/1cem/test/test.txt");
Если ТипЗнч(Ответ) = тип("ДвоичныеДанные") тогда
стр = ПолучитьСтрокуИзДвоичныхДанных(Ответ);
КонецЕсли;
КонецЕсли;
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ФС_ОбъектФССуществует//
//Проверяет: существует-ли каталог или файл //
//---------------------------------------------------------------------------//
Ответ = ВК.ФС_ОбъектФССуществует(
"/data/data/com.e1c.mobile/files/1C/1cem/test");
стк = РазобратьJSON(Ответ);
КаталогСуществует = ложь;
Если стк.Status тогда
КаталогСуществует = истина;
КонецЕсли;
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//Общий пример для работы с файловой системой: удаляет все файлы внешних //
//компонент из каталога ExtCompT мобильной платформы. //
//---------------------------------------------------------------------------//
&НаКлиенте
Процедура СканироватьФайловуюСистему(Команда)
//stat.h
//#define S_IRWXU 00700
//#define S_IRUSR 00400
//#define S_IWUSR 00200
//#define S_IXUSR 00100
//#define S_IRWXG 00070
//#define S_IRGRP 00040
//#define S_IWGRP 00020
//#define S_IXGRP 00010
//#define S_IRWXO 00007
//#define S_IROTH 00004
//#define S_IWOTH 00002
//#define S_IXOTH 00001
БазовыйКаталог = "";
Ответ = ВК.ФС_ОбъектФССуществует(
"/data/data/com.yourapp.tsd/files/1C/1cem");
стк = РазобратьJSON(Ответ);
Если стк.Status тогда
БазовыйКаталог = "/data/data/com.yourapp.tsd/files/1C/1cem";
иначе
Ответ = ВК.ФС_ОбъектФССуществует(
"/data/data/com.e1c.mobile/files/1C/1cem");
стк = РазобратьJSON(Ответ);
Если стк.Status тогда
БазовыйКаталог = "/data/data/com.e1c.mobile/files/1C/1cem";
КонецЕсли;
КонецЕсли;
Если БазовыйКаталог <> "" тогда
Ответ = ВК.ФС_ПрочитатьДанныеИзФайла(БазовыйКаталог +
"/ibases.v8i");
Если ТипЗнч(Ответ) = тип("ДвоичныеДанные") тогда
стр = ПолучитьСтрокуИзДвоичныхДанных(Ответ);
Попытка
ИВФ = ПолучитьИмяВременногоФайла("txt");
ЗаписьТекста = новый ЗаписьТекста(ИВФ);
ЗаписьТекста.ЗаписатьСтроку(стр);
ЗаписьТекста.Закрыть();
ЧтениеТекста = новый ЧтениеТекста(ИВФ);
стр = "";
Пока стр<>Неопределено Цикл
стр = ЧтениеТекста.ПрочитатьСтроку();
Если СтрНачинаетсяС(стр,"[Tsd test]") тогда
стр = "";
Пока стр<>Неопределено Цикл
стр = ЧтениеТекста.ПрочитатьСтроку();
Если стрСравнить(Лев(стр,стрДлина("Connect=File=")),"Connect=File=")=0 тогда
масСтр = СтрРазделить(стр,"/1cem/");
Если масСтр.Количество()>1 тогда
сткРез0 = РазобратьJSON(ВК.ФС_ПрочитатьКаталог(БазовыйКаталог + масСтр[1]));
Если сткРез0.Status тогда
сткРез1 = РазобратьJSON(сткРез0.Data);
Для каждого эстк из сткРез1 Цикл
Если эстк.Значение = ".." или эстк.Значение = "." тогда продолжить КонецЕсли;
П = БазовыйКаталог + масСтр[1] + ?(прав(БазовыйКаталог + масСтр[1],1)="/","","/")+эстк.Значение;
сткЭтоДиректорияСтатус = РазобратьJSON(ВК.ФС_ЭтоДиректория(П));
Если сткЭтоДиректорияСтатус.Status тогда
Если РазобратьJSON(сткЭтоДиректорияСтатус.Data).IsDirectory тогда
Р = УдалитьФсеФСОРекурсивно(П + "/ExtCompT",ВК);
Если ЗначениеЗаполнено(Р) тогда
Попытка
ВызватьИсключение "Не удалось зачистить кэш: "+Р;
исключение
Ош = ОписаниеОшибки();
//ДИАГНОСТИКА
КонецПопытки;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
Прервать;
КонецЕсли;
КонецЦикла;
прервать;
КонецЕсли;
КонецЦикла;
исключение
Ош = ОписаниеОшибки();
//ДИАГНОСТИКА -
КонецПопытки;
Попытка
УдалитьФайлы(ИВФ);
исключение
Ош = ОписаниеОшибки();
//ДИАГНОСТИКА - ошибка удаления ВФ
КонецПопытки;
КонецЕсли;
иначе
Попытка
ВызватьИсключение стк.Description;
исключение
Ош = ОписаниеОшибки();
//ДИАГНОСТИКА
КонецПопытки;
КонецЕсли;
//Ответ = ВК.ФС_ОбъектФССуществует("/data/data/com.e1c.mobile/files/1C/1cem/test");
//стк = РазобратьJSON(Ответ);
//КаталогСуществует = ложь;
//Если стк.Status тогда
// КаталогСуществует = истина;
//иначе
// Ответ = ВК.ФС_СоздатьКаталог("/data/data/com.e1c.mobile/files/1C/1cem/test", 511);
// стк = РазобратьJSON(Ответ);
// Если стк.Status тогда
// КаталогСуществует = истина;
// КонецЕсли;
//КонецЕсли;
//
//Если КаталогСуществует тогда
// Ответ = ВК.ФС_СоздатьФайл("/data/data/com.e1c.mobile/files/1C/1cem/test/test.txt");
// стк = РазобратьJSON(Ответ);
// Если стк.Status тогда
// Ответ = ВК.ФС_ЗаписатьДанныеВФайл("/data/data/com.e1c.mobile/files/1C/1cem/test/test.txt", ПолучитьДвоичныеДанныеИзСтроки("СтрокаДляДД"));
// стк = РазобратьJSON(Ответ);
// Если стк.Status тогда
// Ответ = ВК.ФС_ПрочитатьДанныеИзФайла("/data/data/com.e1c.mobile/files/1C/1cem/test/test.txt");
// Если ТипЗнч(Ответ) = тип("ДвоичныеДанные") тогда
// стр = ПолучитьСтрокуИзДвоичныхДанных(Ответ);
// КонецЕсли;
// КонецЕсли;
//
// Ответ = ВК.ФС_ПереименоватьФайлИлиКаталог("/data/data/com.e1c.mobile/files/1C/1cem/test/test.txt","/data/data/com.e1c.mobile/files/1C/1cem/test/test1.txt");
// стк = РазобратьJSON(Ответ);
// Если стк.Status тогда
// Ответ = ВК.ФС_УдалитьФайлИлиКаталог("/data/data/com.e1c.mobile/files/1C/1cem/test/test1.txt");
// стк = РазобратьJSON(Ответ);
// иначе
// Ответ = ВК.ФС_УдалитьФайлИлиКаталог("/data/data/com.e1c.mobile/files/1C/1cem/test/test.txt");
// стк = РазобратьJSON(Ответ);
// КонецЕсли;
// КонецЕсли;
//
// Ответ = ВК.ФС_УдалитьФайлИлиКаталог("/data/data/com.e1c.mobile/files/1C/1cem/test");
// стк = РазобратьJSON(Ответ);
//КонецЕсли;
//
//
////Для а = 0 по 10000 цикл
//
////Ответ = ВК.ФС_ЭтоДиректория("/data/data/com.e1c.mobile/files/1C/1cem");
////стк = РазобратьJSON(Ответ);
////Если стк.Status тогда
//// стк0 = РазобратьJSON(стк.Data);
//// //Для каждого эстк из стк0 цикл
//// //
//// //КонеЦЦикла;
////КонецЕсли;
////КонеЦЦИкла;
КонецПроцедуры
&НаКлиенте
Функция УдалитьФсеФСОРекурсивно(вхКаталог, ВК)
Если РазобратьJSON(ВК.ФС_ОбъектФССуществует(вхКаталог)).Status тогда
сткРез = РазобратьJSON(ВК.ФС_ПрочитатьКаталог(вхКаталог));
Если сткРез.Status тогда
сткРез0 = РазобратьJSON(сткРез.Data);
Для каждого эстк из сткРез0 Цикл
Если эстк.Значение = ".." или эстк.Значение = "." тогда продолжить КонецЕсли;
П = вхКаталог + ?(прав(вхКаталог,1)="/","","/")+эстк.Значение;
сткЭтоДиректорияСтатус = РазобратьJSON(ВК.ФС_ЭтоДиректория(П));
Если сткЭтоДиректорияСтатус.Status тогда
Если РазобратьJSON(сткЭтоДиректорияСтатус.Data).IsDirectory тогда
УдалитьФсеФСОРекурсивно(П, ВК);
КонецЕсли;
КонецЕсли;
ВК.ФС_УдалитьФайлИлиКаталог(П);
КонецЦикла;
КонецЕсли;
КонецЕсли;
ВК.ФС_УдалитьФайлИлиКаталог(?(прав(вхКаталог,1)="/", Лев(вхКаталог,стрДлина(вхКаталог)-1), вхКаталог));
КонецФункции
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//ОписаниеУстройства//
//Свойство компоненты - показывает производителя и модель устройства //
//---------------------------------------------------------------------------//
стрПроизводительИМодель = ВК.ОписаниеУстройства;
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//Запустить получение геоданных//
//---------------------------------------------------------------------------//
//1й параметр - получать данные от провайдера GPS,
//2й параметр - получать данные от провайдера NETWORKPROVIDER
//Данные от разных провайдеров приходят разными событиями
Р = ВК.ГЕО_НачатьПолучениеКоординат(истина, истина);
ВК.ГЕО_ОстановитьПолучениеКоординат();
//1й параметр - получать данные от провайдера GPS,
//2й параметр - получать данные от провайдера NETWORKPROVIDER
//Данные от разных провайдеров приходят разными событиями
Р = ВК.ГЕО_ПолучитьСейчас(истина, истина);
Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)
Если стрСравнить(СокрЛП(Источник),"Hermes") = 0 тогда
Если СтрСравнить(СокрЛП(Событие), "GEO_location") = 0 тогда
//Что-то сделать с геоданными...
КонецЕсли;
Возврат;
КонецЕсли;
КонецПроцедуры
//---------------------------------------------------------------------------//
Это JSON, который приходит во внешнем событии:
{
"data": "",
"description": "",
"object": [
{
"accuracy": 603.0,
"altitude": 0.0,
"latitude": 37.4218964,
"longitude": -122.0840582,
"provider": "NETWORK",
"speed": 0.0
}
],
"status": true
}
Работа с СУБД sqlite3.
При начале тестирования работы МП на мобильном фреймворке 1с столкнулись с извечной проблемой этой платформы - ОЧЕНЬ НИЗКОЙ ПРОИЗВОДИТЕЛЬНОСТЬЮ.
Когда таблицы содержат более 500к строк, то время поиска соответствующих просканированному штрихкоду данных доходит до 4х секунд. Вынос этих данных в СУБД sqlite3 + некоторые другие нехитрые манипуляции (в целях загрузки файла БД sqlite3 на устройство) решают эту проблему. Разницу в производительности не замеряли, но субъективно sqlite3 работает шустрее примерно на 2-3 порядка.
//---------------------------------------------------------------------------//
//СКЛт_ОткрытьСоединение//
//Открывает новое подключение к файлу БД //
//1й параметр - полный путь к файлу БД СУБД sqlite3 //
//---------------------------------------------------------------------------//
ИВФНазн = КаталогВременныхФайлов() + "test.db";
УдалитьФайлы(ИВФНазн);
джРез = ВК.СКЛт_ОткрытьСоединение(ИВФНазн);
сткРез = JSON.РазобратьJSON(джРез);
Если сткРез.status тогда
локИДСоединения = сткРез.data.conn_id;
КонецЕсли;
//---------------------------------------------------------------------------//
Ответ:
{
"Data" :
{
"conn_id" : 0
},
"Description" : "",
"Status" : true
}
//---------------------------------------------------------------------------//
//СКЛт_ПолучитьДеталиПоБД//
//Открывает новое подключение к файлу БД //
//1й параметр - ID подключения к БД //
//---------------------------------------------------------------------------//
ИВФНазн = КаталогВременныхФайлов() + "test.db";
УдалитьФайлы(ИВФНазн);
джРез = ВК.СКЛт_ОткрытьСоединение(ИВФНазн);
сткРез = JSON.РазобратьJSON(джРез);
Если сткРез.status тогда
локИДСоединения = сткРез.data.conn_id;
КонецЕсли;
джРез = ВК.СКЛт_ПолучитьДеталиПоБД(локИДСоединения);
//---------------------------------------------------------------------------//
Ответ:
{
"Data" :
{
"Size" : 12288
},
"Description" : "",
"Status" : true
}
//---------------------------------------------------------------------------//
//СКЛт_ВыполнитьСкрипт//
//Выполняет скрипт //
//1й параметр - ID подключения к БД //
//2й параметр - текст скрипта //
//---------------------------------------------------------------------------//
ИВФНазн = КаталогВременныхФайлов() + "test.db";
УдалитьФайлы(ИВФНазн);
джРез = ВК.СКЛт_ОткрытьСоединение(ИВФНазн);
сткРез = JSON.РазобратьJSON(джРез);
Если сткРез.status тогда
локИДСоединения = сткРез.data.conn_id;
КонецЕсли;
джРез = ВК.СКЛт_ПолучитьДеталиПоБД(локИДСоединения);
скриптCreate = "CREATE TABLE IF NOT EXISTS МАРКИ (Марка TEXT NOT NULL UNIQUE, DocDate TEXT, ID TEXT, PRIMARY KEY(Марка))";
джРез = ВК.СКЛт_ВыполнитьСкрипт(локИДСоединения,скриптCreate);
скриптИнсерт = "INSERT INTO МАРКИ (Марка, DocDate, ID)
|VALUES('102400137351161018001T3XIKZ5WR2MEEAXXWN2JKZBEBEZCB5ZVMFPUTVXHNMXPUJCWQJXYV3FTR2TOLGZ3CNTYMOKGL3XTWDYZUVHCHJ7ZPOFMZDHUABQ66GMELE4LGAEGNEV4A7AL199999',
|'20220122', '99999')";
джРез = ВК.СКЛт_ВыполнитьСкрипт(локИДСоединения,скриптИнсерт);
скриптСелект = "select * from МАРКИ where Марка like '%8001T3XIKZ5WR2MEEAXXWN2JKZBEBEZCB5ZVMFPUTVXHNMXPUJCWQJ%'";
джРез = ВК.СКЛт_ВыполнитьСкрипт(локИДСоединения,скриптСелект);
джРез = ВК.СКЛт_ЗакрытьСоединение(локИДСоединения);
УдалитьФайлы(ИВФНазн);
//---------------------------------------------------------------------------//
Ответ:
{
"Data" :
{
"rows" :
[
{
"DocDate" : "20220122",
"ID" : "99999",
"Марка" : "102400137351161018001T3XIKZ5WR2MEEAXXWN2JKZBEBEZCB5ZVMFPUTVXHNMXPUJCWQJXYV3FTR2TOLGZ3CNTYMOKGL3XTWDYZUVHCHJ7ZPOFMZDHUABQ66GMELE4LGAEGNEV4A7AL199999"
}
]
},
"Description" : "",
"Status" : true
}
Работа с smb (samba) протоколом.
В состав компоненты введен функционал по работе с "сетевыми каталогами Windows".
Что это такое.
https://ru.wikipedia.org/wiki/Server_Message_Block
Проще говоря: этот протокол используется для работы с сетевыми каталогами Windows.
Это может быть фильм на вашем компьютере, который вы смотрите с другого компьютера.
Это может быть файловая база данных 1с, расположенная на компьютере бухгалтера и к которой подключаются остальные пользователи - с других компьютеров.
Это может быть "обменный" каталог в офисе.
Это может быть общий сетевой принтер.
Для работы со всеми этими ресурсами сети используется smb-протокол.
В ОС Windows работа с smb визуально реализована как работа с обычными объектами файловой системы.
Зачем это нужно.
Это очень быстро настраваемый способ обмена данными между мобильным приложением на 1с и любым компьютером на базе ОС Windows, работающем в той-же локальной сети, что и мобильное устройство.
Не нужны ни HTTP, ни FTP сервера.
Достаточно просто опубликовать сетевой каталог на любом из компьютеров, положить в него текстовый файлик с данными и этот файлик "станет" доступен на мобильном устройстве -
как на любом другом компьютере в той-же локальной сети.
Технические условия.
Те-же самые, что и для получения доступа к сетевому каталогу с настольного компьютера.
1. Компьютер, на котором опубликован сетевой каталог, должен быть в зоне сетевой доступности ТСД (из wi-fi сети, к которой подключено мобильное устройство).
2. На компьютере с публикацией сетевого каталога, не должно быть запрета на работу с протоколом SMB.
3. Если опубликованный каталог виден с другого компьютера сети, то в общем случае, он должен быть виден и для ТСД.
Реализация.
Использована достаточно известная open-sorce библиотека https://github.com/sahlberg/libsmb2.
Как работает из 1с.
Взаимодействие с сетевыми каталогами из 1с немного отличается от взаимодействия с ними из ОС Windows.
Если в Windows для доступа в каталог надо в УРЛ-строке написать что-то вроде "\\MyHomeComputer\temp\какой-то каталог", то библиотека libsmb2 кушает URL строку вида smb://[<username>@]<host>[:<port>]/<share>/<path>
и "\\MyHomeComputer\temp\какой-то каталог" превратится в "smb://Ivanov@MyHomeComputer/temp/какой-то каталог"
Также, для успешного проникновения в недру сетевого каталога - каждый раз при подключении следует указывать пароль локального (или доменного) пользователя компьютера, на котором расшарен каталог.
Вдаваться в описание всех членов URL не буду - его можно нагуглить, а лучше приведу код из 1с:
&НаКлиенте
Процедура Самба_Каталог(Команда)
УстановитьВнешнююКомпоненту("ОбщийМакет.Hermes_gith");
Р = ПодключитьВнешнююКомпоненту("ОбщийМакет.Hermes_gith", "Test", ТипВнешнейКомпоненты.Native);
Гермес = Новый("AddIn.Test.Hermes");
//smb://[<username>@]<host.domain(домен не обязателен)>[:<port(не обязателен)>]/<share>/<path>
р = Гермес.SMB_ПрочитатьКаталог("smb://Ivanov@MyHomeComputer/temp/kp", пароль_пользователя_на_компьютере);
стк = JSON.РазобратьJSON(р);
В ответ приходит структура с массивом объектов в указанном сетевом каталоге
КонецПроцедуры
&НаКлиенте
Процедура Самба_ПолучитьФайл(Команда)
ДД = ПолучитьДвоичныеДанныеИзСтроки("1";);
Прочитано = -1;
Читать = 8388608;
Поз = 0;
ОбщийТекст = "";
ИВФ = ПолучитьИмяВременногоФайла("cf";);
Пока истина цикл
//smb://[<username>@]<host.domain(домен не обязателен)>[:<port(не обязателен)>]/<share>/<path>
р = Гермес.SMB_ПолучитьФайл("smb://username@host:445/temp/1cv8.cf", паруль, Читать, Поз, ДД);
стк = JSON.РазобратьJSON(р);
Если не стк.Status тогда
ПоказатьПредупреждение(,стк.Description);
Прервать;
КонецЕсли;
Прочитано = стк.Data.size;
Поток = ФайловыеПотоки.Открыть(ИВФ, РежимОткрытияФайла.Дописать);
Буф = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(ДД);
Поток.Записать(Буф,0,Буф.Размер);
Поток.СброситьБуферы();
Поток.Закрыть();
Поз = Поз + Прочитано;
Если Прочитано < Читать тогда прервать КонецЕсли;
КонецЦикла;
//Либо, если файлик не больше 8388608 байт, то его можно прочитать сразу весь - указав соответствующий РазмерБуффераДвоичныхДанных.
//Входной буфер двоичных данных (здесь - "ДД") при вызове функции SMB_ПолучитьФайл каждый раз переопределяется и заполняется полученными данными.
//Т.е. его размер при вызове функции - значения не имеет. По сути, это просто указатель.
КонецПроцедуры
&НаКлиенте
Процедура ЗаписатьФайл(Команда)
//стр = "арбадакарба";
//ДД = ПолучитьДвоичныеДанныеИзСтроки(стр);
Буф = Новый БуферДвоичныхДанных(8388608);
ДД = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(Буф);
//smb://[<username>@]<host.domain(домен не обязателен)>[:<port(не обязателен)>]/<share>/<path>
р = Гермес.SMB_ЗаписатьФайл("smb://username@host:445/temp/111.txt", паруль, ДД, 0); // создает файл и открывает для записи. Если файл существует, то обрезает в ноль и открывает для записи
р = Гермес.SMB_ЗаписатьФайл("smb://username@host:445/temp/111.txt", паруль, ДД, 1); // Открывает для записи и перемещает указатель в конец файла. (дозаписывает данные в конец файла).
стк1 = JSON.РазобратьJSON(р);
Сообщить(р);
КонецПроцедуры
Работа с regEx (используется встроенная в std библиотека (#include <regex>)).
&НаКлиенте
Процедура REX_match(Команда)
р = Гермес.REX_Совпадения("0104603744393009215!&WLVz93BwZ5z310300100070032212030600", "^01(?:0{1,6}(\d{8,13}))21(.{6,7})(?:93.{4})z?(?:3103(\d{6}))(?:17|7003)(\d{6,10})$");
Сообщить(р);
стк = JSON.РазобратьJSON(р);
КонецПроцедуры
&НаКлиенте
Процедура REX_replace(Команда)
р = Гермес.REX_Замена("0104603744393009215!&WLVz93BwZ5z310300100070032212030600", "^01(?:0{1,6}(\d{8,13}))21(.{6,7})(?:93.{4})z?(?:3103(\d{6}))(?:17|7003)(\d{6,10})$","[$1][$2][$3]");
Сообщить(р);
стк = JSON.РазобратьJSON(р);
КонецПроцедуры
QR-code генератор (используется com.github.kenglxn.QRGen:android:2.6.0).
&НаКлиенте
Процедура QRCodeGen(Команда)
стрДжей = Гермес.QR_Сгенерировать("Some people, when confronted with a problem, think
|""I know, I'll use regular expressions.""
|Now they have two problems... (https://en.cppreference.com/w/cpp/regex)", 250);
сткРез = JSON.РазобратьJSON(стрДжей);
Если не сткРез.Status тогда
Возврат;
КонецЕсли;
ЭтаФорма.КартинкаШтрихкод = ПоместитьВоВременноеХранилище(новый картинка(Base64Значение(сткРез.data)),ЭтаФорма.УникальныйИдентификатор);
КонецПроцедуры
JSON-валидатор.
Что это такое: https://otus.ru/journal/schema-json-i-comments-chto-nuzhno-znat/ (в разделе "JSON Schema") или даже лучше: https://habr.com/ru/post/495766/.
Где может потребоваться: в тех ситуациях, когда нет уверенности, что придет JSON с тем составом и форматом полей или коллекций, который ожидается. Например, когда информация получается от неопределенного круга источников или когда нет уверенности в источнике.
Короче, согласно https://json-schema.org/, benefits такие:
1.Describes your existing data format(s).
2. Provides clear human- and machine- readable documentation.
3. Validates data which is useful for:
3.1 Automated testing.
3.2 Ensuring quality of client submitted data.
Пример использования:
&НаКлиенте
Процедура JVD_validate(Команда)
Схема = "{
|""$id"": ""tsdGoodsPosting"",
|""description"": ""Данные о товаре, поступившем на точку в рамках маршрутного листа"",
|""type"": ""object"",
|""properties"": {
| ""ДатаДок"": {
| ""type"": ""string"",
| ""pattern"": ""^20\\d{6}$""
| },
| ""НомерДок"": {
| ""type"": ""string""
| },
| ""Товары"": {
| ""type"": ""array"",
| ""items"": {
| ""$ref"": ""#/definitions/good""
| }
| }
|},
|""definitions"": {
| ""good"": {
| ""type"": ""object"",
| ""required"": [
| ""Товар_КодНСИ"",
| ""ЕИ""
| ],
| ""properties"": {
| ""Товар_КодНСИ"": {
| ""type"": ""string"",
| ""description"": """"
| },
| ""ЕИ"": {
| ""type"": ""string"",
| ""description"": """"
| }
| }
| }
|}
|}";
ДанныеОк = "
|{
|""ДатаДок"": ""20221125"",
|""НомерДок"": ""005-00001315"",
|""Товары"": [
| {
| ""Товар_КодНСИ"": ""90000013"",
| ""ЕИ"": """"
| },
| {
| ""Товар_КодНСИ"": ""90012291"",
| ""ЕИ"": """"
| }
|]
|}";
стрДжей = Гермес.JVD_Проверить(Схема, ДанныеОк);
стк = JSON.РазобратьJSON(стрДжей);
ПоказатьПредупреждение(,стрДжей);
ДанныеНЕОк = "
|{
|""ДатаДок"": ""30221125"",
|""НомерДок"": ""005-00001315"",
|""Товары"": [
| {
| ""Товар_КодНСИ"": ""90000013"",
| ""ЕИ"": """"
| },
| {
| ""Товар_КодНСИ"": ""90012291""
| }
|]
|}";
стрДжей = Гермес.JVD_Проверить(Схема, ДанныеНЕОк);
стк = JSON.РазобратьJSON(стрДжей);
ПоказатьПредупреждение(,стрДжей);
КонецПроцедуры
ОТВЕТЫ:
1. {"Data":"","Description":["OK"],"Status":true}
2. {"Data":"","Description":["Отсутствует обязательное поле 'ЕИ'. Объект: <root> --> [Товары] --> [1]","Провалена валидация значения на соответствие выражению RegEx. Объект: <root> --> [ДатаДок]"],"Status":false}
ИМХО: технология огонь. В среде 1с, она не слишком известна и востребована. Однако, быстрая валидация json по схемам очень будет полезной при обмене через rest+json.
P.S.
Библиотеки jsoncpp и valijson переведены мной на русский язык в одно лицо, так-что прошу прощения, если где-то перевод не слишком точен.
P.P.S.
Вариант ВК для Винды: //infostart.ru/public/1786101/.
Исходники:
https://github.com/KotVezdehod/Hermes
https://github.com/KotVezdehod/dreamcatcher_gith
Частично использован код из //infostart.ru/1c/articles/987286/