Русский
Русский
English
Статистика
Реклама

Sdk

Перевод Flutter и настольные приложения

25.06.2020 12:16:27 | Автор: admin
Ни для кого не секрет то, что команда разработчиков Flutter стремится к тому, чтобы этот фреймворк позволял бы, пользуясь единой кодовой базой, создавать приложения для широкого разнообразия платформ. Сюда входят iOS, Android, Windows, Linux, macOS и веб. При этом такие приложения должны компилироваться в формат, специфичный для каждой из платформ, а их внешний вид не должен уступать внешнему виду хорошо сделанных игр. В Google фреймворк Flutter применяется во многих проектах: от Assistant до Stadia, от Cloud Search до Blogger. Flutter используются и другими компаниями от ByteDance до Grab, от Nubank до MGM Resorts. Всем им приносит пользу та гибкость и продуктивность разработки, которую даёт Flutter.

Многие из вас заинтересованы в развитии возможностей Flutter, касающихся настольных платформ, куда входят Windows, macOS, Linux. В опросах и на GitHub тема разработки настольных приложений относится к одной из самых заметных новых возможностей Flutter. В ближайшее время мы собираемся больше рассказать о том, чем мы занимаемся. Полагаем, стоит начать с обзора того, что сделано различными командами, отвечающими за возможности Flutter. Хотя поддержка настольных приложений пока находится на стадии ознакомительной технической версии, над соответствующими возможностями ведётся серьёзная работа.


Сборка приложений


Недавно мы выпустили профили и режимы сборки приложений для Windows и Linux в дополнение к существующей поддержке macOS. Например, если вы пользуетесь последней сборкой Flutter, Flutter-приложения можно компилировать в исполняемые файлы Windows командой flutter build windows. Для этого используется наш AOT-компилятор продакшн-уровня, который позволяет создавать машинный код для архитектуры x64, который можно выполнять на соответствующих компьютерах без установки Flutter.

Особенности настольных приложений


Разрабатываете ли вы приложение, представленное самостоятельным исполняемым файлом, или веб-приложение, у настольных приложений есть некоторые специфические возможности и особенности. Например, окна настольных приложений обычно выводятся в ландшафтном режиме, а их размер можно менять. Пользователи обычно вводят данные в приложения, применяя клавиатуру и мышь, а не экранные клавиатуры и сенсорный ввод. Элементы управления оптимизированы с учётом того, что в настольных приложениях при размещении элементов управления используются особые значения визуальной плотности.

Мы, на уровне фреймворка, внесли во Flutter некоторые изменения, которые направлены на поддержку настольных приложений.

  • Когда вы создаёте новый проект в свежих сборках Flutter, вы увидите, что шаблон, применяемый по умолчанию, теперь включает в себя ссылку на свойство visualDensity, которое позволяет настраивать визуальную плотность расположения элементов управления на основе целевой платформы приложения. В макетах настольных приложений элементы управления упакованы плотнее, чем в мобильных приложениях. Например, это используется при настройке текстового поля (TextField), которое теперь предлагает варианты визуальной плотности compact, comfortable и standard, зависящие от параметров проекта.
  • Мы значительно улучшили поддержку мыши и клавиатуры. Сюда входит возможность работы с кодами клавиш клавиатуры в Windows, поддержка щелчка правой кнопкой мыши, поддержка изменения курсора и колёсика мыши.
  • Теперь можно, пользуясь классом Platform, узнавать о том, на какой платформе выполняется приложение. При работе приложения а Windows, macOS и Linux можно получить соответствующие результаты.
  • В самом свежем релизе мы добавили виджет NavigationRail, представляющий нечто вроде боковой панели. Этот виджет специально спроектирован для поддержки возможностей приложений, запускаемых на настольных ПК и на планшетах.

FFI


Команда Dart проделала большую работу по улучшению интерфейса внешних функций (Foreign Function Interface, FFI). Это способствует повышению скорости внедрения новых возможностей во Flutter. Например, для API, основанных на C, библиотека dart:ffi предоставляет прямой механизм для организации привязки к нативному коду. Среда выполнения Dart даёт возможность вызывать динамически связываемые библиотеки и выделять память в куче. В основе этого механизма лежат объекты Dart.

Вот фрагмент кода (здесь можно найти его полный вариант), представляющий собой простой пример, в котором показано обращение к традиционному Win32-API MessageBox(), полностью выполняемое средствами Dart-кода:

