пятница, 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

5 комментариев:

  1. Если бы этот пост был написан и попался бы мне пару недель назад, то сэкономил бы уйму времени. Я тоже искал способ добавлять файлы в обход Depolyment manager-a, но когда обнаружил что файлы хранятся в .dproj файле - отказался от этой идеи.
    Очень приятно видеть, что работающий подход существует.

    ОтветитьУдалить
  2. Чесгря потрясён, что это кто-то прочёл. Я писал на эту тему в эмбаркадеровские публикации, думал читают там. Я сам там читал одно время. А сейчас просто гуглю.

    ОтветитьУдалить
  3. Я случайно наткнулся в поисковике =) А оказалось в тему =)

    ОтветитьУдалить
  4. Павел, спасибо за пост. Скажите, этот подход для чего был продуман? Можно ли его использовать для сторонних библиотек (.so, .dll, .dylib)? Есть ли работающий пример? Сам хочу покопаться, но пугает неопределенность и не знаю с чего начать.

    ОтветитьУдалить
    Ответы
    1. Утилита сделана для разложения дополнительных файлов, которые хочется включить в приложение. Например - файл конфигурации с предустановками, какое-нибудь изображение, музыку и т.п. Поэтому автоматически ставится путь "Документы приложения". Работающий пример - WhoIsWho в предыдущем посте. Там Примерно 1000 фото для досье. Что касается исполняемых файлов, то такие случаи у меня не возникали. Советую провести эксперимент и рассказать общественности. Кроме того, доступные исходники можно скорректировать по своему усмотрению, чтобы для разных расширений использовать разные папки.

      Удалить