DeployFolder - Развёртывание мобильного
подкаталога
Автоматическое
прописывание пути развёртывания файла для мобильного приложения.
Для конкурса Embarcadero "Осеннее настроение 2013" исходник выложен в папку с программой, разработка которой без DeployFolder была бы совершенно невозможной: https://subversion.assembla.com/svn/who-is-who/trunk/WhoIsWho
Вы можете отдельно взять исходный код программы здесь: https://db.tt/YAOLB40g. Но я не гарантирую, что оставлю его без изменения.
Итак, с чего началось создание программы - с простого вопроса: как добавить файл в проект мобильного приложения? Казалось бы, есть простой ответ: Project|Deployment и Add Files. Так? Не совсем. Вам ещё следует прописать каталог, в который файл попадёт на мобильном устройстве. Доступ к этому файлу в коде будет выглядеть примерно так:
DataDir :=
{$IF Defined(MSWINDOWS)}
'..\..'{runing in windows - <Platform>\<Configuration>}
'..\..'{runing in windows - <Platform>\<Configuration>}
{$ELSE}
TPath.GetDocumentsPath
{$ENDIF}
+PathDelim + 'Data' +
PathDelim;
В данном случае 'Data' – это имя подпапки, в которой лежат мои файлы для приложения внутри папки проекта. А что значит TPath.GetDirectory – зависит от мобильной системы. Для iOs – это '.\StartUp\Documents', а для Android – ‘.\assets\internal’.
К сожалению, эти константы вы вынуждены вносить вручную для кучи разных конфигураций. Не вздумайте что-нибудь забыть или перепутать – приложение может не найти ваш файл после запуска на устройстве или в эмуляторе! Это не очень удобно, не правда ли? Давайте немного облегчим себе жизнь и заполним пути автоматически. Тем более, если количество добавленных файлов больше одного!
Итак, где хранятся пути развёртывания файла? Нет, не в <ProjectName>.deployproj, а в <ProjectName>.dproj! По правде говоря, сначала я был немного озадачен файлом <deployproj>. С одной стороны – расширение файла «.deployproj» так и просит заглянуть в этот файл. И – да! – там перечислены все те файлы, которые были добавлены в проект. Но с другой стороны - всё, что я менял в <deployproj>, вдруг исчезало самым таинственным образом - мистика! Если вы читаете эти строки, то вы уже не попадётесь в эту ловушку. А теперь давайте посмотрим внутрь <dproj> и сравним его кусочек с таблицей Deployment <ProjectName> в IDE.
</Excluded_Packages>
</Delphi.Personality>
<Platforms>
<Platform value="Android">True</Platform>
<Platform
value="iOSDevice">True</Platform>
<Platform
value="iOSSimulator"
ActiveMobileDevice="iPad">True</Platform>
<Platform
value="Win32">True</Platform>
</Platforms>
<Deployment>
<DeployFile
LocalName="Data\896.jpg" Class="File">
<Platform
Name="Android">
<RemoteDir>.\assets\internal\Data\</RemoteDir>
<RemoteName>896.jpg</RemoteName>
</Platform>
<Platform
Name="iOSDevice">
<RemoteDir>.\StartUp\Documents\Data\</RemoteDir>
<RemoteName>896.jpg</RemoteName>
</Platform>
<Platform
Name="Win32">
<RemoteName>896.jpg</RemoteName>
</Platform>
<Platform
Name="iOSSimulator">
<RemoteDir>.\StartUp\Documents\Data\</RemoteDir>
<RemoteName>896.jpg</RemoteName>
</Platform>
</DeployFile>
<DeployFile
LocalName="Data\816.jpg" Class="File">
<Platform
Name="Android">
Без труда можно заметить, что добавленные нами файлы имеют тип “File”. В зависимости от платформы у файла может быть разный каталог размещения. Зная, что <dproj> - это в сущности XML, мы можем бросить на форму из палитры Internet компонент TXMLDocument, найти узел “\Project\ProjectExtensions\BorlandProject\Deployment” и расставить теги <RemoteDir>, в которых хранятся пути развёртывания наших файлов.
Поскольку программа, которую я написал, изначально носила скорее исследовательский характер, то перед изменением файла проекта в отдельной строке я собираю имена папок, которые собираюсь обработать с возможностью редактировать имена как в строке, так и в виде списка. Возможно, эта особенность пригодится в будущем, а возможно - нет.
Ещё отмечу, что новый путь я ставлю только для платформ из списка 'Android','iOSDevice','iOSSimulator'.
Стоит также заметить, что после обработки проекта я вставил ещё несколько действий. Во-первых - вы можете смеяться, но я не знаю, как удалить строку XML-заголовка, которая появляется в файле проекта после сохранения его компонентом XMLDocument1. Поэтому, не сильно задумываясь, я опять считываю файл на этот раз в TStringList и удаляю первую строчку. Во-вторых, моя Delphi (наткнулся на это в XE5 trial) не хочет собирать проект, если остался старый deployproj. Что ж, удалить его не сложно.
DeployFolder очень удобно поместить в IDE как инструмент c параметром $PROJECT. Этот
инструмент можно вызывать каждый раз, когда вы добавили файлы в развёртывание
проекта. Например так:
После обработки новым инструментом файла проекта Delphi сама обнаруживает изменение, и достаточно будет просто согласиться
на предложение, чтобы перегрузить проект.
Но, увы - на больших проектах происходит ошибка занятости файла*. Ещё одна проблема - при открытой странице Project|Deployment новые файлы задваиваются. Поэтому я закрываю проект после добавления новых файлов и вызываю инструмент без параметров. Обычно, когда работа идёт над одним и тем же проектом, никаких неудобств не возникает - имя проекта сохраняется.
Но, увы - на больших проектах происходит ошибка занятости файла*. Ещё одна проблема - при открытой странице Project|Deployment новые файлы задваиваются. Поэтому я закрываю проект после добавления новых файлов и вызываю инструмент без параметров. Обычно, когда работа идёт над одним и тем же проектом, никаких неудобств не возникает - имя проекта сохраняется.
И да, ВНИМАНИЕ, УВАГА, ATTENTION, ACHTUNG: При формировании для Андроид списка дополнительных файлов Delphi (или SDK?) формирует список, где имена каталогов в нижнем регистре! Имена самих каталогов в пакете приложения при этом остаются в том регистре, в котором вы написали на вкладке Project|Deployment. При старте приложения на устройстве происходит выгрузка файлов из пакета приложения в "песочницу". И, поскольку имена каталогов в списке и в пакете не совпадают, приложение даже не проходит строчку begin в проекте. Будьте бдительны! А в моей программе это обстоятельство уже учитывается.
---
* ошибка занятости файла судя по всему связана с тем, что проект хранится в DropBpox. Т.е. как только файл изменился, его начинают тащить в сеть и, видимо, для этого блокируют. Т.е. надо перед первой записью самому файл захватить и отпустить только после второй записи. Если кто-то сразу мне кинет ссылку на блокировку файла, буду признателен. Но я скорее всего пойду по другому пути - однократной записи. Т.е. ХМL записать в поток и считать его уже оттуда в StringList, а не из файла. И уже потом сохранить один раз. Пока руки не дошли.**
---