typedef MessageBoxNative = Int32 Function(IntPtr hWnd, Pointer<Utf16> lpText, Pointer<Utf16> lpCaption, Int32 uType);typedef MessageBoxDart = int Function(int hWnd, Pointer<Utf16> lpText, Pointer<Utf16> lpCaption, int uType);final user32 = DynamicLibrary.open('user32.dll');final win32MessageBox =user32.lookupFunction<MessageBoxNative, MessageBoxDart>('MessageBoxW');void showMessageBox(String message, String caption) => win32MessageBox(0,           // Нет окна-владельцаUtf16.toUtf16(message), // Текст сообщенияUtf16.toUtf16(caption), // Заголовок окна0            // Только кнопка OK);showMessageBox('Test Message', 'Window Caption'); // этот вызов выглядит как вызов обычной Dart-функции

Здесь у нас имеются typedef-псевдонимы, представляющие сигнатуры методов и для их нативного представления, и для их Dart-представления. Когда у нас есть эти псевдонимы, мы можем загрузить динамически связываемую библиотеку Windows, которая содержит реализацию функции. Для этого можно воспользоваться методом lookupFunction(), который делает мэппинг сигнатуры функции Dart на нативную функцию. И, наконец, мы, что не обязательно, описываем простую функциональную обёртку, которая упрощает работу с нативными механизмами в Dart-коде. В результате у нас получается нечто, подобное следующему рисунку.


Простой пример Windows-проекта, в котором использовано Win32-API MessageBox()

На самом деле, программисту необязательно делать всё это самому. Дело в том, что велика вероятность того, что кто-то уже подготовил код, упрощающий работу с необходимыми вам API. Здесь о FFI можно почитать подробнее.

Обновление модели плагинов


Flutter спроектирован с учётом того, чтобы у него было бы компактное ядро. Для оснащения фреймворка дополнительными возможностями соответствующий функционал оформляется в виде подключаемых плагинов и пакетов, дающих возможность интеграции с операционными системами, на которых работает Flutter. Плагины и пакеты могут создавать не только разработчики Flutter, но и другие программисты.

Правда, учитывая то, что во Flutter улучшается поддержка мобильных и настольных платформ, а так же веб-приложений, разрабатывать плагины для каждой поддерживаемой фреймворком платформы становится всё сложнее и сложнее. При разработке некоего плагина, весьма вероятно, понадобится объединить усилия разных программистов, каждый из которых хорошо разбирается в какой-то платформе.

Здесь нам на помощь может прийти подход, в соответствии с которым некий базовый плагин описывает общий интерфейс, который может быть независимо реализован на разных платформах. В результате, как было описано в свежем материале про современную разработку плагинов, мы недавно внедрили во Flutter систему, которая упрощает совместную работу различных авторов над плагинами. Благодаря этой системе уже можно в явном виде указывать то, какие именно платформы поддерживаются конкретным плагином.

Мы начали использовать эту модель при работе над некоторыми базовыми плагинами. Примеры нового подхода к совместной разработке плагинов можно найти здесь.

Обратите внимание на то, что API плагинов для Windows и Linux пока ещё не устоялся, поэтому, хотя мы и советуем разработчикам знакомиться с новыми возможностями Flutter, мы пока не готовы к выпуску этих возможностей в продакшн. Мы, кроме того, работаем над добавлением на pub.dev тегов, относящихся к настольным платформам.

Запуск программ на Windows: Win32 и UWP


Один интересный аспект нашей работы, связанный с Windows, заключается в том, что здесь мы экспериментируем с различными подходами к архитектуре. Flutter, на любой платформе, внедряется в маленькое хост-приложение, являющееся контейнером (embedder) с применением подхода, напоминающего тот, который используется в игровых движках вроде Unity. Это приложение-embedder, особое для каждой платформы, предоставляет нам точку входа в проект. Оно согласовывает свои действия с операционной системой, работая со средствами рендеринга, с пользовательским вводом и с инструментами, обеспечивающими доступность контента. Оно поддерживает и цикл событий.


Windows даёт нам два способа создания подобного приложения. Первый это зрелая модель программирования Win32, которую можно использовать в качестве точки входа для Flutter-проектов. Этот подход предлагает максимальный уровень обратной совместимости с различными платформами, с такими, как Windows 7. Он позволяет создавать стандартные EXE-файлы, которые ожидает получить в результате работы над проектом множество программистов. В отличие от Win32, современная модель приложений UWP рекомендована для Windows 10. Эта модель предлагает заманчивые возможности по созданию Flutter-приложений для особых устройств, вроде Xbox, и для ОС Windows 10X, которая должна скоро выйти.

Мы, неофициально, работаем с различными разработчиками и исследуем разные решения. Мы с удовольствием более близко поработали бы с Microsoft ради того, чтобы повысить качество Windows-приложений, сделанных во Flutter. Так как семейство устройств Surface теперь включает в себя системы, основанные на Android и на Windows, мы думаем, что Flutter способен предложить Microsoft мощную платформу, которая позволяет создавать привлекательные нативные приложения для самых разных устройств.

Эксперименты с настольными приложениями


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

Если вы уже сейчас хотите испытать новые возможности, то вам нужно пользоваться каналом разработки. Поддержка Windows и Linux доступна в ветке master, в том месте, где идёт активная разработка Flutter. Поддержка macOS доступна в ветке dev. Там находятся более стабильные возможности, которые, правда, не рекомендуется применять в продакшне. Переключаться между каналами можно, используя команды flutter channel master или flutter channel dev. После этого нужно выполнить одну из следующих команд для того чтобы включить поддержку интересующей вас платформы:

C:\flutter> flutter config --enable-windows-desktop$ flutter config --enable-macos-desktop$ flutter config --enable-linux-desktop

Мы уже видели, как некоторые смелые разработчики начали создавать настольные приложения с помощью новых возможностей Flutter. Одно из первых таких приложений разработано для macOS. Оно называется Sharezone. Это планировщик для учеников, нацеленный на немецкий рынок образования. Сначала этот проект был выпущен в виде мобильного приложения. А недавно он вышел в настольном варианте и в варианте, предназначенном для веб.


Sharezone Schulplan приложение для учеников, учителей и родителей. Оно позволяет планировать и отслеживать домашние задания, учебные группы и расписания

Планируете ли вы использовать Flutter для разработки настольных приложений?



Подробнее..

МойОфис представил общедоступные веб-редакторы. Теперь ознакомиться с продуктами компании можно прямо в окне браузера

07.04.2021 12:05:29 | Автор: admin

МойОфис запустил открытый сервис, где любой желающий может поработать с текстовыми и табличными документами, а также оценить интерфейс, ключевые функциональные возможности и практическое удобство наших редакторов. Без скачивания каких-либо файлов, регистрации и установки браузерных расширений: для запуска демонстрационной версии веб-редакторов достаточно перейти по ссылке в браузере на вашем ПК или ноутбуке. В процессе работы с сервисом все документы остаются на компьютерах пользователей.


Привет, Хабр! В новом релизе 2021.01 мы провели комплексную работу над оптимизацией линейки продуктов МойОфис. Часть наиболее любопытных изменений коснулась технологии автономного модуля редактирования (АМР). Для иллюстрации возможностей AMP мы интегрировали модуль в корпоративный сайт МойОфис, и теперь работа с текстовым и табличным редакторами доступна всем посетителям сайта прямо из окна их браузера.

Если вашим ИТ-системам необходимы инструменты редактирования документов, вы можете запросить комплект средств для разработчиков, который позволит интегрировать АМР в собственные решения. Статус технологического партнера МойОфис откроет вам доступ к библиотеке справочных материалов по нашим продуктам и ускорит вашу разработку.

Что такое АМР?

АМР специальная версия редакторов МойОфис, которая разработана для веб-сервисов и интеграции в приложения сторонних разработчиков для работы с документами.

AMP не требует отдельного сервера и содержит полный набор средств редактирования и форматирования, при этом не имеет функций совместной работы.

Редактор в АМР обрабатывает только те файлы, которые передает ему информационная система приложение или сервис, куда интегрирован сам модуль АМР.

Что умеют веб-редакторы МойОфис на базе AMP?

Пользователям пробной версии веб-редакторов МойОфис доступно создание, открытие, редактирования и форматирования текстовых и табличных файлов. При этом можно вставлять изображения (а также копировать изображения в буфер обмена и вставлять их в другие приложения), таблицы, оглавление и колонтитулы в тексты, использовать формулы и строить графики в электронных таблицах.

Сохранение файлов осуществляется в форматах ODT, ODS, DOCX, XLSX, PDF.

В интерфейсе доступны режим рецензирования и работа с файлами в режиме правок. В зависимости от настройки информационной системы, в которую интегрирован АМР, открытие документа может происходить в режиме постоянного рецензирования без возможности его отключения. (Пример: система, в которую встроен АМР, управляет режимом работы с документом и выдает права принимать или отклонять исправления отдельным пользователям системы). Все правки и комментарии, которые будут оставлены в документе в режиме рецензирования, сохранятся в документе.

Печать документов осуществляется с помощью средств браузера и доступна прямо из интерфейса AMP. Для табличных документов реализована возможность предварительной настройки параметров печати размера и ориентации страницы, масштаба и области печати, ширины полей, а также отключение печати пустых страниц.

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

Предлагаем читателям блога МойОфис ознакомиться с веб-редакторами и поделиться мнением в комментариях, а разработчикам программных продуктов оценить возможности интеграции АМР в свои ИТ-решения и стать технологическими партнерами. Будем рады вашей обратной связи по новому сервису!

Подробнее..

Из песочницы Как Kotlin Multiplatform помогает сократить время разработки приложений

30.10.2020 20:07:38 | Автор: admin
Привет, Хабр! Представляем вашему вниманию перевод статьи How Kotlin Multiplatform helps reduce app development time.

Kotlin Multiplatform может сократить время разработки на 30 процентов об этом написали статью наши коллеги из компании Archer Software. Они подробно разобрали проблемы, которые возникают в процессе работы, и то, может ли кроссплатформенная технология их решить. Мы считаем, что материал нужный и полезный, поэтому публикуем в бло перевод.




Из этой статьи вы узнаете


  1. Какие проблемы возникают, когда над приложением работают несколько команд
  2. Может ли кроссплатформенная технология решить эти проблемы
  3. Чем хорош Kotlin Multiplatform при разработке кроссплатформенных приложений
  4. Недостатки Kotlin Multiplatform
  5. Заключение

Если учесть, что в мире ежегодно появляется 100 миллионов стартапов, то время вывода продукта на рынок теперь намного важнее стоимости. Пользователи становятся все требовательнее, поэтому разработчикам лучше выбирать нативные решения.


Однако приложение сразу под три платформы: Android, iOS и десктоп обойдется клиенту в три раза дороже. Но можно пойти другим путем и создать универсальный код, который работает одинаково на всех платформах.


Какие проблемы возникают, когда над приложением работают несколько команд


Как правило, при разработке мультиплатформенных нативных приложений несколько команд работают независимо друг от друга. Конечно, им нужно общаться и обмениваться результатами, но в процессе координации возникает ряд проблем.


Разные решения одних и тех же задач


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


Трудности коммуникации


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


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


Специфические особенности платформ


Каждая из операционных систем предъявляет свои требования к качеству продукта, в особенности к пользовательскому интерфейсу, который должен максимально соответствовать конструкции устройств, использующих эту ОС.


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


Взаимозаменяемость разработчиков


В идеале код должен быть настолько понятным, чтобы любой специалист, владеющий определенным языком программирования, мог разобраться, как он работает.


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


Может ли кроссплатформенная технология решить эти проблемы


Процесс разработки нужно как-то синхронизировать. Кажется, что единственный выход использовать одну кроссплатформенную технологию, которая способна хранить и применять код для различных операционных систем. Однако все не так радужно, как хотелось бы.


Недостатки кроссплатформенных решений:


  • трудно получить доступ к API системы;
  • обновления запаздывают;
  • нет возможности работать с устаревшим кодом;
  • большинство кроссплатформенных комплектов для разработки (SDK) доступны только в бета-версии или на экспериментальной стадии;
  • одинаковый вид приложения на всех платформах может испортить впечатление пользователя.

Чем хорош Kotlin Multiplatform при разработке кроссплатформенных приложений


Эти недостатки не настолько критичны, если знать, как с ними справляться. Чтобы ускорить разработку и облегчить взаимодействие между отдельными командами, наша компания использует Kotlin.


Что такое Kotlin Multiplatform? Это язык программирования с открытым исходным кодом, позволяющий создавать максимально чистый код. С ним не нужно делать одну и ту же работу дважды. Например, если мы создаем приложение для Android и iOS, мы можем частично использовать один и тот же код.


Как работает Kotlin Multiplatform


Kotlin для Android, iOS и других популярных операционных систем хранит фрагменты кода, которые можно использовать для двух и более версий приложения. На Kotlin мы пишем общий код, а затем компилируем его в нативные фреймворки с ссылкой на нативные Android и iOS проекты.


Функции, которые неэффективно кодить с помощью Kotlin, можно прописать в нативной среде. Так ниже риск разработки двух или более решений для разных платформ. И это не единственное преимущество.


Основные преимущества Kotlin Multiplatform


Значительная экономия денег и времени. Разработчики при работе на Kotlin экономят 3050% рабочего времени. Поэтому экономит и клиент: разработчикам не надо платить за то, что они воспроизводят один и тот же код несколько раз.


Меньше ошибок. Kotlin позволяет создавать максимально чистый код. Однако, если ошибки все-таки закрались, их можно найти и исправить до начала исполнения. Это экономит время и деньги в процессе тестирования и контроля качества (QA).


Эффективная работа в команде. Kotlin помогает командам программистов взаимодействовать и фокусироваться на приоритетных задачах. Более того, он позволяет распределять задачи между разработчиками. Например, команда Android может работать над реализацией регистрации (user signup flow), а команда iOS созданием поста (post create flow). На следующем этапе команда Android может использовать код, написанный командой iOS, и наоборот.


Практически нативное решение. Код Kotlin очень похож на Swift и на 100% совместим с Java.


Недостатки Kotlin Multiplatform


Несмотря на все плюсы, есть также минусы, которые следует учитывать, принимая решение в пользу языка программирования Kotlin.


Нужно время на обучение


Разработчики часто спрашивают, как можно бесплатно изучить Kotlin или сколько времени на это нужно. Изучать основы вы можете бесплатно. Если владеете Java, вам потребуется меньше времени, чтобы их освоить.


Тем не менее, не стоит ждать, что ваша команда разработчиков переключится на Kotlin через несколько часов. Переход потребует дополнительного времени и затрат на обучение.


Так что лучше: Kotlin или Java? Это зависит от цели, которую вы хотите достичь.


Нехватка разработчиков-экспертов


Конечно, для решения конкретных задач лучше нанимать программистов с опытом разработки на Kotlin Multiplatform. Но найти им замену нелегко, потому что технология не так широко распространена, как нативные языки программирования.


Заключение


Если вам нужно приложение для двух платформ и веб-версия, обращайтесь к экспертам по Kotlin, это беспроигрышный вариант. Мы в компании IceRock Development, как и наши коллеги в Archer Software, знаем, насколько он эффективен.


Наша компания делает заметный вклад в развитие технологии Kotlin Multiplatform:



Приходите к нам, и мы покажем, как Kotlin Multiplatform может быть полезен вашему бизнесу!

Подробнее..

А я говорю, возьми Excel и позвони

01.04.2021 14:11:52 | Автор: admin

Voximplant, как и любая облачная платформа, предоставляет API, с помощью которого можно управлять пользователями, запускать звонки, просматривать их историю и логи и делать немало других полезных вещей. В принципе, практически всё, что можно настроить в панели управления, можно сделать и через API.

Но в современном мире иметь API недостаточно мало кто хочет формировать HTTP-запросы, передавать параметры, думать про правильную авторизацию. Поэтому мы предлагаем SDK для разных языков программирования: Python, PHP, C# и многих других. И кажется, что этого достаточно, чтобы сделать нашу платформу лёгкой в использовании для очень большой аудитории. Или всё-таки недостаточно?

Обратимся к статистике. По разным данным сейчас в мире насчитывается где-то 15-30 миллионов разработчиков цифра несомненно впечатляющая. Но, например, пользователей MS Excel в мире не менее 100 миллионов. Почему же они должны страдать? Ведь, будем честны, почти каждый из тех, кто хоть раз открывал Excel, явно ощущал недостаток возможностей по управлению коммуникационными платформами в этом без сомнения очень гибком программном продукте. Практически каждый день мы получаем на наш email сотни запросов, которые сводятся к очень простой просьбе: Я хочу звонить из Excel!. Однажды у окон нашего офиса даже выстроились люди с такими требованиями (видели фото выше?) Мы просто не могли оставаться в стороне.

Однако звонки это всё-таки слишком революционно, а главное, потребует установки дополнительных ActiveX-компонентов, что, безусловно, противоречит всем существующим и несуществующим политикам информационной безопасности, поэтому давайте начнём с более простой вещи SDK для работы с нашим API. Из средств разработки в Экселе доступен VBA, для него мы и создадим SDK.

Для того, чтобы выполнить API-запрос, необходимо:

  1. Сформировать URL и тело POST-запроса.

  2. Добавить аутентификационные параметры.

  3. Непосредственно выполнить запрос.

  4. Распарсить результат (в нашем случае это JSON).

Формируем URL и тело POST-запроса

Первая часть, казалось бы, самая простая: нужно просто закодировать параметры в URL-кодировку и склеить их. Но в стандартом VBA не предусмотрена URL-кодировка (позже мы поймём, почему). Ничего страшного, на просторах Интернета есть множество разных решений, выберем одно из них.

Public Function URL_Encode(ByRef txt As String) As String    Dim buffer As String, i As Long, c As Long, n As Long    buffer = String$(Len(txt) * 12, "%")     For i = 1 To Len(txt)        c = AscW(Mid$(txt, i, 1)) And 65535         Select Case c            Case 48 To 57, 65 To 90, 97 To 122, 45, 46, 95  ' Unescaped 0-9A-Za-z-._ '                n = n + 1                Mid$(buffer, n) = ChrW(c)            Case Is <= 127            ' Escaped UTF-8 1 bytes U+0000 to U+007F '                n = n + 3                Mid$(buffer, n - 1) = Right$(Hex$(256 + c), 2)            Case Is <= 2047           ' Escaped UTF-8 2 bytes U+0080 to U+07FF '                n = n + 6                Mid$(buffer, n - 4) = Hex$(192 + (c \ 64))                Mid$(buffer, n - 1) = Hex$(128 + (c Mod 64))            Case 55296 To 57343       ' Escaped UTF-8 4 bytes U+010000 to U+10FFFF '                i = i + 1                c = 65536 + (c Mod 1024) * 1024 + (AscW(Mid$(txt, i, 1)) And 1023)                n = n + 12                Mid$(buffer, n - 10) = Hex$(240 + (c \ 262144))                Mid$(buffer, n - 7) = Hex$(128 + ((c \ 4096) Mod 64))                Mid$(buffer, n - 4) = Hex$(128 + ((c \ 64) Mod 64))                Mid$(buffer, n - 1) = Hex$(128 + (c Mod 64))            Case Else                 ' Escaped UTF-8 3 bytes U+0800 to U+FFFF '                n = n + 9                Mid$(buffer, n - 7) = Hex$(224 + (c \ 4096))                Mid$(buffer, n - 4) = Hex$(128 + ((c \ 64) Mod 64))                Mid$(buffer, n - 1) = Hex$(128 + (c Mod 64))        End Select    Next    URL_Encode = Left$(buffer, n)End Function

Следующий нюанс передача даты и времени. В API Voximplant временные метки принимаются в UTC в формате YYYY-MM-DD hh:mm:ss. В Excel же дата и время хранятся без учёта часового пояса (на самом деле, в самой таблице они вообще хранятся как число с плавающей точкой). Поэтому нам придётся принимать дату/время из таблицы тоже UTC. Мы думаем, что все 100+ миллионов пользователей Excel знают, что такое UTC, и это не вызовет у них никаких вопросов.

Кстати, в VBA есть функция форматирования даты, и она даже работает, но весьма необычным образом. Интересующий нас формат даты описывается так: yyyy-mm-dd hh:mm:ss. То есть mm это либо месяц, либо минуты в зависимости от того, за чем оно следует: за hhили за yyyy (это не шутка, это даже в MSDN описано). В общем, если кто-то захочет вывести время без часов, придётся импровизировать.

Переходим к аутентификации

Здесь нас ожидает самое большое разочарование. Мы в Voximplant предлагаем нашим клиентам использовать JWT, что, конечно, весьма мудрёно, если выполнять запросы из консоли или браузера, но при использовании наших SDK это совершенно никак не усложняет жизнь разработчику. В то же время JWT обеспечивает крайне высокий уровень безопасности.

А что же VBA? К сожалению, разумно простого способа сформировать JWT-подпись просто не существует. Причина в том, что в VBA доступен фреймворк .NET версии 4.x, а функция RSA.ImportPkcs8PrivateKey, необходимая для загрузки приватного ключа из PKCS8, появилась только в .NET 5. Да и вообще, все .NET-разработчики используют для таких задач сторонние библиотеки.

Поэтому нам придётся ограничиться авторизацией с помощью статического API-ключа. Ведь, как известно, один из способов обработки риска информационной безопасности - принятие этого риска. Так и поступим. Ведь нам ну очень-очень нужен этот SDK.

Кадр из кинофильма Большой Лебовски (The Big Lebowski (1998), Polygram Filmed Entertainment, Working Title Films)Кадр из кинофильма Большой Лебовски (The Big Lebowski (1998), Polygram Filmed Entertainment, Working Title Films)

Выполняем запрос

Переходим к третьей части к выполнению самого запроса. Встроенных средств работы с HTTP в VBA нет (теперь понятно, почему нет и функции URL-кодирования, а зачем?).

Но, тем не менее, это достаточно тривиальная манипуляция подключаем необходимый фреймворк MSXML 6.0 и Microsoft Scripting Runtime и выполняем запрос, подключая через COM сам MSXML. Просто!

Function makeRequest(name As String, params As Dictionary, accountId As Integer, apiKey As String) As Object    Dim objHTTP As New MSXML2.XMLHTTP60    Dim jsonData As String    Dim parsedJson As Object    Dim postString As String    postString = ""        Dim iterKey As Variant        For Each iterKey In params.Keys        postString = postString & "&" & iterKey & "=" & URL_Encode(params(iterKey))    Next    Url = "https://api.voximplant.com/platform_api/" + name    objHTTP.Open "POST", Url, False    objHTTP.send "account_id=" & accountId & "&api_key=" & apiKey & postString    jsonData = objHTTP.responseText    Set parsedJson = JsonConverter.ParseJson(jsonData)    Set makeRequest = parsedJsonEnd Function

Парсим JSON

Ну и, наконец, JSON. Как и всё остальное, парсер JSON надо искать где-то вовне экосистемы VBA. К счастью, на дворе 2021 год, есть GitHub, и кто-то уже озадачился созданием JSON-парсера для VBA. Мы взяли вот такой.

Он подключается как отдельный модуль и превращает JSON-строку в Dictionary. То, что нужно!

Дальше берём генератор одного из наших SDK (мы взяли питоновский), заменяем шаблоны и заставляем его генерировать код на VBA. В итоге получаем готовый SDK, который можно скачать на нашем GitHub.

SDK представляет собой Class Module, который можно подключить к вашей любимой книге в Excel и делать с его помощью разные странные вещи. В принципе, можно даже звонки запускать, SDK поддерживает все необходимые для этого функции API в). Но это будет не лучшей идеей, учитывая, что не до конца известно, когда Excel решит пересчитать все формулы (именно в этот момент произойдёт вызов функции API).

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

