Разработка мобильных приложений в Embarcadero FireMonkey (FMX 6)

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

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

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

    FireMonkey — это продукт небезызвестной компании Embarcadero. FireMonkey входит в состав среды разработки RAD Studio. Лежащий в его основе движок FMX был когда-то разработан нашим соотечественником, и представляет собой похожий на Flash или WPF, кросс-платформенный фреймворк для построения пользовательских интерфейсов. При этом, как и упомянутые продукты, FMX использует векторную графику и аппаратную акселерацию. Продукт появился всего несколько лет назад, но за это время вышло уже 5 обновлений. Хочется верить, что продукт не постигнет участь печально известного Delphi .NET.

    Приложения компилируется напрямую в машинный код, и это является одной из главных отличительных особенностей рассматриваемого решения. В связи с этими замечательным обстоятельством, Embarcadero, в теории, обещает нам общую производительность на уровне нативных приложений. Будучи встроенным в Delphi и в С++ Builder, FireMonkey позволяет реализовывать логику приложений на Pascal и C++. Один и тот же код приложения FireMonkey (FM) может быть скомпилирован для работы в Windows, iOS и Android. Нас привлекла возможность вести разработку на C++, так как в штате компании имелось большое количество программистов по этому направлению. Поэтому для проверки работоспособности был установлена именно C++ Builder версия RAD Studio XE6, хотя редакция Delphi не должна отличаться ничем, кроме используемого языка программирования.

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


    Имея за своей спиной бурное прошлое, связанное с созданием компиляторов, производитель снарядил FireMonkey нативными компиляторами С++ для x86 и ARMv7. Это позволяет выполнять компиляцию непосредственно на компьютере, где запущена среда разработки. Именно наличие собственных компиляторов и дает нам возможность программировать на C++ или даже Pascal, получая необходимый машинный код ARM на выходе. Однако для сборки приложения (link), подписывания, запуска на устройствах и отладки по-прежнему используется оригинальный инструментарий из средств разработки (SDK) мобильных платформ. Таким образом, перед началом работы вам всё равно потребуется выполнить следующие действия:

    iOS Android
    Иметь Mac ---
    Зарегистрироваться в iOS Developer Program Зарегистрироваться на сайте Android Developer
    Получить сертификаты (developer, provisioning) Сгенерировать ключ для подписи приложений
    Скачать и установить iOS SDK Скачать и установить Android SDK и NDK
    Скачать и установить PAServer на Mac ---
    Настроить соединение между RAD Studio и PAServer ---

    Поскольку и RAD Studio и инструментарий Android работают на PC, то для разработки под Android требуется несколько меньше телодвижений, чем для iOS. Для сборки iOS приложений требуется Mac OS (так как только для неё Apple выпускает SDK). Таким образом, если разработка приложения проходит на PC, они должны как-то связываться. Из приведенный ниже диаграммы видно, как при помощи поставляемого Embarcadero PAServer (Platform Assistant Server) осуществляется сборка приложений iOS через PC:



    Пример


    В рамках пробы FireMonkey мы разработали простое приложение (на уровне Hello world), на примере которого хотелось проверить работоспособность предлагаемой технологии.

    Ниже приведен скриншот версии этого приложения для Windows и небольшой видеоролик, чтобы можно было увидеть его нехитрую работу в динамике:

    image


    Наше приложение почти не содержит кода. Тем не менее, расскажем, что именно мы делали.

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

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

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

    Обработчик поворота колеса:
    //---------------------------------------------------------------------------
    void __fastcall TForm1::DialAngleChange(TObject *Sender)
    {
    	// Every time the angle dialer is spinned, assign
    	// its current value to the Image control...
    	imgLogo->RotationAngle = 360 - DialAngle->Value;
    
    	// The progress bar will get updated with a normalized angle value
    	pbAngle->Value = (int)fabs(DialAngle->Value)%360;
    }
    //---------------------------------------------------------------------------
    

    Как видно, это обычный C++, но немного «запачканный» наследием Delphi.

    Ниже расположена традиционная кнопка (которая, впрочем, не так уж и похожа на кнопку) со следующим HW обработчиком:
    //---------------------------------------------------------------------------
    void __fastcall TForm1::btnHelloClick(TObject *Sender)
    {
    	// A simple HW assignment
    	btnHello->Text = "Hello world!";
    }
    //---------------------------------------------------------------------------
    


    Правее виднеется поле для выбора даты (DateTimePicker). Нас интересовал, прежде всего, его внешний вид на мобильных ОС: будет ли в каждом случае использован нативный элемент управления или что-то рисованное. По этой же причине ниже следует ползунок и переключатель ВКЛ./ВЫКЛ. Этот переключатель, однако, обрел еще одну функцию: он включает один из стандартных визуальных эффектов FMX (радиальное размытие): нам хотелось посмотреть, рисует ли FMX элементы управления сам или делегирует эту работу мобильной ОС. Ниже мы еще вернемся к этому вопросу, так как результат оказался не очевидным.

    В самом низу размещена таблица с двумя колонками. Таблица имеет отчетливые черты desktop приложения, хотя и с инерционной прокруткой. Нам хотелось посмотреть: каково будет ей пользоваться на мобильном телефоне. Таблица заполняется на старте приложения, просто, чтобы глазу было за что цепляться:
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
    	: TForm(Owner)
    {
    	// Initialize the string grid with a bit of texts
    	// Define the number of items
    	gdDemo->RowCount = 1000;
    
    	// Generate the texts for every Row and Column
    	for(int r = 0; r < gdDemo->RowCount; r++)
    	{
    		gdDemo->Cells[0][r] = "iResearchFX";
    		gdDemo->Cells[1][r] = IntToStr(r+1);
    	}
    }
    //---------------------------------------------------------------------------
    


    Компиляция



    Компиляция проходит весьма неспешно — по своему обыкновению C++ Builder делает это как-то натужно. Всё же, долгие годы не сделали их компилятор C++ ни чуть не быстрее.

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

    Переключения платформы осуществляется без особых усилий — в IDE этот аспект интерфейса сделан нарочито и бескомпромиссно. Вы должны выбрать: Debug или Release компиляцию, целевую платформу, симулятор или устройство, и отдельно пометить осуществляется ли сборка для внутренних нужд или для публикации. В последнем случае от вас потребуются сертификаты для подписывания. Сертификаты Android, если у вас их еще нет, вам тут же любезно предложат генерировать прямо из среды разработки; ну, а iOS профили должны стоять на том Mac, где будет выполняться заключительный этап сборки.

    Легко видеть, что в разделе Android перечислены все симуляторы, настроенные в Android SDK, а так же все подключенные устройства.

    В разделе iOS опции в точности повторяют набор из XCode — это и не удивительно, учитывая, что сборка и запуск симулятора будут выполнены на удаленной машине Mac OS.



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

    Как нетрудно заметить — и это отрадно — внешний вид почти не изменился, точнее, напротив: приложение непостижимым образом изменилось, но выглядит оно теперь точно так же, как если бы мы делали его интерфейс с нуля для каждой из платформ. В этом и состоит тот соблазн, ради которого мы хотели проверить FMX. Походит на восторг от первого использования Qt!

    Видно, что это по-прежнему то же самое приложение, но все элементы управления сменились на «родные» для каждой из платформ. Именно это, по нашему мнению, и можно было бы назвать подлинно кросс-платформенной разработкой GUI приложений.

    Мобильное приложение уже готово! Предлагаем вам посмотреть на его работу в живую на примере экранного видео, сделанного на физическом Android устройстве (HTC One). Видео почти идентичны, мы сделали два ролика для статистики.

    На видео заметны некоторые аспекты работы нашего приложения.
    1. Время запуска. Считается, что все приложения на Android-e запускаются не очень быстро, если мы говорим о «холодном» запуске. Здесь же прекрасно видно, что мы теряем около 2 секунд на старте (черный экран в самом начале видео). Много это или нет — решать Вам, но, по нашему мнению, это сильно зависит от типа приложения.
    2. Скорость работы. Тут особых нареканий нет — интерфейс работает вполне ладно.
    3. Элементы управления. Все элементы заменены на нативные и производят вполне Андройдовское впечатление.
    4. Grid. Выглядит интересно для мобильной платформы и, вполне, рабочий — есть даже inplace редактирование ячеек.


    Post-mortem



    Давайте посмотрим, что собой представляет изнутри наше свежесобранное приложение Android.

    APK архив имеет весьма ощутимый размер в 6 Мб. Видимо, по старой традиции Delphi, в него затянули всю runtime библиотеку.

    Внутри APK архива мы видим следующую структуру папок (показано справа). В глаза бросается наличие динамических библиотек (so), как бы намекающее нам на то, для чего именно использовался родной компилятор ARMv7 и NDK.

    Обратим внимание на то, что папка lib содержит вложенные папки с названием архитектуры, и в каждой из них лежит наше приложение, названное отчего-то libProject1.so. Так вот, только в папке armeabi-v7a оно настоящее, и имеет размер порядка 21 Мб (в распакованном виде). Остальные же файлы библиотек представляют собой готовые хлопушки-заглушки, которые выстреливают в лицо пользователю сообщением, если его архитектура отличается от ARMv7. В этом производитель честно признается и не оставляет нам пока ничего иного.

    Файл classes.dex содержит совсем не наше приложение, а Java загрузчик для основного FMX приложения-библиотеки и реализацию оберток для нативных элементов управления Android. Именно этот фрагмент и позволяет приложению взаимодействовать с ОС и «прикидываться» обычным приложением Android.

    Степень нативности


    Как становится заметным на видео, эффекты FMX продолжают прекрасно действовать и на «родные» элементы управления Android, вмешиваясь в их отрисовку (например, мы даже включали свечение контуров у элементов управления, а это означает, что FMX работает с Android элементами управления не просто как с картинками, а очень даже плотно).

    Себастьян Гингтер (SEBASTIAN P.R. GINGTER) в своей широко известной статье по FMX отзывается о фреймворке очень нелестно, критикуя, как раз, то, что пользовательский интерфейс рисуется независимым образом и не выглядит нативно ни на одной из платформ. По всей видимости, в какой-то момент, это было именно так, но сейчас такую критику нельзя считать справедливой. Автор отрицает саму идею кроссплатформенных GUI приложений, без оглядки на конкретные реализации, отрицая потенциальные преимущества такого подхода.

    Заключение


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

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

    Использованные материалы:


    1. Документация Embarcadero
    2. Описание процесса разработки в FM
    3. ARM заглушки в XE6
    4. Критика не нативного интерфейса
    Поделиться публикацией

    Комментарии 10

      0
      Интересно, а как происходит взаимодействие с сенсорами телефона (акселерометр например) или с NFC модулем? И как реализована система запроса разрешений (или тут тоже присутствует манифест)?
        0
        Локация определяется легко — есть кроссплатформенный класс TLocationSensor. У него два состояния ВКЛ/ВЫКЛ. Есть возможность проверить доступен он или нет: свойство Active (false/true)

        Нужно активировать его, когда требуется и далее слушать событие OnLocationChanged. Например, так:

        //---------------------------------------------------------------------------
        void __fastcall TForm2::LocationSensor1LocationChanged(TObject *Sender, const TLocationCoord2D &OldLocation,
        		  const TLocationCoord2D &NewLocation)
        {
        	AnsiString s;
        	s.sprintf("%2.6f", NewLocation.Latitude);
        	lblLatitude->Text = s;
        	s.sprintf("%2.6f", NewLocation.Longitude);
        	lblLongitude->Text = s;
        
        }
        //---------------------------------------------------------------------------
        


        Что касается остальных датчиков, то там есть целый зоопарк (мы их все не проверяли): TLightSensor, TMotionSensor, TBiometricSensor, TElectricalSensor и проч.

        Есть возможность занумеровать все датчики в системе по их типу используя метод TSensorManager::Current::GetSensorsByCategory.

        Что касается манифеста:
        Вы можете зайти в настройки проекта Project options-> User settings и выбрать требуемое. Там всё наглядно: галочками. Скрин ниже:
          0
          Ошибка: Active просто включает или выключает, а проверить текущее состояние, т.е активность датчика, кажется, можно через энумерацию всех датчиков.
        0
        «Хлопушки-заглушки», выстреливающие пользователю x86-планшета (с встроенным неплохим эмулятором armv7) — это, конечно, то о чём все всю жизнь мечтали. Кому этого хорошо-то становится?
          0
          Пока только 7ка АРМа. Но, вы знаете, насколько нам известно, 6-я версия уже мало где стоит сейчас…

          А, вот, насчёт x86 — вопрос актуальный. Некоторые производители железа сейчас подумывают перенести свои решения с арма на Intel (Всё же, в 5 раз быстрее работает (...))

          В общем, на мобильных пока так.
            0
            Я про другое. Если приложение содержит в себе только ARM'овские библиотеки, то при попытке запустить его на x86 Android-устройстве запустится довольно-таки неплохой эмулятор и всё работает как нужно. Пользователь даже не узнает, что приложение x86 кода не содержит.

            А вот если кому-то в голову пришла идиотская идея засунуть туда x86-заглушку, то именно она и будет вызвана. И ничего работать не будет.

            И кому от этой деятельности стало хорошо? Кто мешал положить только ARM'овые библиотеки и всё?
          0
          А как насчёт Windows Phone? Можно ли создавать приложения сразу и для этой платформы?
            0
            Насчёт, Windows Phone пока никак… Есть Win32, iOS и Android.

            Не сказать, чтобы WinPhone был особо востребован (на данном этапе), но для общности его в FMX не хватает. Досадно, конечно, но у них, видимо, руки пока не дошли.

            А хотелось бы увидеть…
            0
            Радует, радует душу эта вот старая как мир, ненастраиваемая по длине
            //---------------------------------------------------------------------------
              0
              Да, она появилась на заре, еще в первых версиях. Видимо, Borland Embarcadero она тоже радует душу.
              И самое главное, что выключить её тоже нельзя.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое