Pull to refresh

Сборка Android проекта: исключение ненужных файлов

Reading time4 min
Views4.8K
Заканчивая свой первый проект на Android я столкнулся с проблемой отсутствия достаточной гибкости при сборке релиза.

Изначально для сборки предполагается использование ant. При создании проекта платформа любезно создает вам build.xml. Как правило, вся конфигурация состоит на указании пути к Android-SDK в local.properties файле. Еще может возникнуть желание указать там key.store и key.alias параметры, чтобы приложение подписалось автоматически при сборке. Google в документации не рекомендует так делать, потому что предлагаемый в процессе сборки ввод пароля для ключа логируется в Shell.

Но что если при сборке нужно дополнительно что-либо сделать? В моем случае понадобилось исключить некоторые файлы из финального пакета, находящиеся assets/test папке. В этих файлах хранятся пути к тестовым вебсервисам и данные для авторизации. Совершенно ни к чему включать их в состав финального приложения. Решение оказалось найти не быстро, несмотря на простоту. Проблема — малое количество документации. Предлагаю заглянуть внутрь для экономии времени в будущем.


Если заглянуть внутрь build.xml, то можно обнаружить там некоторые закомментированные элементы для кастомизации:

<!-- extension targets. Uncomment the ones where you want to do custom work
     in between standard targets -->
<!--
    <target name="-pre-build">
    </target>
    <target name="-pre-compile">
    </target>

    [This is typically used for code obfuscation.
     Compiled code location: ${out.classes.absolute.dir}
     If this is not done in place, override ${out.dex.input.absolute.dir}]
    <target name="-post-compile">
    </target>
-->


После идет инструкция

<setup />

Она импортирует содержимое SDK/tools/ant/main_rules.xml. Если заглянуть внутрь указанного файла то можно увидеть весь процесс сборки проекта. К сожалению, оттуда мы видим, что использование -pre-build, -pre-compile или -post-compile не подходит для решаемой задачи. Процесс упаковки assets в .apk файл выглядит так:

    <target name="-package-resources">
        <echo>Packaging resources</echo>
        <aapt executable="${aapt}"
                command="package"
                versioncode="${version.code}"
                debug="${build.packaging.debug}"
                manifest="AndroidManifest.xml"
                assets="${asset.absolute.dir}"
                androidjar="${android.jar}"
                apkfolder="${out.absolute.dir}"
                resourcefilename="${resource.package.file.name}"
                resourcefilter="${aapt.resource.filter}">
            <res path="${resource.absolute.dir}" />
            <!-- <nocompress /> forces no compression on any files in assets or res/raw -->
            <!-- <nocompress extension="xml" /> forces no compression on specific file extensions in assets and res/raw -->
        </aapt>
    </target>



Очевидно, что менять что-то нужно именно в этой задаче. Логически я видел два варианта:
1. Каким-то образом задать исключения которые отфильтруют ненужные assets при запаковке.
2. Добавить еще один шаг: удаление ненужных файлов из уже готовой apk.

Самым сложным был поиск документации по . Очевидно что задача опирается на инструмент платформы aapt. Но все что про него есть — это формальная справка в Shell и кусок текста в документации:

The other platform tools, such as aidl, aapt, dexdump, and dx, are typically called by the Android build tools or Android Development Tools (ADT), so you rarely need to invoke these tools directly. As a general rule, you should rely on the build tools or the ADT plugin to call them as needed.

Из заголовочных task-def в main-rules.xml видим, что этот aapt — ни что иное как класс com.android.ant.AaptExecLoopTask. Находим исходный код класс. Из него видим, что задача — ничто иное как узкая прослойка для стандартной запаковки с помощью утилиты командной строки aapt. Можно настраивать пути и имена, но более глубокой гибкости не заложено, как ее не заложено в самой aapt при работе с assets. Инструмент позволяет лишь указать директорию, но не управлять списками файлов. Если вы все же видите варианты — буду рад прочитать их в комментариях.

Поэтому я решаю оставить запаковку в таком виде, в каком есть, и пойти вторым путем: удалить ненужные файлы после запаковки. Для этого внутри нашего build.xml переопределяем зависимости для задачи
"-package-release" которая опирается на задачу запаковки:

    <target name="-package-release" depends="-dex, -package-resources, -package-removetestassets">
        <package-helper
                output.filepath="${out.unsigned.file}"/>
    </target>



Теперь этот target будет использоваться вместо исходного из main_rules.xml. В нем добавлена новая зависимость -package-removetestassets. Добавляем простейшую задачу которая будет удалять ненужные assets:

 
    <target name="-package-removetestassets">
        <echo>Excluding test assets from apk</echo>
        <exec executable="${aapt}">
            <arg value="remove"/>
            <arg value="${out.absolute.dir}/${resource.package.file.name}"/>
            <arg value="assets/test/*.*"/>
        </exec>
    </target>



Результат достигнут, при этом с минимально возможными изменениями в build.xml. А это очень важно, т.к. уменьшает риски при переходи на новые версии Android.

Надеюсь что заметка будет полезной.
Tags:
Hubs:
+12
Comments8

Articles