Для этого пишем вот такую функцию:

Function getTotalCallCost(FromDate, ToDate, Username) As Double    Dim totalCost As Double    Dim lastCount As Integer    Dim offset As Integer    Dim res As Dictionary    Dim RecordsPerRequest As Integer    Dim api As New VoximplantAPI    totalCost = 0    lastCount = 1    offset = 0    RecordsPerRequest = 100        'Pass Voximplant account id and API key    api.SetCredentials 100, "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"        Do While lastCount > 0        Set res = api.GetCallHistory(FromDate, ToDate, remote_number:=Username, with_calls:=True, with_records:=True, with_other_resources:=True, offset:=offset, count:=RecordsPerRequest)                Dim session As Variant        Dim item As Variant                For Each session In res("result")            For Each item In session("calls")                totalCost = totalCost + item("cost")            Next            For Each item In session("records")                totalCost = totalCost + item("cost")            Next            For Each item In session("other_resource_usage")                totalCost = totalCost + item("cost")            Next        Next                lastCount = res("count")        offset = offset + RecordsPerRequest    Loop        getTotalCallCost = totalCostEnd Function

И вызываем её следующим образом:

А потянув мышкой за правый нижний угол активной ячейки, мы можем применить эту формулу ко всем интересующим нас пользователям и узнать, кто из них звонил двоюродной сестре в Монако больше других.


