Разработка кроссплатформенных мобильных приложений в Delphi #1
Как вы, наверное, знаете, в сентябре этого года компания Embarcadero Technologies представила очередной релиз RAD Studio, набора средств разработки, включающих в себя Delphi, C++ Builder, HTML5 Builder и ряд сопутствующих продуктов. Основное новшество RAD Studio XE5 состоит в том, что с помощью Delphi стало возможным вести разработку нативных приложений для Android – самой популярной на текущий момент мобильной платформы.
Предыдущие версии Delphi уже поддерживали разработку для Mac OS (XE2, XE3, XE4) и для iOS (XE4). Поэтому сейчас мы не говорим о том, что кроссплатформенная разработка стала «изюминкой» новой версии Delphi. Однако, по отношению к разработчикам приложений, Android по-настоящему демократичная система. Здесь не требуется ни дорогостоящего оборудования (как в случае с iOS), ни покупки сертификатов разработчика (возможность публиковать приложения в GooglePlay стоит всего $25, возможность отладки на своем Android устройстве абсолютно бесплатна).
Таким образом, если вы имеете некоторые навыки работы в Delphi, то именно сейчас у вас появилась прекрасная возможность попробовать себя в мобильной разработке.
Говоря о Delphi, следует упомянуть и C++ Builder. Обычно оба эти продукта развиваются параллельно. Однако, на этот раз Delphi, выражаясь спортивным языком, «немного вырвался вперед» и пользователям C++ Builder приходится некоторое время ожидать пока их средство разработки «подтянется к лидеру».
Многие Delphi разработчики со стажем ассоциируют Delphi с VCL – мощной расширяемой библиотекой классов, предназначенных для создания широчайшего спектра приложений для Windows. Однако, как вы знаете, или успели догадаться, для создания кроссплатформенных приложений используется не VCL, а платформа приложений FM, ранее известная как FireMonkey.
С точки зрения IDE FM, это, прежде всего, новая библиотека визуальных классов (элементов управления). С ее помощью можно создавать качественные пользовательские интерфейсы практически для любых видов программ. При этом среди прочего «в коробке» поставляются также и объекты для работы с 3D графикой, что позволяет задействовать FM для решения целого ряда специфических задач, таких как моделирование физических процессов, создание наглядных учебных пособий и т.д. Многие из компонентов, представленных в FM, имеют свои VCL аналоги. Однако, далеко не все.
В отличие от VCL, FM является «абстрактной» прикладной платформой. Ранее визуальные библиотеки классов обрабатывали соответствующие элементы операционной системы. В VCL, например, компонент «TButton» является оболочкой элемента управления Windows Button (кнопка). Вместо этого, в FireMonkey появилось абстрактное понятие кнопки, к которой могут применяться различные стили, для того чтобы она выглядела нативной под различными платформами, или использовала полностью настраиваемый стиль пользовательского интерфейса.
В то время, как другие библиотеки абстрагируют пользовательский интерфейс, FM привязывается непосредственно к нативной графической библиотеке, предлагая наилучшее решение с точки зрения использования GPU на целевой платформе.
Еще один момент, который следует затронуть, это сам термин «кроссплатформенность» в контексте мобильных приложений. Совершенно очевидно, что мобильные платформы используют специфичный набор элементов управления для организации пользовательского интерфейса. И по этой причине принципы построения классических настольных приложений в большинстве случаев не применимы в мобильной разработке.
Конечно, описанный выше принцип абстрагирования интерфейса во многих случаях решает проблему. Однако, далеко не всегда. И, говоря о кроссплатформенном приложении, мы не подразумеваем единое приложение для различных платформ. Мы говорим о единой кодовой базе в разных приложениях. И здесь очень важным становится правильное построение архитектуры приложения, а именно, максимальное разделение интерфейсной и логической части.
На сегодняшний день платформа FM поддерживает следующие операционные системы: Windows (Win32 и Win64), OSX, iOS и Android.
Для разработки мобильных приложений (для iOS и Android) в Delphi используется так называемый модульный компилятор LLVM. В контексте кроссплатформенной разработки это дает неоспоримое преимущество. Модульный компилятор разделен на две части: front-end и back-end. Front-end компилятора переводит исходный код программы конкретной в универсальный платформонезависимый виртуальный код (байт-код). Back-end обрабатывает полученный байт-код и преобразовывает его непосредственно в машинный код конкретной платформы. Back-end LLVM поддерживает целый ряд различных платформ, что в будущем даст возможность RAD Studio расширить список поддерживаемых платформ.
В контексте разработки бизнес-приложений так же следует упомянуть и о механизмах доступа к базам данных. Действительно, работа с БД всегда была сильной стороной Delphi, и вполне логично было бы ожидать, что мобильные Delphi приложения будут работать с базами так же хорошо, как и настольные.
Совсем недавно, весной этого года, комплект поставки старших редакций Delphi/RAD Studio пополнился новой библиотекой доступа к данным – FireDAC, созданной на базе хорошо известного решения AnyDAC, созданного и долгое время развиваемого Дмитрием Арефьевым. FireDAC является универсальным набором компонентов, поддерживающим доступ к весьма внушительному списку СУБД. И если мы говорим о настольных приложениях, то платформа FM с помощью FireDAC поддерживает практически все популярные СУБД. Что же касается мобильных приложений, то здесь существуют определенные ограничения, связанные, прежде всего, с отсутствием библиотек доступа к большинству СУБД. Так мобильные Delphi приложения будут поддерживать SQLite (родная СУБД как для iOS, так и для Android) и IBLite/IB ToGo. Но напрямую подключиться, например, к Oracle уже не получится.
Тем не менее, существует возможность создания мобильных клиентов с помощью многозвенной технологии DataSnap. Эта технология не нова и довольно хорошо себя зарекомендовала среди разработчиков.
И, коль скоро мы затронули тему работы с базами данных, следует упомянуть об одном из ключевых отличий FM и VCL приложений. Для отображения данных в VCL обычно используются специальные элементы управления, так называемые DB-контролы. Для FM такие элементы управления не реализованы и для отображения данных используются обычные элементы управления. Связь между данными и элементами управления производится при помощи механизма Live Binding. И хотя Live Binding интуитивно понятен, прост в изучении и полностью визуализирован, работа с этой технологией все же требует некоторых навыков.
Из всего вышесказанного следует, что мобильная разработка в Delphi довольно существенно отличается от «классической». И сейчас имеется некоторый дефицит технической информации, посвященной именно мобильной разработке в Delphi
Хотя подобная ситуация, в принципе, характерна для любой интенсивно развивающейся технологии.
Данная статья открывает цикл публикаций, посвященных созданию мобильных приложений в Delphi. Мы надеемся, что этот цикл поможет вам не только познакомиться с возможностями новой среды разработки, но и разобраться с основными техническими вопросами, которые могут вызвать сложность.
В следующей части мы перейдем от слов к делу. Для рассмотрения будет выбрана абсолютно реальная задача, и мы попытаемся пошагово рассмотреть процесс создания FM приложений для разных платформ.
Источник
Delphi XE5 + Android: первые впечатления
Возвращение к истокам
Delphi XE5 я взял в руки по случаю конкурса «Осенняя Мобилизация». Идея (и возможность) писать под Андроид не на си-шарпе или яве, а на знакомом вдоль и поперёк паскале мне определённо понравилась. Расскажу тут о своих впечатления, проблемах, которые встретились, а также развенчаю некоторые «городские легенды».
Использовал триал-версию Update-1. Теперь уже вроде второй апдейт вышел и, возможно, что-то поменялось. Сразу замечу, что менять в установке настройки по умолчанию лучше не стоит. Установленный до этого Андроид-SDK прицепить к Делфи не удалось, поэтому ставил заново с тем, который к ней прилагается. После первого запуска выяснилось, что не работает Хелп. Нашёл решение
support.embarcadero.com/article/43035
Хелп оказался толковый и довольно подробный. Содержит не только свойства и методы, но и примеры и даже описание методик разработки. В общем, возвращение к истокам, как оно было ещё у Борланда.
Cама среда мне очень нравится. В Визуал Студио всё какое-то аморфное и невнятное. Юнити визуально неплох, но там совсем другая специфика. Короче – язык программиста всё равно не опишет то, что видит глаз эстета, даже если они принадлежат одному человеку…
Интерфейс пользователя
FireMonkey порадовал своей гибкостью. На любой контрол можно повесить другой, на тот ещё один, и так далее, достигая очень интересных результатов. По сравнению с VCL стандартизовано именование свойств. Никаких больше Caption’ов и прочего, если где-то есть текст – это всегда Text. Позиция – всегда Position. Масса способов выравнивания. Кроме того, есть TLayout – нечто «невещественное» (об этом будет и ниже), невидимое, на что можно положить контролы и выравнивать их «в пустоте», а не обязательно на какой-нибудь панели.
Когда много всего на форме, становится очень полезным свойство DesignVisible – скрыть в дизайн-тайме. Набор стилей для Андроида прилагался только один, но очень элегантный – белым по чёрному, как мне нравится.
В инете ходят слухи, что ссылки на стиль для контрола (StyleLookup) иногда «не сохраняются». Для многих типов контролов (а может и для всех) существует для каждого своя ссылка «по умолчанию», которая будет назначена, даже если не указана, и которая-то и не сохраняется, как я понимаю, для экономии места в ресурсе формы.
Контролу можно добавить анимацию, и даже несколько, и даже одновременно. И это не только перемещение по экрану, но и изменение любых вещественно-численных свойств (размеров, цвета, масштаба и т.д.). Для каждой анимации можно указать временную задержку её начала, что очень удобно в сложных случаях, т.к. можно обойтись без дополнительных таймеров, просто запустив все нужные анимации одновременно из одного блока кода.
Теперь о жестах. В принципе всё просто – назначаем контролу Touch.GestureManager, галочками помечаем интересующие жесты, назначаем искусственное расширение границ ловли жестов (если контрол мелкий) в TouchTargetExpantion, создаём для него событие OnGesture и ловим там по EventInfo.GestureID нужный жест. Но есть тонкости.
Например, на большом TLayout мы разместили какие-то мелкие (относительно него) контролы и независимо от того, насколько «попал» пользователь пальцем по этим контролам своим жестом, надо что-то там делать. Замечу – если всё описанное в абзаце выше сделано для этого TLayout, то мы поймаем только те жесты, начало которых приходится на «видимые» объекты – т.е. на один из тех самых мелких контролов. Это я определил экспериментально. В принципе ничего удивительного – лайоута-то как бы и нет, он невидим и виртуален, и все «экранные сообщения», которые он может получить – от положенных на него «видимых» объектов. Можно сделать по-другому — не лениться, назначить менеджера и создать событие для формы (как и делается в демках) и гарантированно его всегда получать – но тогда придётся вручную разбираться с координатами, чтобы определить, к какому контролу какой жест относится.
Ещё именно под Андроидом я бы настоятельно порекомендовал явно проверять GestureID каждого пойманного жеста и реагировать только на те, которые интересуют (независимо от того, какие жесты помечены галочками).
И пример. Долго не мог сообразить, как показать баннер в TWebBrowser. Решение нашёл на одном форуме и творчески переработал. Но, если быть уж совсем точным, не до конца. Практикующие перфекционисты могут поразвлечься и этот недочёт поискать. Однако код при этом абсолютно рабочий и именно его я использую:
HTML тут – это код этого самого банера.
Базы данных
В XE5 включён набор компонентов для универсального доступа к базам данных – FireDAC. В принципе все названия свойств и методов как у других аналогичных наборов, так что тут всё ясно. Я использовал его для общения с SQLite. Всё настолько просто и обычно, что даже не знаю, что рассказать. К тому же и не помню ничего – в это время смотрел что-то по медиаплейеру, руки сами всё сделали.
Чтобы почувствовать разницу, желающие могут для сравнения после FireDAC сделать что-нибудь с базой данных из программы на той же Юнити. Да ладно Юнити, она игровая, – вон из той же Визуал Студии. После этого начинаешь понимать, где пули свистят, а где туземки коктейли разносят…
Ну и для любителей делать всё своими руками приведу небольшой пример, как заполнять ListBox без Bindings:
Кроме всего прочего, в зависимости от кода в столбце d_result в строчку лист-бокса помещается та или иная картинка:
Главное, что тут не забыть – это aList.AddObject(aItem);
Ну и Next, конечно, чтобы не зависло.
Манипуляции с формами
То, к чему приучает Делфи – это каждому действию свою форму. Под Андроидом в ней можно точно так же, как и под Виндоуз, создавать, показывать и закрывать формы. Каждая новая так или иначе созданная и показанная форма будет как бы «модальной», т.е. закрывающей всё пространство приложения. Однако Form.ShowModal делать не следует (Андроид этого «не понимает»), а следует по старинке просто вызывать Form.Show. По системной кнопке Back автоматом вызывается Form.Close и самая верхняя на данный момент форма закрывается. Можно её потом опять использовать. При закрытии главной (первой) формы приложение, как и следовало ожидать, закрывается. Замечу, что не следует закрывать форму с параметром caFree либо явно её уничтожать (Free, Release) – не любит Андроид этого!
Читал в инете про проблемы у людей с ARC. Уверен, дело не в этом. Если всё правильно спроектировано, то вообще без разницы, считаются ссылки или нет, ходит там сборщик мусора с косой по расписанию как в .Net или уничтожается сразу как в Delphi. Я всё писал по-старинке:
и работало как часы и под Андроидом, и под Виндами.
Если же возникают какие-либо проблемы с пониманием этого процесса, без всякого стёба рекомендую немного пописать на си-шарпе. Там вообще деструкторы явно вызывать не принято, просто или выходишь из процедуры, где данный объект был локальной переменной, или присваиваешь (глобальной) переменной значение null. Через некоторое время уже спинным мозгом начинаешь чувствовать момент, когда ладьи с объектами отправляются в Вальгаллу, причём безо всякого с твоей стороны толчка.
Массивы
При разработке под мобильный компилятор в руководстве по адаптации кода сказано «не использовать статические массивы». Указано также одно исключение – когда статический массив является членом структуры. И всё. Не совсем ясно, относится ли это к константам-массивам. Например, таким как
Не исключено, что так делать можно, хотя я такого старался избегать и формировал массивы строк в initialization динамически. В си-шарпе там хоть это можно в описании делать… Короче, вопрос требует дальнейшего исследования и разъяснения.
Следует также помнить, что элементы строки (string) в мобильном компиляторе нумеруются с нуля.
Операторы
Появился (уж не знаю в какой версии) новый оператор
Похоже, все языки стремятся к общему знаменателю. Кстати, перебирать им в паскале можно не только массивы, но и множества.
Источник