пятница, 27 декабря 2013 г.

DeployFolder - Развёртывание мобильного подкаталога

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>}
{$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 новые файлы задваиваются. Поэтому я закрываю проект после добавления новых файлов и вызываю инструмент без параметров. Обычно, когда работа идёт над одним и тем же проектом, никаких неудобств не возникает - имя проекта сохраняется.

Кстати. Я стал задумываться, не сделать ли каталогам псевдонимы, например c:\mo\x=\x. Что вы об этом думаете? Есть у вас ещё предложения? Пишите мне – alhymov@mail.ru

И да, ВНИМАНИЕ, УВАГА, ATTENTION, ACHTUNG: При формировании для Андроид списка дополнительных файлов Delphi (или SDK?) формирует список, где имена каталогов в нижнем регистре! Имена самих каталогов в пакете приложения при этом остаются в том регистре, в котором вы написали на вкладке Project|Deployment. При старте приложения на устройстве происходит выгрузка файлов из пакета приложения в "песочницу". И, поскольку имена каталогов в списке и в пакете не совпадают, приложение даже не проходит строчку begin в проекте. Будьте бдительны! А в моей программе это обстоятельство уже учитывается.
---
ошибка занятости файла судя по всему связана с тем, что проект хранится в DropBpox. Т.е. как только файл изменился, его начинают тащить в сеть и, видимо, для этого блокируют. Т.е. надо перед первой записью самому файл захватить и отпустить только после второй записи. Если кто-то сразу мне кинет ссылку на блокировку файла, буду признателен. Но я скорее всего пойду по другому пути - однократной записи. Т.е. ХМL записать в поток и считать его уже оттуда в StringList, а не из файла. И уже потом сохранить один раз. Пока руки не дошли.**
---
** Руки дошли - см. DropBox против файлов http://alhymov.blogspot.ru/2014/02/dropbox.html