Резюме:

При желании можно и для VBA сделать какое-то подобие SDK. При его создании не пострадал ни один разработчик. Ах да, с 1 апреля! :D

Подробнее..

IDA Pro каким не должен быть SDK

05.07.2020 22:23:42 | Автор: admin

Приветствую,



Эта статья будет о том, как не нужно делать, когда разрабатываешь SDK для своего продукта. А примером, можно даже сказать, самым ярким, будет IDA Pro. Те, кто хоть раз что-то разрабатывал под неё и старался поддерживать, при чтении этих строк, наверняка, сейчас вздрогнули и покрылись холодным потом. Здесь я собрал опыт сопровождения проектов, начиная с IDA v6.5, и заканчивая последней на момент написания статьи версии v7.5. В общем, погнали.


Краткое описание


SDK для IDA Pro позволяет вам разрабатывать следующие типы приложений:


  • Загрузчики различных форматов
  • Процессорные модули
  • Плагины, расширяющие функционал (процессорных модулей, интерфейса и т.п.)
  • IDC-скрипты (свой внутренний язык) и Python-скрипты (вторые использует стороннюю разработку IDAPython, которая стала неотъемлемой частью IDA)

По информации с сайта Hex-Rays, стоимость плана поддержки SDK 10000 USD. На практике же если у вас есть лицензия, вам даётся код доступа к Support-зоне, в которой вы его скачиваете и работаете с ним. Стоимость же указана на тот случай, если у вас будут появляться вопросы и вы захотите задать их разработчикам: без плана поддержки вам скажут, мол, напишите это сами; с поддержкой же, как я понимаю, отказать вам не могут. К сожалению, я не знаю ни одного человека (фирмы), который купил данный план.


Немного подробнее


С того момента, как у вас появляется желание написать что-то под IDA, и вы скачиваете SDK, вы ступаете на достаточно скользкую дорожку, на которой, к тому же, очень легко сойти с ума. И вот почему:


1) В современной разработке вы, скорее всего, уже привыкли к тому, что у любого более-менее серьёзного проекта есть либо doxygen-сгенерированная справка по API, либо вручную написанная хорошая справка, которая вам говорит что куда передаётся, что нужно заполнять, чтобы работало, и т.п., с кучей примеров.
В IDA практически в большинстве доступных пользователю API указаны лишь имена параметров и их типы, а что туда передавать можно отгадывать лишь по именам аргументов. В последнее время, конечно, со справкой у IDA стало получше, но не то что бы значительно.


2) Во многих заполняемых структурах требуется задавать callback-функции, при этом некоторые указаны как необязательные, мол, не укажешь (передашь NULL) и ладно. В действительности крэши приложения при попытке запуска вашего плагина. И, т.к. колбэков много (пример плагин-отладчик), ты начинаешь поочерёдно задавать все, которые "можно не задавать". В итоге это очень сильно утомляет, ты открываешь x64dbg/ollyDbg, в нём idaq.exe/ida.exe, грузишь плагин, ставишь точки остановки, и пытаешься словить момент, когда управление передаётся в 0x00000000.


Эх, помню те времена, когда так много папок с проектами были забиты 200MB dmp-файлами, которые создавались при крэше IDA Но мне они ничем не помогали.


3) Самая болезненная тема для IDA Pro обратная совместимость. В принципе, это достаточно тяжёлая для любого разработчика задача наперёд продумывать интерфейсы, структуры, модульность и т.п. Поэтому здесь и возникает два пути:


  • Хранить обратную совместимость со всеми старыми версиями
  • Не заниматься обратной совместимостью

В первом случае очень быстро накапливается legacy-код, от которого потом становится невозможно избавиться. Вычистить его редко кому удаётся. Потому как, фактически, нужно бросать все силы не на разработку нового функционала, а на выпиливание/перенос старого.


Во втором случае у нас не стоит проблемы обратной совместимости, но возникает другая: т.к. у нас имеется публично доступный SDK, требуется регулярно следить за тем, какие изменения происходят, и документировать их, чтобы все те, кто начал разработку под предыдущую версию, могли безболезненно перейти на новую.


Что же в случае Hex-Rays? Вы удивитесь, но они пошли двумя путями одновременно! Известно, что проект развивается с очень и очень бородатых времён, когда основной целевой платформой был лишь MS-DOS (и, следовательно, реверс-инжиниринг написанных под него приложений). Нужно было поддерживать сегментные регистры, селекторы, параграфы и другую подобную атрибутику. Шло время, в IDA начали появляться другие платформы, процессорные модули и загрузчики, где модель памяти уже была плоской (flat), но пережиток в виде перечисленных мной MS-DOS "фич" сохраняется до сих пор! Весь интерфейс IDA пронизан этим. При разработке процессорных модулей, в который только flat, вам всё равно придётся указываться сегментные регистры (правда уже виртуальные).


А вот с SDK ни о какой обратной совместимости речи идти не может вовсе. В каждой новой версии (даже внутри минорных билдов 6.x и 7.x) что-то да ломается: у колбэков появляются новые аргументы, у старых структур переименовываются и теряются поля, функции API, которые раньше делали одну задачу, теперь делают другую. И таких примеров много.


И ладно бы это всё хоть как-то сопровождалось разработчиком, мол, в этой версии поменялось то и это, теперь нужно так и так. Так нет же! Гайд есть, да: IDA 7.0 SDK: Porting from IDA 4.9-6.x API to IDA 7.0 API, но это всё. Более того, по нему вам не удастся перевести свой проект на новую версию, т.к. он не включает очень многих, но мелких, изменений, о которых, конечно же, вам никто не сообщит. К тому же, это последний гайд для C/C++ разработчика, а с тех пор вышло ещё где-то 5-6 версий SDK.


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


Реальный пример


Когда-то я взял на себя смелость попытаться разработать свой первый плагин-отладчик Motorola 68000 под IDA. В поставляемом SDK был пример отладчика (который, фактически, используется в IDA Pro и сейчас в качестве локального и удалённого), но он был выполнен настолько плохо, что пытаться по нему сделать свой было невозможно. Тогда я полез в интернет и нашёл единственный плагин-отладчик для PS3, который, что забавно, был выполнен на базе того самого кода из SDK.


Чтобы вы понимали, почему код из SDK я так и не решился использовать, вот вам скриншот участка кода, на котором я уже тогда понял, что будет несладко:



Видите cpp-файлы, которые включены через #include? И так по всему исходнику. Тем не менее, тщательно изучив исходный код отладчика PS3, мне удалось вычленить из него что-то рабочее и сделать свой для Sega Mega Drive.


Была одна загвоздка: исходников процессорного модуля, так необходимого для написания отладчика, у меня не было. А нужно было обращаться к регистрам, знать, какие индексы и флаги у каких опкодов установлены, заполнять структуры, отображающие вычисляемые ссылки...



Для этого пришлось снова отлаживать IDA, процессорный модуль m68k, и делать исправления для последнего (об этом я писал в "Модернизация IDA Pro. Исправляем косяки процессорных модулей").


Несмотря на все трудности, мне удалось написать хороший отладчик! К сожалению, вышла новая версия SDK В ней изменилась структура debugger_t, отвечающая за отладчик и его колбэки, и всё, что я пытался сделать, приводило к крэшам самой IDA. Спустя время я и с этим справился.


Но вышла новая версия SDK x64, без совместимости с x86! А эмулятор Gens, на базе которого я делал отладчик, не умел в x64, и проект заглох на много лет. Когда же я нашёл эмулятор, который был способен работать в x64, вышло так много версий SDK, что снова пытаться понять, почему мой плагин не работает, я не решился.


Выводы


Проблемы SDK для IDA Pro в отсутствии нормальной документации об изменениях в каждой из версий; в том, что изменения выходят скопом их много, они кардинальные, и за ними очень тяжело угнаться.


Если уж ваша фирма/команда выкладывает какой-то публичный SDK, и у него есть пользователи, которые платят деньги будьте добры, думайте и о них тоже! Их разработки могут помочь вашему продукту стать лучше и популярнее, как это произошло с IDAPython. Понятно, что хранить обратную совместимость очень сложно, но, если уж решились не поддерживать старые версии, постарайтесь документировать все изменения, которые вы делаете.


Я видел на Github большое количество полезных проектов, которые так и остались непортированными на IDA v7.x. Можно подумать, что их функционал стал ненужным в новых версиях? Может и так, но, как по мне, это усталость и нежелание бороться с постоянно меняющимся API в совокупности с хоббийностью проекта.


IDA Pro Book


Ещё хотелось бы вспомнить об одной бесценной книге, которая мне когда-то очень помогла, но которая сейчас абсолютно бесполезна для разработчика плагинов к IDA IDA Pro Book от Chris Eagle. Всё описанное в ней относится к версии 6.x (ориентировочно v6.5-v6.8). С тех пор изменилось практически всё.


