Jump to content

Yaroslav Brovin

Administrators
  • Posts

    2,568
  • Joined

  • Last visited

  • Days Won

    647

Blog Entries posted by Yaroslav Brovin

  1. Yaroslav Brovin
    Доброго дня, уважаемые пользователи FGX Native.
    Наши клиенты делают интересные проекты на базе нашего продукта, однако, к сожалению, об этом знаю только я в результате получения обратной связи по FGX Native. Мне кажется, что всем было бы интересно узнать о таких приложениях, о применяемых возможностях FGX Native и об использованных технических решениях. Сегодня я начну с обзора приложения, которое первоначально задумывалось, как приложения для каршеринга. Однако, в ходе разработки, области применения гораздо расширились за счет универсальности разработанного решения. Но обо всем по порядку.
       
    Далее приведен текст автора @r3h0soft.
    Перед нами стояла задача реализовать программный комплекс мониторинга за ГЛОНАСС устройствами, который бы включал возможности:
    Отслеживание местоположения устройств Мониторинг телеметрии Формирование различных отчётов за выбранный период времени И т.д. В комплекс входило так же и мобильная разработка, при которой стоило преимущественно выбрать среду разработки с лаконичными и понятным кодом имеющим в комплекте кроссплатформенной реализации. Выбор остался за Delphi. Мобильное приложение должно было отвечать всем требованиям на текущий момент что касаемо UI, отзывчивый интерфейс, анимации, поддержкой API и т.д.  Но если с реализацией бэкенд всё было прозрачно, то неотъемлемой частью разработки UI было не всё гладко с использованием FireMonkey. Выбор пал на FGX Native, который предлагает все инструменты для простой и лёгкой разработки и решению поставленных задач.
    В FGX Native реализовано собственное уникальное решение реализации UI, за основу взята система позиционирования FlexBox. С его помощью можно на лету, только через свойства компонента, реализовать UI любой сложности, которое будет одинаково выглядеть при любом разрешении устройств без единой строчки кода. Этот подход значительно ускорил процесс разработки и позволил сосредоточится на построении логики приложения, не загромождая код, вычислениями позиционирования элементов интерфейса.
    Карты
    Данный проект сложно представить без отражения мониторинга в режиме реального времени. За основу мы взяли компонент карт TfgMap с возможностью отображать маркеры, полигоны, географические зоны, строить маршруты, используя линии с большим количеством объектов. Удивила скорость работы компонента и его плавность. Одной из приятных функций для нашего проекта оказалась стилизация карт. Это позволило нам настроить внешний вид карты, чтобы он не выбивался из общего дизайна интерфейса. Одной из задач при использовании карт было построение маршрута, реализовав парсер точек по заданному диапазону времени с необходимой информацией о состоянии объекта и его положении GPS, используя фильтр настойки для разграничения маршрута использовали состояния "простоя" объекта, и иные события при которых объект не выполнял движения. Так мы получили точный список точек перемещения и реализовали отображение через поли линии. Через свойства реализации в FGX Native, мы смогли стилизовать под свои нужды, зная определенные участки состояния объекта смогли через маркеры объектов вывести определенные состояния (к примеру, участки превышения скорости). Хорошим моментом послужило что точками можно взаимодействовать присвоив им ID, так можно получить дополнительную информацию в любом участке трекера просто выбрав точку на карте. Конечно, в будущем очень хотелось бы использовать некую сущность для маркера имеющую стиль, для наполнения его своими объектами как в TfgCollectionView и отображения определенных маркеров при определенных состояниях.
    Сами маркеры добавляются легко через менеджер объектов.
      
    Списки
    Не обошлось и без списков, следовало подгружать объекты в стилизованные карточки одного списка, не нагружая при этом систему, с плавность отрисовки и высокой скоростью. Для решения данной задачи взят TfgCollectionView. Этот компонент отвечает всем требованиям и прост как и все другие решения библиотеки в освоении.  Мы использовали списки, как для формирования меню навигации, так и для отображения маршрутов, истории поездок и т.д. Чтобы не нагружать приложение разными формами, мы использовали выдвигаемые панели сбоку TfgDrawerLayout и снизу TfgBottomSheetLayout. С помощью этих компонентов решена задача быстрого доступа к данным истории телеметрии при этом не нагружая интерфейс и проект дополнительными формами.
     
    Не обошлось и без списков, следовало подгружать объекты в стилизованные карточки одного списка, не нагружая при этом систему, с плавность отрисовки и высокой скоростью. Для решения данной задачи взят TfgCollectionView. В списках мы добавили нужные нам стили объектов списка, что позволило генерировать нужный по событию изменяя только имя стиля, это удобно. Единственное чего не хватило, так это свайпа по элементам списка (лево/право). В общем и целом, этот компонент отвечает всем требованиям и прост как и все другие решения библиотеки в освоении.  Мы использовали списки, как для формирования меню навигации, так и для отображения маршрутов, истории поездок и т.д.
    Чтобы не нагружать приложение формами, мы использовали выдвигаемые панели сбоку TfgDrawerLayout и снизу TfgBottomSheetLayout. С помощью этих компонентов решена задача быстрого доступа к данным истории телеметрии при этом не нагружая интерфейс и проект дополнительными формами.
      
     
    Анимация
    Чтобы оживить интерфейс и порадовать пользователя внешним видом было принято решение встроить готовые сценарии анимации. В одном из обновлений FGX Native появилась поддержка продвинутых анимаций Lottie. Мы нашли готовые примеры анимации и просто встроили их в пару кликов. Таким образом получился такой вот симпатичный экран:
    AddingDriver.mp4
    Так же имеется и конструктор анимации для самих компонентов, мы использовали анимацию тряски для неправильного ввода пароля и анимацию появления для уведомлений.
    Сканер штрих кодов
    В ходе работы с приложением, пользователю необходимо выполнить регистрацию ГЛОНАСС устройства. Можно было бы ограничится вводом в ручную серийного номера, указанного на устройстве. Однако, мы воспользовались готовым сканером штрих кодов TfgBarcodeScanner и камерой TfgCamera и сделали эту процедуру автоматической.

    Уведомления и монетизация
    Любое приложение каршеринга - это контроль за местоположением транспортного средства. И в нашем случае это не исключение. Нам нужно было уведомлять пользователя при определенных событиях телеметрии устройства (вход/выход из геозоны, состояния устройства, ДТП, включения зажигания). Для этого мы использовали локальные уведомления. А вот для системных уведомлений, таких как "обновление приложения" или "необходимости оплаты" легко реализованы с помощью Push уведомлений на базе FGX и Firebase.
    Кстати, среди поставляемых примеров, вы найдете много готовых решений и примеров возможностей библиотеки.
    Хотите иметь возможность монетизации в приложении будь то подписка или продажа, для этого есть готовые компоненты оплаты, как для Android так и iOS.
    Реализация авторизации
    Как и любое приложение, работающее с пользователя, нам необходимо было организовать процесс авторизации. Мы использовали Firebase, реализация выполнена с помощью FB4D библиотеки, в FGX имеется возможность легко реализовать авторизацию и с помощью Google Sign, Facebook, VK, AppleID, что не может не радовать. Основная база крутится на PostgreSQL, используя штатные компоненты FireDAC. Общение построено с использованием REST API, чьим ответственным выступил DelphiMVCFramework фреймворк. Как видно, FGX Native не конфликтует с различными сторонними решениями, что позволяет расширять возможности разработки приложений любой сложности и поставленных задач.
    Bluetooth
    Не обошлось и без штатных задач управления устройством с помощью Bluetooth , мы использовали стандартные средства Delphi RTL для синхронизации и управления модулем через Bluetooth.
    Итог
    Это лишь малая часть которой хотел поделиться, возможности FGX Native для нас очень обширны, мы реализовали разные сложные проекты с его помощью, о которых я расскажу напишу в следующих статьях. Среди таких:
    Мониторинг за сотрудниками (курьерами, работниками, водителям где устройством мониторинга выступает мобильное приложение на FGX с использованием сервисов фоновой локации и состоянием устройства, мониторинга задач и управления через Bitrix), личный кабинета клиента микрофинансовой компании, личный кабинет клиентов интернет провайдера, управление модулем автопилота для лодок fishboat по Bluetooth и многое другое. FGX Native - это лучшее решение для нас!
  2. Yaroslav Brovin
    Добрый вечер,
    Мы плотно работаем над новой версией библиотеки FGX Native, в которую войдут новые компоненты-контейнеры и многие другие улучшения. В этой статье мы хотели бы поделиться двумя новыми компонентами-контейнерами TfgVirtualPagerLayout и TfgPagerLayout, которые появятся в релизе 1.13.1.0. 
    TfgVirtualPagerLayout
    Это базовый компонент, который предназначен для динамической загрузки/выгрузки страниц по мере их необходимости. В отличии от привычных подходов с добавлением вложенных компонентов заранее в дизайнере, этот компонент запрашивает загрузку/выгрузку страницы через события OnLoadPage и OnUnloadPage по мере их необходимости. Это значит, что фактически вместо загрузки 10-20 страниц, он загружает только видимую и еще 1-2 смежных в зависимости от текущего состояния компонента и, как следствие, ускоряет загрузку приложения.
    На базе данного компонента можно легко сделать оптимизированный слайдер изображений. Например вот такой:
    PhotoSlider.mp4
    Компонент не хранит все страницы у себя и работает по cхожему c TfgCollectionView принципу, те запрашивает необходимую информацию у разработчика через набор событий. Перед использованием компонента, вам необходимо написать обработчики для 3-х событий:
    OnGetPageCount - вернуть общее количество страниц в компоненте. OnLoadPage - вернуть компонент страницы. Это может быть любой визуальный компонент. Вы можете создавать  страницу в этом событии динамически, а можете реализовать пул объектов, чтобы повторно использовать выгруженные ранее страницы. OnUnloadPage - можно выполнить уничтожение страницы или вернуть страницу в пул объектов для дальнейшего повторного использования. Типичным примером реализации данных событий может быть такой код, создающий страницы с текстом на базе TfgLabel:
    procedure TFormMain.fgVirtualPagerLayout1GetPageCount(Sender: TObject; var ACount: Integer); begin // Сообщаем компоненту о количестве страниц. ACount := 100; end; procedure TFormMain.fgVirtualPagerLayout1LoadPage(Sender: TObject; const AItemIndex: Integer; var APage: TfgControl); var LPage: TfgLabel; begin // Создаем страницу на базе TfgLabel, которая будет отображать номер страницы. LPage := TfgLabel.Create(nil); LPage.Font.Size := 30; LPage.Text := Format('Page %d', [AItemIndex]); APage := LPage; end; procedure TFormMain.fgVirtualPagerLayout1UnloadPage(Sender: TObject; const AItemIndex: Integer; const APage: TfgControl); begin // Удаляем страницу. APage.Free; end; В результате получим:
    Basic_Text_Pages.mp4
     
    Пул страниц
    В этом примере вы можете обратить внимание, что если страницы по структуре одинаковые, то смысла удалять страницу и создавать заново особо не имеет смысла. Поэтому для этого случая, можно написать простой пул объектов, который не будет удалять вкладку, как только она не нужна, а складывать ее в список для дальнейшего повторного использования. Для реализации пула страниц создадим два списка:
    Список используемых страниц в компоненте в текущий момент времени - FAcquiredPages. Список использованных страниц, которые уже не используются в текущий момент времени - FReleasedPages. Код по объявлению списков выглядит так:
    type TFormMain = class(TfgForm) private FAcquiredPages: TList<TfgLabel>; FReleasedPages: TObjsetList<TfgLabel>; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; end; var FormMain: TFormMain; implementation {$R *.xfm} uses System.SysUtils, FGX.Application, FGX.Dialogs, FGX.Log; { TFormMain } constructor TFormMain.Create(AOwner: TComponent); begin inherited; FAcquiredPages := TList<TfgLabel>.Create; FReleasedPages := TObjsetList<TfgLabel>.Create; end; destructor TFormMain.Destroy; begin FreeAndNil(FAcquiredPages); FreeAndNil(FReleasedPages); inherited; end; Теперь, когда компонент запрашивает страницу мы выполняем простые действия:
    Если страница есть в пуле, то мы ее извлекаем. Если свободной страницы в пуле нет, то создаем новую. Когда же страница выгружается компонентом, мы просто возвращаем ее в пул.
    procedure TFormMain.fgVirtualPagerLayout1GetPageCount(Sender: TObject; var ACount: Integer); begin ACount := 100; end; procedure TFormMain.fgVirtualPagerLayout1LoadPage(Sender: TObject; const AItemIndex: Integer; var APage: TfgControl); var Page: TfgLabel; begin if FReleasedPages.Count = 0 then begin // В пуле нету свободных страниц, создаем новую Page := TfgLabel.Create(nil); Page.Font.Size := 30; end else // В пуле есть свободная страница, берем ее Page := FReleasedPages.ExtractAt(0); // Переносим страницу в список используемых страниц. FAcquiredPages.Add(Page); // Задаем текст и возвращаем страницу Page.Text := Format('Page %d', [AItemIndex]); APage := Page; end; procedure TFormMain.fgVirtualPagerLayout1UnloadPage(Sender: TObject; const AItemIndex: Integer; const APage: TfgControl); begin TfgAssert.IsClass(APage, TfgLabel); // Возвращаем страницу в пул для повторного использования FAcquiredPages.Remove(APage as TfgLabel); FReleasedPages.Add(APage as TfgLabel); end; Теперь мы получили такое же приложение, как и без использования пула, но теперь страницы не пересоздаются по мере их пролистывания, а повторно используются. Тем самым мы ускоряем процедуру загрузки страниц. 
    Таким образом, этот компонент позволяет ускорить загрузку приложения за счет загрузки только необходимых страниц, а не всех сразу. На базе данного компонента можно легко реализовать слайдер изображение с большим количеством изображений и многое другое.
    Динамическое изменение страниц
    Поскольку компонент запрашивает страницы и их количество у разработчика, то при любом изменении количества страниц, удаление/добавление страниц необходимо уведомить об этом компонент при помощи следующих методов:
    Reload - Уведомляет компонент о том, что список страниц изменился и надо заново его построить. NotifyPageInserted - Уведомляет компонент, что в список вставлены новые страницы по указанным индексам. NotifyPageRemoved - Уведомляет компонент, что из списка нужно удалить страницы по указанным индексам. Состав страниц нельзя менять в процессе переключения вкладок!
    Дополнительные события
    Данный компонент предлагает широкий набор дополнительных событий, позволяющих полностью контролировать процесс смены вкладок:
    OnChanged - Вызывается только при интерактивной смене вкладки, как только компонент понимает на какую вкладку окончательно переключается пользователь.  OnBeginDragging - Вызывается, когда пользователь опустил палец на экран и начал двигать содержимое.  OnEndDragging - Вызывается, когда пользователь поднял палец с экрана и закончил двигать содержимое. OnBeginScrolingAnimation - Вызывается, когда началась анимация смены вкладки. OnEndScrolingAnimation - Вызывается, когда анимация смены вкладки закончилась. TfgPagerLayout 
    Этот компонент-контейнер построен на базе TfgVirtualPagerLayout и в отличии от TfgVirtualPagerLayout выравнивает все добавленные в него компоненты по страницам. Он не выгружает/загружает страницы и по сути является аналогом TfgPageControl. Вы добавляете в него любые компоненты и TfgPagerLayout сам осуществляет их выравнивание и переключение.
     
  3. Yaroslav Brovin
    Как вы знаете, библиотека FGX Native - это кроссплатформенная библиотека, разрабатываемая с учетом возможностей добавления новых платформ.
    На текущий момент доступна только платформа Андроид. Однако, работа над iOS уже идет полным ходом.
    Рад поделится с вами промежуточными результатами. Перед вами простое приложение с одной кнопкой и меткой:

    Полностью работает система выравнивания, реализована часть базовых сервисов платформы и сделаны первые наброски стандартных компонентов (кнопки, метки и контейнеры).
    video_2020-04-07_02-12-49.mp4.994174c5afa23d87170f03d57d1b01e0.mp4
  4. Yaroslav Brovin
    В ближайшем релизе 1.1.4.0 появится возможность указывать форматированный текст, используя упрощенный HTML формат.
    Чтобы использовать форматированный текст необходимо:
    1. Указать в свойстве Text HTML разметку.
    Например: 
    <font color='red'>red</font> <b>and</b> <font color='blue'>blue</font> Внимание! Поддерживается только форматирование текста, такое как изменение цвета и стиля текста.
    2. Указать, что нужно воспринимать исходный текст, как HTML разметка (TextType = HTML).

    Внимание! В версии 1.1.4.0 TfgLabel не поддерживает отображение html в дизайнере IDE.

  5. Yaroslav Brovin
    В обновлении 1.1.6.0 процесс сборки android приложения претерпел незаметное на первый взгляд, но очень важное для пользователей изменение, а именно,  добавлена автоматическая генерация файла classes.dex.
    classes.dex - обязательный для android приложения файл, содержащий все используемые в приложении Java библиотеки. Ранее конечное приложение собиралось с готовым classes.dex файлом поставляемым вместе с библиотекой FGX Native, что создавало для разработчиков некоторые проблемы при использовании сторонних jar библиотек. Процесс добавления был нетривиален и требовал глубокого погружения в документацию, процессы сборки и микширования classes.dex.
    Механизм автоматической генерации уже используется в FMX проектах, однако, по ряду причин и ограничений, накладываемых IDE, он не мог быть задействован для FGX Native.
    Мы пересмотрели пользовательский опыт и рады представить вам новый удобный диалог для управления jar библиотеками, используемыми в проекте.
    Вызвать диалог можно двумя способами:
    Через главное меню: Project -> FGX Android Libraries Через контекстное меню панели Projects. Target Platforms -> Android (32/64 bits) -> Libraries -> Setup Android Libraries.
    Всё, что необходимо для включения в ваше приложение сторонней jar библиотеки — это добавить её в разделе «Все модули» или «Пользовательские».
    Для возврата списка библиотек к первоначальноиу состоянию воспользуйтесь кнопки «По-умолчанию».
  6. Yaroslav Brovin
    и 
    Что связывает итальянскую конференцию DelphiDay по Delphi и FGX Native?
    Правильно! В ближайшие дни FGX Native будет представлена на одной из крупнейших Delphi конференций Европы в Италии, на родине Марко Канту. Это очень важный шаг в истории развития проекта, потому как библиотека постепенно выходит на международный уровень. Возможностью рассказать о себе широкому кругу иностранных разработчиков мы обязаны нашему клиенту из Италии @claudio.piffer, который сам проявил инициативу и подготовил интереснейшую презентацию о  FGX Native. В данной презентации  Клаудио расскажет о главных возможностях библиотеки и поделится своими впечатлениями об её использовании. 
    От всего сердца желаем Клаудио удачи и с нетерпением ждём его выступления.
    Ниже опубликована вся информация о конференции.
    P.S. Выступление будет на итальянском.
    Когда: 11 июня 12:30 (по московскому времени) Программа конференции: https://www.delphiday.it/ Язык: итальянский Заголовок: FGX Native: мобильная альтернатива FMX Спикер: @claudio.piffer  Анонс:
  7. Yaroslav Brovin
    Всем доброго дня!
    Как и обещал ранее, перед релизом 1.4.0.0 выкладываю инструкцию о миграции использования старого Android-Delphi моста на новый в 1.4.0.0. Это руководство актуально тем разработчикам, которые используют Android Api в своих проектах. В этой статье я рассмотрю только те аспекты в работе моста, которые изменились.
    По большей части изменения были необходимы только в свете поддержки RAD Studio 10.4, в которой была полностью удалена поддержка модели памяти ARC.
    1. Создание Java объекта:
    Было:
    var Intent: TJIntent; Intent := TJIntent.Create; Стало: 
    var Intent: JIntent; Intent := TJIntent.Create; Все объявления переменных, атрибутов и тд должны быть теперь именованы без префикса "T". TJActivity -> JActivity.
    2. Передача Java объектов через Java интерфейс:
    Было:
    // Декларация метода. Принимает атрибут интерфейсного типа CharSequence. TJTextView.setError(const AArg0: JCharSequence); // Java cтрока TJString реализует интерфейс JCharSequence. Поэтому передача идет напрямую (в старой версии моста). View.setError(StringToJString(Control.Error)); Стало:
    // Декларация метода. Принимает атрибут интерфейсного типа CharSequence. TJTextView.setError(const AArg0: JCharSequence); // Теперь обертка Java cтроки TJString НЕ реализует явно интерфейс JCharSequence. Поэтому необходима явная конвертация JString -> JCharSequence View.setError(TJCharSequence.Wrap(StringToJString(Control.Error))); // Или можно воспользоваться хелпером из FGX.Helpers.Android.pas View.setError(StringToJCharSequence(Control.Error)); 3. Работа с Java массивами:
    При создании экземпляра Java массива (TJavaArray<T>) вся работа теперь осуществляется через интерфейс IJavaArray<T>.
    Было:
    var Points: TJavaArray<Single>; Points := TJavaArray<Single>.Create(0); FCanvas.drawLines(Points, FStroke); Стало:
    var Points: IJavaArray<Single>; Points := TJavaArray<Single>.Create(0); FCanvas.drawLines(Points, FStroke); 4. Работа с Java-листенерами:
    Если вы реализовывали свои листенеры через наследование класса Java.Bridge.TJavaLocal, то в 1.4.0.0 листенеры теперь поддерживают счетчик ссылок через Delphi IInterface. Это значит, что при создании листенера, его необходимо сохранять в переменную/поле интерфейсного типа, а не объектного.
    Было:
    TfgAndroidCameraStateListener = class(TJavaLocal, JCameraStateListener) private [Weak] FCamera: TfgAndroidCamera; public constructor Create(const ACamera: TfgAndroidCamera); { JCameraStateListener } procedure onClosed(const AArg0: JCameraDevice); procedure onDisconnected(const cameraDevice: JCameraDevice); procedure onError(const cameraDevice: JCameraDevice; const errorCode: Integer); procedure onOpened(const cameraDevice: JCameraDevice); end; var FStateListener: TfgAndroidCameraStateListener FStateListener := TfgAndroidCameraStateListener.Create(Self); FStateCallback.setListener(FStateListener); Стало:
    TfgAndroidCameraStateListener = class(TJavaLocal, JCameraStateListener) private [Weak] FCamera: TfgAndroidCamera; public constructor Create(const ACamera: TfgAndroidCamera); { JCameraStateListener } procedure onClosed(const AArg0: JCameraDevice); procedure onDisconnected(const cameraDevice: JCameraDevice); procedure onError(const cameraDevice: JCameraDevice; const errorCode: Integer); procedure onOpened(const cameraDevice: JCameraDevice); end; var FStateListener: JCameraStateListener FStateListener := TfgAndroidCameraStateListener.Create(Self); FStateCallback.setListener(FStateListener); В противном случае, экземпляр листенера FStateListener будет удален сразу же после вызова 
    FStateCallback.setListener(FStateListener); Что в свою очередь приведет к последующим падения приложения. Так как сработает механизм подсчета ссылок Delphi интерфейсов. 
    5. Конвертация string <-> JString:
    До RAD Studio 10.4 мобильные компиляторы поддерживали добавление операторов неявного преобразования. Это в свою очередь позволило нам реализовать автоматическую конвертацию "на лету" Delphi string <-> Java JString. В 10.4 эту возможность убрали вместе с ARC, так как неявное преобразование реализуется через ARC. Поэтому теперь нужно явно вызывать преобразование строк через StringToJString и JStringToString:
    Было:
    TjUri.parse('tel:+'); Стало:
    uses FGX.Helpers.Android; TJUri.parse(StringToJString('tel:+')) Это все изменения, которые необходимо сделать.
×
×
  • Create New...