Спасибо.

Подробнее..

Опыт Тинькофф Оплаты улучшили мобильный SDK и сделали оплату в интернете еще удобнее

23.10.2020 10:09:29 | Автор: admin
image

Привет! В начале лета мы обновили Tinkoff Acquiring SDK и зарелизили вторую версию для Android и iOS. Tinkoff Acquiring SDK это open-source-библиотека для мобильных платформ. С ней удобно принимать оплату в приложениях. В статье хочу рассказать, чем это круто для владельцев интернет-бизнеса и их покупателей.

Что улучшили


Проблемы, которые были в прошлой версии:

  1. Сложная архитектура библиотеки. Из-за этого разработчики тратили много времени на поиск и исправление ошибок.
  2. Избыточный API библиотеки. Разработчики часто ошибались при интеграции SDK.
  3. Не соблюдаются требования Apple Pay и Google Pay по настройке этих видов оплаты.


Что мы сделали, чтобы это исправить, и что ещё нового появилось:

  1. Полностью переписали код для обеих операционных систем. Провели рефакторинг кода и добавили много полезных функций. Теперь библиотеки работают на Kotlin и Swift.
  2. Добавили Систему быстрых платежей. Можно платить через СБП по QR-коду или через Мгновенный счёт по кнопке на экране оплаты.
  3. Поддерживаем решение all in one. Всё в одном месте: привязка карт, бесконтактная оплата, быстрые платежи по QR-коду.
  4. Обновили дизайн. Добавили темную тему. Но и не забыли про кастомизацию темы на Android, которая была в прошлой версии.
  5. Продолжаем поддерживать предыдущую версию. Подумали обо всех клиентах, не обделили старых и новых SDK работает одинаково и в первой, и во второй версии. Но рекомендуем все же обновиться, чтобы пользоваться новыми функциями.

А теперь обо всем по порядку.

Для чего нужен Tinkoff Acquiring SDK


SDK интегрирует в любое мобильное приложение интернет-эквайринг и подходит бизнесу, который принимает онлайн-платежи в приложениях: интернет-магазинам, маркетплейсам, тревел-компаниям, клинингу, стриминговым площадкам, фриланс-биржам.

Решение помогает покупателям привязать карту в приложении и оплачивать покупки в пару кликов, а продавцам сделать приложение более функциональным и не терять клиентов на этапе оформления.

Вот что умеет SDK:

Сканировать и распознавать банковские карты с помощью камеры и NFC и сохранять их. Покупатель один раз привязывает карту в приложении, а потом вводит только CVC-код, чтобы оплатить покупки.

Принимать все виды платежей в приложении: по банковским картам, через личный кабинет tinkoff.ru, Apple Pay и Google Pay. В том числе рекуррентные платежи то есть автоматические, по подписке, без повторного ввода реквизитов.
imageimage

Оплачивать с помощью Системы быстрых платежей (СБП). SDK помогает принимать платежи через СБП: покупатель оплачивает товары по QR-коду, в котором содержится вся информация о заказе. Реализуем два сценария: оплату в клиентском приложении и выставление счёта.

Поддерживать онлайн-кассу и фискализацию. Всё в соответствии с ФЗ-54.

Настраивать окно оплаты под дизайн приложения. Доступно в приложениях на Android.


Архитектурные улучшения


Проблема. Архитектура кода SDK устроена так, что поддерживать и внедрять в него новые функции сложно и долго.
Решение. Разработчики SDK провели полный рефакторинг старого кода библиотек:

код написан на современных языках Kotlin и Swift. Это ускорило процесс разработки и помогло выстроить удобную архитектуру, которую легко поддерживать и расширять: мы быстрее внедряем новые функции, а клиенты быстрее получают обновления. В первой версии код написан на Java и Objective-C;

на Android настройки экрана созданы с помощью Kotlin DSL. А вся многопоточная работа построена на корутинах: они помогают обрабатывать запросы в сеть, размер библиотеки при этом увеличивается менее чем на 1 МБ;

в проекте сократилось количество кода. Используем Generic enum, обработку ошибок с помощью throws и расширения некоторых базовых классов. Поддерживать проект стало проще;

обновили API библиотек. Методы вызова экранов и основных функций для оплаты вынесли в отдельный класс. Это единая точка входа библиотеки: гораздо проще вызывать методы API из одного места, чем из раскиданных по коду.

Структуру методов спроектировали так, чтобы работа с API была удобной и понятной. Методы хорошо задокументированы и соответствуют привычным стандартам кода на Java, Kotlin, Swift.

Например, так выглядит формирование настроек экрана оплаты и его запуск в SDK Android:
val tinkoffAcquiring = TinkoffAcquiring("terminalKey", "password", "publicKey")        val paymentOptions = PaymentOptions()                .setOptions {                    orderOptions {                        orderId = "777"                        amount = Money.ofCoins(1000)                        title = "Order Title"                        description = "Order Description"                    }                    customerOptions {                        customerKey = "user-key"                        checkType = CheckType.HOLD.toString()                        email = "useremail@gmail.com"                    }                    featuresOptions {                        localizationSource = AsdkSource(Language.RU)                        useSecureKeyboard = true                    }                }tinkoffAcquiring.openPaymentScreen(this, paymentOptions, PAYMENT_REQUEST_CODE)


Пример SDK iOS:
let credentional = AcquiringSdkCredential(terminalKey: "terminalKey", password: "terminalPassword", publicKey: "testPublicKey")let acquiringSDKConfiguration = AcquiringSdkConfiguration(credential: credentional)if let sdk = try? AcquiringUISDK.init(configuration: acquiringSDKConfiguration) {sdk.presentPaymentView(on: self, paymentData: createPaymentData(), configuration: acquiringViewConfiguration()) { [weak self] (response) inself?.responseReviewing(response)}}


SDK не ограничивает приложения клиентов: например, принимать оплату можно не только через экраны библиотеки. Иногда владельцам бизнеса и их разработчикам нужно больше возможностей в приложении.

Например, на нашем экране оплаты совершаются два запроса на сервер, а продавцу нужна дополнительная обработка заказа в приложении. Поэтому один из запросов должен выполняться до открытия экрана SDK, а второй уже на экране. Мы можем такое реализовать.

Для этого в SDK есть отдельный модуль Core. Он не зависит от платформы разработки, и с помощью него можно вызывать методы Tinkoff Acquiring API. А модуль с UI-частью предлагает другие решения без экрана SDK дополнительные методы, которые запускают экран оплаты с определенного этапа.


Google Pay и Apple Pay


Проблема. Google и Apple требуют, чтобы их способы оплаты находились не рядом с картами на экране оплаты SDK, а как отдельные кнопки в приложении, которые нужно делать самостоятельно. Разработчикам клиента приходится выполнять больше работы по настройке Google Pay и Apple Pay.
Решение. В обновленном SDK улучшили поддержку приема платежей через Google Pay и Apple Pay.

Мы учитываем требование Google и Apple, но при этом упрощаем задачу разработчикам. Большую часть настроек оплаты берет на себя SDK, а разработчикам клиента нужно вызвать всего несколько методов.

Эти методы выполняют:

  • настройку сервисов для платежа Google Pay и Apple Pay;
  • обработку доступности сервисов на девайсе;
  • вызов сервиса для оплаты;
  • обработку результата оплаты.

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


Система быстрых платежей


Это новая функция на рынке финтеха и новая технология, поэтому разработчикам пришлось реализовывать ее в SDK с нуля. СБП помогает принимать платежи по QR-коду и моментально зачислять деньги на счет продавца они приходят сразу же, даже в выходные и праздники.

Как это работает:

  1. При оплате заказа покупатель нажимает Оплатить через СБП.
  2. Покупатель попадает в банковское приложение и там подтверждает списание денег. Сумма будет указана в платежной форме.
  3. После оплаты деньги сразу приходят на расчетный счет продавца.

imageimage

Подключить новый способ оплаты клиенты могут в личном кабинете Тинькофф Оплаты. После этого в мобильном SDK у клиентов откроется возможность принимать платежи через СБП по кнопке и QR-коду.

Мгновенный счёт. На экране оплаты появляется кнопка с логотипом СБП.

Настройка экрана fpsEnabled включает кнопку для быстрой оплаты в Android SDK:
var paymentOptions = PaymentOptions().setOptions {    orderOptions { /*options*/ }    customerOptions { /*options*/ }    featuresOptions {        fpsEnabled = true             }}

В iOS SDK нужно передать buttonPaySPB:
let viewConfigration = AcquiringViewConfigration.init()viewConfigration.fields = []viewConfigration.fields.append(AcquiringViewConfigration.InfoFields.buttonPaySPB)


По статическому QR-коду. Продавец должен открыть экран оплаты на своем устройстве, а покупатель отсканировать QR-код с экрана. Это можно сделать в банковском приложении или любым QR-ридером откроется мобильное приложение банка, покупатель введет сумму заказа и оплатит товар.

Для экрана оплаты по QR-коду в SDK есть соответствующий метод. Разработчику приложения нужно создать кнопку в разметке и вызвать метод.

На Android:
tinkoffAcquiring.openStaticQrScreen(context, screenOptions, STATIC_QR_REQUEST_CODE)

Метод на iOS:
sdk.presentPaymentSbpQrImage(on: self, paymentData: createPaymentData(), configuration: acquiringViewConfiguration()) { [weak self] (response) inself?.responseReviewing(response)}


Обновленный дизайн и темная тема


Было:
imageimage

Стало:
imageimage

Мы поработали и над дизайном экранов. Обновили визуальные элементы теперь они выглядят современно и в соответствии с фирменным стилем Тинькофф. Как и в предыдущей версии, мы оставили кастомизацию темы на Android через атрибуты стилей. Окно может выглядеть как карточка или открываться на полный экран это тоже легко задать в атрибутах.

Еще экраны SDK теперь поддерживают горизонтальную ориентацию девайса и темную тему. Чтобы поддерживать настройки клиентского приложения, в Android SDK режим темной темы можно указать в настройках экранов. Возможные значения: Всегда включена, Всегда выключена, Переключение в зависимости от настроек девайса или режима экономии заряда батареи. В iOS SDK темная тема переключается в зависимости от настроек самого приложения.


Локализация экранов


Проблема. Использовали стандартную локализацию из SDK, в зависимости от установленного на устройстве языка. Некоторым клиентам нужны были расширенные настройки локализации экранов.
Решение. Запустили расширенную поддержку локализации экранов для Android SDK. Теперь она не зависит от локали девайса. Можно создать свою локализацию на любой язык или поставить стандартную локализацию SDK. На обеих платформах по-прежнему поддерживается русская и английская локализация.


Как начать пользоваться


Чтобы интегрировать SDK в приложение, сначала нужно подключить интернет-эквайринг Тинькофф Оплаты. Это быстро: владелец бизнеса подает заявку, заполняет анкету. Когда мы проверим данные и убедимся, что все в порядке, можно будет начать использовать SDK. Обычно на все это уходит два дня или меньше.

Методы подключения библиотек, документацию и исходный код смотрите на нашем GitHub:

Android SDK

iOS SDK

Если есть любые вопросы по библиотеке или нужна помощь с переходом на новую версию, напишите нам, поможем разобраться: oplata@tinkoff.ru. Или создайте Issue в соответствующем разделе на GitHub.
Подробнее..

Как исправить баг с Drawable.setTint в API 21 Android SDK

09.11.2020 18:08:51 | Автор: admin

Привет, в этой заметке наш android-разработчик Влад Титов расскажет о том, как решить проблему с использованием инструмента изменения цвета для Drawable. Поехали.

В 21 версии API Android SDK появился универсальный инструмент изменения цвета для всех Drawable - Drawable.setTint(int color). Но как раз-таки в этой самой версии он не работает у некоторых наследников Drawable, а именно GradientDrawable, InsetDrawable, RippleDrawable и всех наследников DrawableContainer.

Если посмотреть в исходники API 21, скажем, GradientDrawable (прямого наследника Drawable), мы не найдем переопределенного метода setTint и его вариаций. А это значит, что в данной реализации разработчики попросту не поддержали эту функцию.

Проблему условно решили в библиотеке обратной совместимости. Сейчас ее можно найти по артефакту androidx.core:core. Чтобы поддержать tinting на версиях 14-22, были созданы обертки WrappedDrawableApi14 и WrappedDrawableApi21. Последняя является наследницей первой и, по сути, не несет логики по поддержке окрашивания.

Чтобы обернуть оригинальный Drawable, нужно всего лишь подать его в метод DrawableCompat.wrap(Drawable). Основная идея состоит в том, что сам ColorStateList тинта хранится в обертках, а у оригинального Drawable изменяется цветовой фильтр при изменении состояния Drawable.

final ColorStateList tintList = mState.mTint;final PorterDuff.Mode tintMode = mState.mTintMode;if (tintList != null && tintMode != null) {   final int color = tintList.getColorForState(state, tintList.getDefaultColor());   if (!mColorFilterSet || color != mCurrentColor || tintMode != mCurrentMode) {       setColorFilter(color, tintMode);       mCurrentColor = color;       mCurrentMode = tintMode;       mColorFilterSet = true;       return true;   }} else {   mColorFilterSet = false;   clearColorFilter();}

Данный кусок кода будет вызываться каждый раз при вызове Drawable.setState(int[] stateSet).

При использовании этих оберток вы теряете возможность вызывать специфические методы для конкретных Drawable. Так, например, при оборачивании GradientDrawable вы не сможете управлять градиентом, так как обертка в своем интерфейсе не имеет методов таких, как setShape, setGradientType и.т.п. Чтобы получить доступ к данным методам, обернутый Drawable придется развернуть (DrawableCompat.unwrap(Drawable)). Но в таком случае вы теряете тинт. Если он у вас состоял только из одного цвета, ничего страшного, ведь этот цвет сохранится как цветовой фильтр в оригинальном Drawable. Но если тинт был stateful, цвета для стейтов, отличных от текущего, будут потеряны.

Выходом из сложившейся ситуации может быть пример, приведенный далее.

Если ваш тинт состоит лишь из одного цвета, вы можете в любой момент выполнить следующие действия:

val wrapped = DrawableCompat.wrap(drawable)wrapped.setTint(...)drawable = DrawableCompat.unwrap(wrapped)

После чего смело делать дальше свои дела.

В ином случае есть смысл воспользоваться следующим решением:

class GradientDrawableWrapper(    val original: GradientDrawable,     var ColorStateList tint) {    fun get(): Drawable {        return wrap()    }    fun setShape(@Shape shape: Int) {        original.setShape(shape)    }    // other specific method proxies...    private fun wrap(): Drawable {        val wrapped = DrawableCompat.wrap(original)        wrapped.setTint(tint)        return wrapped    }}

Такое решение выглядит немного объемным, но полностью решает указанную проблему.

Подробнее..

Создание SDK под Android в стиле Single-Activity

18.10.2020 04:15:28 | Автор: admin

Single activity подходом при создании конечного приложения под Android никого не удивишь. Но мы пошли дальше и использовали No-Activity при разработке SDK. Сейчас разберемся для чего это понадобилось, возникшие сложности и как их решали.

Стандартные 3rd party SDK в Android

Как обычно работают внешние SDK в Android? Открывается Activity библиотеки, выполняется некая работа, при необходимости возвращается результат в onActivityResult.

Стандартная схема работы SDK.Стандартная схема работы SDK.

Обычно такого подхода хватает, когда SDK выполняет целиком инкапсулированную функцию и не зависит от внешнего приложения. Но иногда необходимо обеспечить более тесное взаимодействие между приложением и SDK, например:

Желаемый стек экранов приложения и SDKЖелаемый стек экранов приложения и SDK

Получается, что экраны нашего SDK должны быть частью внешнего приложения. Точно также, как вы можете использовать, например, MapFragment от Google. Итого, при стандартном подходе, мы сталкиваемся с рядом трудностей и ограничений.

Проблемы при стандартном подходе к SDK

  • Если вам нужно несколько взаимодействий между SDK и приложением, то придется открывать-закрывать Activity от SDK и аккуратно обрабатывать передачу данных туда-обратно.

  • Сложно поддержать такой логический порядок экранов, когда элементы приложения чередуются с SDK. (Спойлер: это можно понадобится, но редко).

  • При относительно долгом возможном нахождении в SDK внешнее приложение может уйти в Lock Screen. Такое может случиться, если Lock реализован на колбеках жизненного цикла Activity.

No-Activity подход при разработке SDK

Итак, мы решили, что основная проблема в том, что контекст (Activity) внешнего приложения и SDK разные. Отсюда следует резонное решение - отказаться от контекста SDK и во внешнее приложение поставлять только фрагменты. В таком случае разработчик сможет сам управлять стеком экранов.

No-Activity SDK на ФрагментахNo-Activity SDK на Фрагментах

Данный подход имеет как ряд плюсов, так и значительные минусы. Какие же?

Плюсы No-Acitivty SDK

  • Приложение и SDK имеют общий контекст, т.е. для пользователя это выглядит как абсолютно единое приложение.

  • Основное приложение имеет свой стек фрагментов, а SDK - свой через childFragmentManager.

  • Можно организовать любой порядок экранов и наложений элементов, т.к. навигация доступна и для внешнего приложения.

Минусы No-Acitivty SDK

  • Внешнее приложение должно изначально работать с фрагментами, желательно вообще быть Single-Activity.

  • У SDK нет своего контекста, если хотите использовать dagger - придется исхитриться (но это все же возможно).

  • SDK может влиять на внешнее Acitivty, т.к. requireActivity вернет именно его. Надо полностью доверять SDK.

  • Activity будет получать onActivityResult, и, вероятно, придется его прокидывать во фрагменты.

  • Разработчику внешнего приложения сложнее интегрировать SDK, т.к. простой вызов Activity уже не сработает.

Использование 3rd party библиотек внутри SDK

При любом подходе так или иначе придется использовать библиотеки внутри SDK. Это в свою очередь может привести к коллизии версий с внешним приложением. А части библиотек, например dagger2 нужен будет выделенный контекст.

Dagger2 внутри SDK

Для использования dagger зачастую в приложении используется класс Application. В случае с SDK так сделать не получится, потому что Application, вероятно, будет перетерт со стороны внешнего приложения.

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

internal object ComponentHolder {    lateinit var appComponent: SdkAppComponent        private set    @Synchronized    fun init(ctx: Context) {        if (this::appComponent.isInitialized) return        appComponent = DaggerSdkAppComponent            .builder()            .sdkAppModule(SdkAppModule(ctx))            .build()    }}

Остается только лишь понять, откуда вызвать init, да так, чтобы в процессе жизни SDK быть уверенным, что инициализация выполнилась до любой другой работы. Для этого можно использовать одну точку входа в SDK. Назовем ее EntryPointFragment. Данный фрагмент и будет виден внешнему приложению как единственная точка входа в SDK. Вся дальнейшая навигация внутри SDK будет происходить уже в нем через childFragmentManager.

Как раз при создании EntryPointFragment можно и инициализировать ComponentHolder для Dagger.

override fun onCreate(savedInstanceState: Bundle?) {        ComponentHolder.init(requireActivity())        ComponentHolder.appComponent.inject(this)        super.onCreate(savedInstanceState)    }

Итого, на выходе мы получили ComponentHolder, который можно использовать внутри SDK для инъекции нужных компонент.

Устранение коллизии в версиях

С данной проблемой столкнулись при обновлении версии okhttp3 до новой major версии 4.+. В ней добавили улучшенную поддержку Kotlin, в том числе, например, доступ к коду ошибки через code() теперь стало ошибкой. Клиенты SDK, используя либо 3, либо 4 версию должны получать ту же внутри SDK, иначе все сломается.

Это реально сделать, вынеся код с коллизиями в отдельный модуль. В нем будут 2 flavor:

    flavorDimensions("okhttpVersion")    productFlavors {        v3 {            dimension = "okhttpVersion"        }        v4 {            dimension = "okhttpVersion"        }    }        dependencies {        v3Api okhttp3.core        v3Api okhttp3.logging        v4Api okhttp4.core        v4Api okhttp4.logging}

В двух разных папках, отвечающих за каждый flavor будут одинаковые классы, один из которых будет использовать code() а другой code.

// Code in v3 folderclass ResponseWrapper(private val response: Response) {    val code : Int        get() = response.code()}
// Code in v4 folderclass ResponseWrapper(private val response: Response) {    val code : Int        get() = response.code}

Остается только на уровне приложения выбрать необходимый конфиг и дальше правильная версия приедет в финальный проект.

Подсказка: если вы сами используете свой же модуль в проекте и подключаете как исходники, не забудьте следующее:

defaultConfig {...missingDimensionStrategy 'okhttpVersion', 'v4'}

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

Заключение

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

Подробнее..

Создаём мини PHP SDK для подписи запросов к Oracle Cloud Infrastructure API

11.02.2021 04:19:49 | Автор: admin

Идея написать эту библиотеку возникла, когда захотелось в полной мере воспользоваться всеми преимуществамибесплатного предложенияOracle Cloud Infrastructure, а именно 10 ГБ хранилища объектов (Object Storage) и 10 ТБ исходящего трафика в месяц. Разница сAWSS3 простоогромнейшая. К сожалению,OracleCloudне имеетв наличииSDKдля всё еще самого популярного языка программирования для разработки веб-сайтов. Хорошая новость состоит в том, что сервисчастично совместимсAmazonS3, а это означает, что можно применить уже имеющиеся и отлично задокументированныеинструменты разработчика, в том числе дляPHP.

Тем, кому не терпится увидеть код, добро пожаловатьhttps://github.com/hitrov/oci-api-php-request-sign.

Действительно, с имеющимися инструментами можно выполнять почти все операции, которые можно представить - для создания, чтения и удаления корзин (buckets) и объектов (файлов). Корзины могут быть как публичными (с возможностью листинга файлов и без) и приватными. Есть возможность загружать файлы в приватную корзину, имея лишь секретныйURL(сгенерированный вручную с помощьюCLIили веб-интерфейса - консолиOracleCloud). На самом деле этого уже может быть достаточно для многих сценариев, особенно если генерировать стойкие к подбору имена файлов - в случае, если вы не хотите выставлять их на публику.

Меня интересовала возможность расшаривать файлы, то есть делиться общедоступными ссылками на файлы, и, конечно же, ограничивать доступ при необходимости. При небольшом количестве файлов можно делать это вручную, но мы собрались здесь, чтобы иметь программный доступ. ВAWS S3этоназываетсяPre-Signed URL,ауOracle -Pre-Authenticated Request.

Установка AWS PHP SDK

composer require aws/aws-sdk-php

Ниже будет показано, где взять доступы (AWS_ACCESS_KEY_IDи AWS_SECRET_ACCESS_KEY.

Namespace же можно увидеть

$namespaceName = 'frpegp***';$bucketName = 'test******05';$region = 'eu-frankfurt-1';$endpoint = "https://$namespaceName.compat.objectstorage.$region.oraclecloud.com";$s3 = new Aws\S3\S3Client([    'version' => 'latest',    'region'  => $region,    'endpoint' => $endpoint,    'signature_version' => 'v4',    'use_path_style_endpoint' => true,    'credentials' => [        'key'    => 'AKI***YYJ', // remove if you have env var AWS_ACCESS_KEY_ID        'secret' => 'ndK***cIf', , // remove if you have env var AWS_SECRET_ACCESS_KEY    ],]);$cmd = $s3->getCommand('GetObject', [    'Bucket' => $bucketName,    'Key' => 'fff.txt']);$request = $s3->createPresignedRequest($cmd, '+20 minutes');

К сожалению, данная операция, хотя и не вызывает ошибку, отдавая в ответPSR-7request, но возвращаемый имURLвида

https://{namespace}.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/{bucket}/fff.txt?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=***%2F20210210%2Feu-frankfurt-1%2Fs3%2Faws4_request&X-Amz-Date=20210210T185244Z&X-Amz-SignedHeaders=host&X-Amz-Expires=1200&X-Amz-Signature=a167a***9a857

просто не работает.

<?xml version="1.0" encoding="UTF-8"?><Error>    <Message>The required information to complete authentication was not provided.</Message>    <Code>SignatureDoesNotMatch</Code></Error>

Поскольку совместимость для данной операции не была заявлена, странно было бы ожидать иного, но попробовать стоило :)

Здесь я попробую очень кратко описать, что необходимо для подписи запроса кAPI, ведь все изложено довольно подробноздесь, пусть и с примерами для иных языков программирования.

Разумеется, подпись будет работать для всех запросов начиная от создания\остановки\бэкапаавтономной базы данных, управленияDNSи заканчивая отправкойEmail. Всё что указано в API Reference and Endpoints.

Прежде всего, для того, чтобы начать работу, нужны ключи доступа, в веб-интерфейсе (консоли)OracleCloud необходимо зайти вUserSettings

Действия в профиле Oracle CloudДействия в профиле Oracle Cloud

API KeysAdd API Key

API Keys - Add API KeyAPI Keys - Add API Key

Downloadprivatekey(сохраняем в надежном месте), затемAdd

Download Private Key and AddDownload Private Key and Add

Сохраняем все значения из текстового поля, они нам понадобятся через минуту

Configuration File exampleConfiguration File example

Для того, чтобы воспользоваться AWS PHP SDK, вам необходимы Customer Secret Keys (они же AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY в понимании Amazon.

Установка Oracle Cloud Infrastructure mini PHP SDK(никаких внешних зависимостей!)

composer require hitrov/oci-api-php-request-sign

Пакет использует стандартнуюPSR-4 автозагрузку классов.

require 'vendor/autoload.php';use Hitrov\OCI\Signer;

Для авторизации нужно задать переменные среды (замените на значения, взятые из текстового поля, проставьте путь к файлу с приватным ключом).

OCI_TENANCY_ID=ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsqOCI_USER_ID=ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjqOCI_KEY_FINGERPRINT=20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34OCI_PRIVATE_KEY_FILENAME=/path/to/privatekey.pem

В этом случае конструктор не принимает аргументов.

$signer = new Signer;

Переменным среды есть несколько альтернативhttps://github.com/hitrov/oci-api-php-request-sign#alternatives-for-providing-credentials, не стану дублировать это здесь.

МыпопробуемвыполнитьCreatePreauthenticatedRequest.

Вся сложность (если можно так выразиться) абстрагирована в один публичный метод

public function getHeaders(    string $url, string $method = 'GET', ?string $body = null, ?string $contentType = 'application/json', string $dateString = null): array

Пример использования

$curl = curl_init();$url = 'https://objectstorage.eu-frankfurt-1.oraclecloud.com/n/{namespaceName}/b/{bucketName}/p/';$method = 'POST';$body = '{"accessType": "ObjectRead", "name": "read-access-to-image.png", "objectName": "path/to/image.png", "timeExpires": "2021-03-01T00:00:00-00:00"}';$headers = $signer->getHeaders($url, $method, $body, 'application/json');var_dump($headers);$curlOptions = [  CURLOPT_URL => $url,  CURLOPT_RETURNTRANSFER => true,  CURLOPT_ENCODING => '',  CURLOPT_MAXREDIRS => 10,  CURLOPT_TIMEOUT => 5,  CURLOPT_FOLLOWLOCATION => true,  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,  CURLOPT_CUSTOMREQUEST => $method,  CURLOPT_HTTPHEADER => $headers,];if ($body) {  // not needed for GET or HEAD requests  $curlOptions[CURLOPT_POSTFIELDS] = $body;}curl_setopt_array($curl, $curlOptions);$response = curl_exec($curl);echo $response;curl_close($curl);
array(6) {  [0]=>  string(35) "date: Mon, 08 Feb 2021 20:49:22 GMT"  [1]=>  string(50) "host: objectstorage.eu-frankfurt-1.oraclecloud.com"  [2]=>  string(18) "content-length: 76"  [3]=>  string(30) "content-type: application/json"  [4]=>  string(62) "x-content-sha256: X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE="  [5]=>  string(538) "Authorization: Signature version=\"1\",keyId=\"ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsq/ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjq/20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34\",algorithm=\"rsa-sha256\",headers=\"date (request-target) host content-length content-type x-content-sha256\",signature=\"LXWXDA8VmXXc1NRbMmXtW61IS97DfIOMAnlj+Gm+oBPNc2svXYdhcXNJ+oFPoi9qJHLnoUiHqotTzuVPXSG5iyXzFntvkAn3lFIAja52iwwwcJflEIXj/b39eG2dCsOTmmUJguut0FsLhCRSX0eylTSLgxTFGoQi7K/m18nafso=\""}
{  "accessUri": "/p/AlIlOEsMok7oE7YkN30KJUDjDKQjk493BKbuM-ANUNGdBBAHzHT_5lFlzYC9CQiA/n/{namespaceName}/b/{bucketName}/o/path/to/image.png",  "id": "oHJQWGxpD+2PhDqtoewvLCf8/lYNlaIpbZHYx+mBryAad/q0LnFy37Me/quKhxEi:path/to/image.png",  "name": "read-access-to-image.png",  "accessType": "ObjectRead",  "objectName": "path/to/image.png",  "timeCreated": "2021-02-09T11:52:45.053Z",  "timeExpires": "2021-03-01T00:00:00Z"}

Вот и всё!

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

1) Прежде всего, нам необходимо собрать список подписываемых заголовков (SIGNING_HEADERS_NAMES). Он всегда содержит

  • date

  • (request-target)

  • host

ДляPOST|PUT|PATCHзапросов добавляются еще три

  • content-length

  • content-type

  • x-content-sha256

$signingHeadersNames = $signer->getSigningHeadersNames('POST');

2) SHA256 хэш тела запроса кодированный вbase64

$bodyHashBase64 = $signer->getBodyHashBase64($body);

3) Сформировать строку для подписи, в нашем случае она будет выглядеть следующим образом

date: Mon, 08 Feb 2021 20:51:33 GMT(request-target): post /n/{namespaceName}/b/{bucketName}/p/host: objectstorage.eu-frankfurt-1.oraclecloud.comcontent-length: 76content-type: application/jsonx-content-sha256: X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=
$signingString = $signer->getSigningString($url, $method, $body, 'application/json');

Хэш мы получили в (2).Важно, что дата и время не должны отличаться от текущих на более, чем 5 минут.

4) Подписать строку из (3) приватным ключом с помощью алгоритмаRSA-SHA256

$signature = $signer->calculateSignature($signingString, $privateKeyString);

5) Сформировать KEY_ID данными, которые вы скопировали при создании API Key, это строка, разделенная слешами

"{OCITENANCYID}/{OCIUSERID}/{OCIKEY_FINGERPRINT}"

$keyId = $signer->getKeyId();

6) Теперь мы готовы сгенерировать заголовок авторизации(версия 1останется таковой до отдельного уведомления отOracle)

Authorization: Signature version=\"1\",keyId=\"{KEY_ID}\",algorithm=\"rsa-sha256\",headers=\"{SIGNING_HEADERS_NAMES_STRING}\",signature=\"{SIGNATURE}\"

гдеSIGNING_HEADERS_NAMES_STRING это список из (1), разделенный пробелами.

date (request-target) host content-length content-type x-content-sha256

$signingHeadersNamesString = implode(' ', $signingHeadersNames);$authorizationHeader = $signer->getAuthorizationHeader($keyId, $signingHeadersNamesString, $signature);

Пример вывода

Authorization: Signature version=\"1\",keyId=\"ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsq/ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjq/20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34\",algorithm=\"rsa-sha256\",headers=\"date (request-target) host content-length content-type x-content-sha256\",signature=\"LXWXDA8VmXXc1NRbMmXtW61IS97DfIOMAnlj+Gm+oBPNc2svXYdhcXNJ+oFPoi9qJHLnoUiHqotTzuVPXSG5iyXzFntvkAn3lFIAja52iwwwcJflEIXj/b39eG2dCsOTmmUJguut0FsLhCRSX0eylTSLgxTFGoQi7K/m18nafso=\"

Реальные заголовки запроса - см. выводvar_dump()выше - должны содержать всё из (3), за исключением поля(request-target)и его значения. И, конечно же, заголовок авторизации (6).

МнепомогластатьяOracle Cloud Infrastructure (OCI) REST call walkthrough with curl. Некоторые имена методов позаимствованы из официальногоGoLangSDK. Тест-кейсы оттуда же.

Подробнее..

Зачем нужна еще одна система распознавания баркода?

29.01.2021 18:07:40 | Автор: admin

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

Штрихкод, или баркод, безусловно, является важным изобретением человечества, которое изменило течение нашей жизни. В одной из своих статей на Хабре мы ужерассказывали, как эволюционировал этот способ кодирования информации.

Сегодня не будем углубляться в техническую часть, а рассмотрим существующие проблемы при внедрении технологии распознавания баркодов. Действительно, откуда могут возникнуть проблемы, если штрихкодирование это такой особый способ кодирования данных, который как раз призван обеспечить быстрое и беспроблемное считывание данных машиной? Все алгоритмы декодирования баркодов разжёваны до самых мелочей. Задача декодирования баркодов отлично решается без использования каких-либо нейронных сетей и прочих страшилок нашего века. Кажется, что технология распознавания баркодов это тот космодром, с которого должны взлетать в счастливое будущее большое количество opensource-библиотек.

Оказывается, дело обстоит не совсем так. Первый звоночек о негодности всего бесплатного для решения задачи распознавания баркодов мы получили в виде очередного запроса от давнего клиента одного коммерческого банка (из топ-10), технологичности которого могут позавидовать многие. Коллеги продемонстрировали, что популярные бесплатные библиотеки категорически не справляются даже с QR-кодами. Про коды типа AZTEC даже говорить не приходится (этот вид баркодов, который встречается на платежках, визуально похож на QR-код, но при этом кардинально отличается от него по сложности декодирования).

Мы немного погрузились в задачу и очень быстро поняли, что практически все библиотеки сдали свои позиции на полпути, еще не дойдя даже непосредственно до распознавания. Ведь наибольшую трудность в задаче представляют точная локализация и ориентация распознаваемого штрихкода. На первый взгляд кажется, что задача должна решиться в два счета, так как у многих штрихкодов в структуре присутствуют специальные черно-белые квадратные мишени для локализации. Но мы-то с вами знаем, что задача цветовой константности, решение которой как раз и позволяет понять, какие объекты каким образом окрашены, совсем непроста. Да и мишени, кстати, не всегда черно-белые и даже не всегда квадратные (дизайнерские решения, эксплуатирующие разные цвета и форму, очень мешают задаче распознавания баркода).

Чтобы окончательно проникнуться сложностью задачи распознавания штрихкодов, представьте, какие артефакты возникают при движении камеры, фотографировании в темноте со вспышкой, пересъемке штрихкода с монитора, попытке распознать заламинированный штрихкод. А еще представьте, как выглядит штрихкод с огромным количеством данных внутри (можно даже не представлять, а просто взять квитанцию оплаты, например, за детский садик).

Кстати говоря, мы уже провели первый этап исследований задачи поиска штрихкода на изображении. Ознакомиться с нашими статьями в 2020 году по тематике можноздесьиздесь.

Есть еще одна причина, почему мы не остались в стороне от решения проблемы распознавания штрихкодов. В нашей стране семимильными шагами развивается технология оплаты по QR-кодам (в подтверждение моих слов смотрите, например, материал на vc.ruздесь,здесьиздесь). БудучиучастникамиГлобального договора ООН и ярыми приверженцами ответственного ИИ, мы просто не могли допустить, чтобы рынок не оценил всех преимуществ оплаты по QR из-за фактической неспособности имеющихся бесплатных библиотек распознавания. И не будем забывать про набирающую обороты Систему маркировки и прослеживаемости товаров. Все это натолкнуло нас на создание модуля распознавания штрихкодовSmart Code Engine.

Чтобы проверить эффективность получившегося решения, мы самостоятельно создали небольшой набор фотографий QR-кодов. Единственное требование фотографировать баркоды необходимо так, как это делают обычные пользователи. Ниже приводим примеры изображений из нашего датасета.

Как видите, изображения далеки от идеальных. Мы сравнили качество работы Smart Code Engine с двумя популярными opensource-решениями:OpenCV 4.5.1(библиотека компьютерного зрения с открытым исходным кодом, которую часто применяют при создании системы с ИИ) иZxing(библиотека с открытым исходным кодом для распознавания баркодов). В таблице ниже представлены результаты:

Продукт

Smart Code Engine

OpenCV 4.5.1

Zxing

Качество распознавания

99%

56%

81%

Как трактовать эти числа? Достаточно просто:

  • OpenCV серьезно проигрывает Zxing по качеству декодирования;

  • Smart Code Engine обеспечивает в 19 раз меньше ошибок, чем Zxing (с OpenCV даже и смысла сравнивать нет).

Возникает вопрос: А на чем ошибаются рассмотренные системы? Проведем анализ ошибок только для Smart Code Engine и Zxing. Ниже представлено единственное изображение, на котором ошиблось Smart Code Engine.

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

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

На сегодняшний день Smart Code Engine обеспечивает качественное распознавание одно- и двумерных штрих-кодов из различных счетов и квитанций, включая счета за коммунальные и государственные услуги, налоговых документов и счетов, а также билетов, чеков, счетов-фактур, ценников, плакатов и объявлений. Модуль чтения QR-кодов способен читать инвертированные коды, а также устойчив к любой ориентации. Текущая версия Smart Code Engine поддерживает распознавание QR Code, AZTEC, PDF 417, Data Matrix, codabar, CODE_39, CODE_93, CODE_128, EAN_8, EAN_13, ITF, UPC_A, UPC_E.

Smart Code Engine уже внедрен в мобильные приложения Тинькофф Банка, Рокетбанка, СДМ-Банка, Банка Санкт-Петербург. Мы уверены, это только начало.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru