What is android studio module

Модульная разработка Android приложений

При разработке Android приложений наступают моменты, когда те или иные части кода можно вынести в виде библиотек, чтобы можно было переиспользовать их в разных проектах:

  • Модули в проекте, которые часто встречаются. Например, кастомные View
  • Когда существующий API неудобный или не позволяет сделать то, что задумали — создаем расширение для этого API

Чаще всего все проблемы были решены задолго до нас, но в нашем случае нужно было вынести часть слоя бизнес-логики и фактически весь слой, отвечающий за данные в 3 наших основных продукта объединенной компании Колёса Крыша Маркет. Все наши продукты – классифайды про автомобили, недвижимость и прочие товары. Поэтому нами, разработчиками, было решили написать одно решение для всех продуктов компании. К тому же, это облегчило нашу работу.

Попробовали git submodule

Самое простое решение — использовать git submodule. Если кратко объяснить его работу, то к git repository вы прикрепляете ссылку на другой git repository, который должен автоматически клонироваться вместе с родительским. Казалось бы все просто: у нас есть несколько git repository, где хранятся все наши модульные библиотеки и нужно всего лишь указать его в git submodule.

Но как быть с версиями? При обновлении через команду git submodule update стираются изменения в submodule, merge не происходит. Вам придется постоянно обновляться, когда другой разработчик вносит изменение в данном submodule. Вместо этого стоит разрабатывать модули в виде библиотек с jar файлом или Android Archive (aar). По факту, в этих архивах содержатся те же самые файлы, которые могли быть в git submodule, но теперь есть более понятное версионирование вместо истории commit или tag.

Осторожно, не все можно публиковать

При публикации библиотек стоить учесть, что они не должны содержать конфиденциальные данные компании. Более того, не будет удобно остальным разработчикам, если в библиотеке будет содержаться код, относящийся к конкретной компании. Следовательно, нам нужен закрытый artifactory для хранения библиотек в закрытом доступе. Есть множество open source решений, но мы используем JFrog Artifactory.

А если можно публиковать? В таком случае вас ждет светлая дорога в мир open source проектов. Достаточно просто найти открытые web серверы, которые поддерживают gradle, чтобы размещаемые jar и aar файлы подтягивались через dependency в ваших проектах.

Итак, начинаем создавать модуль



Начинается все просто — заходим в File > New > New Module…
Название библиотеки, которое укажете в этом окне, станет названием бинарника вашей библиотеки.

Создав модуль можете приступить к написанию кода. Если к прилагаемому коду будете писать тесты, остальным членам команды будет понятно, как вашим модулем пользоваться. Еще лучше, если создадите новый sample app module, который работает исключительно с вашим модулем для демонстрации на реальных устройствах. Удобнее, когда вам нужно предварительно протестировать код перед публикацией в artifactory. Для этого достаточно указать зависимость в build.gradle. В примерах я буду указывать librarymodule в качестве названия модуля.

Настраиваем gradle для публикации в artifactory

Конкретно в его случае описывается процесс в maven repository для публичной публикации. Основные настройки абсолютно идентичны: в каждом модуле, который нужно публиковать, вызываем gradle script файл из файла build.gradle модулей и создаем gradle.properties, где будет лежать конфигурационная информация для публикации. Нас интересует возможность публиковать в приватном artifactory

Нам необходимо добавить 2 папки для публикации в artifactory: одну для официального релиза и snapshot для тестовых сборок модулей.


Когда у нас наконец-то настроен конфигурационный файл gradle.properties, мы готовы сделать первую публикацию библиотек в artifactory. В тестовой сборке укажем SNAPSHOT в VERSION_NAME. Затем выполним команду:

Настройка CI окружения

Нам удалось вручную опубликовать модули в наш приватный artifactory. В завершениb осталось настроить CI окружение, чтобы мы могли встроить публикацию в наш процесс разработки.
Мы хотим, чтобы только CI мог публиковать в release artifactory, а для остальных добавим свободный доступ на чтение и запись в snapshot. Поэтому внесем изменения в корневом файле gradle.properties, который обычно лежит в

Читайте также:  Rouge like evolution cheats android

/.gradle/gradle.properties . Пропишем <%username%>и <%password%>для доступа при публикации в artifactory. Таким образом у нас будет настроен уровень доступа, без внесения изменений в .gitignore.

Добавляем trigger на ветку master, чтобы при merge у нас собралась сборка для публикации в release artifactory. В список задач сборок добавляем запуск тестов, если у нас в модуле они есть. Хорошо будет ещё настроить auto increment версии.

Используем модуль в продукте

Как только CI соберет сборку и зальет ее в artifactory, в проекте можно добавить зависимость этого модуля. Но погодите, нам же нужно добавить еще и url к нашему artifactory, ведь они недоступны в типичном repository как maven

Теперь мы можем использовать его в проекте.

С чем мы столкнулись

При подключении Kotlin в наши модули документация для Kotlin файлов не подтягивается. Оказалось, что для этого нужно добавить gradle задачу с Dokka.

Если несколько разработчиков указывали идентичные версии для библиотек при публикации, то, естественно, актуальной версией модели оказывалась последняя публикация. В процессе разработки модуля обязали указывать постфикс с идентификатором ticket из Jira. Получается что-то вроде 1.0.1-AAS-1-SNAPSHOT .

Что в итоге получилось

Со временем у нас возросло количество модулей. Мы держали каждый модуль в отдельном git repository. Множество git repository создает большое количество неудобств в процессе разработки, если модуль имеет зависимость от других модулей. В итоге получилось, что для выполнения одной задачи, необходимо было создавать PR в каждом git repository. Не совсем ясно, в каком порядке их нужно тестировать, не учитывая еще постоянное изменение PR, если в одном из PR внесли правки. Поэтому, использовать один git repository для всех модулей на практике оказалось удобнее всего.

Таких модулей у вас может быть множество. Если в том или ином проекте не требуется конкретный модуль, то мы легко можем убрать зависимость, что в итоге нам позволит не писать дублирующие коды в каждом из трех из наших проектов.

Такая модульная разработка внутренних компонентов бизнеса поможет нам повысить скорость доставки фичи до пользователей. В заключении стоит отметить важное преимущество модульной разработки — сборка apk файлов будет занимать намного меньше времени, так как gradle будет пересобирать только ту часть модуля, в которой произошло изменение.

Источник

Modularizing Android Applications

We’ve all been there. Single module android applications — at some point in our Android development career it’s likely we’ve worked on, or are working on, a project that consists of a single module. Now, there’s nothing wrong with that at all and in a lot of cases, a single module will most likely do the job.

But in cases where our applications may grow, or we may want to take advantage of new distribution features (Instant apps, app bundles) from Google, or even just create a clear separation of concerns to make our project easier to work with— modularizing our applications can help us to achieve all of these things. And because some of these newer tools from Google are aimed at modularized applications, who knows what may become available in the future for applications that are structured this way.

Recently I’ve playing with Instant Apps as well as the new App Bundles, which means there are now more ways to modularize our projects — and knowing a little bit more about these can help us to know the right ways to configure our projects. Maybe you want to modularize your application, or maybe you want to get a clearer understanding on the differences between the different modules that we can create for our project — in this post we’re going to take a quick look at the different kinds of modules we can create and what these can do for our android applications.

Application module

We’ll start here as it’s likely a module that you’ve already encountered or used at some point during your development career. And if not, then it’s the most important place to start! This is essentially the main module of your application and will often be under the app module, using the application plugin in the modules build.gradle file to signify this:

Now if you’re building a single module application then this will be the only module-type plugin that you will be using throughout your project. In single module projects, this base module will contain all of your applications responsibilities — be in User Interface, Networking, Cache, Data operations — you name it and it will be there.

Читайте также:  Android built in language

If you’re building a multi-module application, then the application module will still be the installed module, but the way this application module operates will vary depend on what it is you are building:

  • If your multi-module project simply abstracts out data responsibilities of your application into data modules, then the application module will operate in the same way that you have worked with it in single-application modules but just with a clearer seperation of concerns.
  • If your multi-module project is supporting dynamic feature modules then this application module will behave in pretty much the same way as the single module application . The only difference is that the module will need to define the module references for the dynamic features that are to be supporting for the application instance.
  • If your multi-module project is for instant apps then this application module will simply be used to define the feature-module dependencies for the instant app. This is because when an instant app is being built, this application module does not contain any application code as its responsibility is just consume the feature modules which are declared.

Core modules

You can essentially use these modules to separate out related areas of your project so that they are decoupled from the main module of your project. There’s not really a coined term for these but lets call them core modules.

For example, let’s say you have a project that supports both Android wear and Android Phones, you might have a module for the Wear UI layer, Phone UI layer followed by a core module. This core module will contain all of the shared business logic, data operations, caching etc that is used by both of the UI modules. In this case, you are promoting code re-use as all of these aspects can be shared between the two UI modules.

Re-use isn’t the only reason as to why you might want to create this kind of module though. Separating core logic can also help to create a clear separation of concerns that makes your code easier to understand, test and maintain across your team — you may also benefit from build time improvements in some cases.

So for example, you may have a large application with a complex data layer that communicates with both a remote and cache data source. In cases like this, separating out these parts of logic into their own responsibility-specific modules allows you to achieve these things. This could result in us having a data module (to handle the fetching of data and data source), remote module (to handle remote data source communication) and cache module (to handle local data persistence) alongside a presentation module to handle the user-facing parts of our application.

There are no strict guidelines as to what should be in these core modules. My advice would be to not move stuff out into module for the sake of it, but if you feel there will be some benefit for your team (like the ones mentioned above) then moving a responsibility into a module can help you to achieve some of the benefits of modularization.

Core modules that contain android framework references will need to use the library plugin:

Whilst on the other hand, core modules that do not reference the android framework can simply be pure kotlin / java modules:

Abstraction modules

Core modules may often be used to move chunks of shared logic or independent responsibilities, but sometimes we may want to abstract some third-party responsibility out of our application. This can often be a good idea so that our application will not be tightly coupled to a specific implementation of something— in this situation we’d simply communicate via an interface between the app and abstraction module, allowing us to easily switch out the implementation for another if required. Therefore if some library becomes deprecated, a service shuts down or for whatever reason you need to change the implementation then you can do so with minimal interruptions to your code base.

Читайте также:  Лучшие камеры переводчики для андроид

In these cases, your abstraction modules will either use the android library plugin or simply be a pure kotlin / java module (depending on the library dependencies) that we previously looked at.

Feature Modules

As well as this approach to splitting out back-end related tasks into core modules, you can do the same for user facing features within your app — we call these feature modules. These feature modules are going to contain specific features of our application which can help us to again decouple different responsibilities to achieve the same benefits as we’ve previously looked at. Now, the way that these are defined will depend on the kind of multi-project application that you are building, so let’s take a look at the different scenarios:

Standard application

In a ‘standard’ application where you are not using instant apps or dynamic delivery, you may still want to split individual features out into modules to achieve some of the benefits from modularization, whilst also future-proofing yourself incase your app moves in an instant/dynamic direction along the line. In these cases you will simply package up a feature into an android library module and add it as a dependency to your application module.

In cases where you are not supporting instant apps, or not ready (or need) to support dynamic delivery yet, featuring by library modules can still help you to decouple your codebase and achieve other benefits of modularization. In these cases you can simply declare modules as library modules using the library plugin and add them as a dependency to your application module.

Instant support application

On the other hand, if your app supports Play Instant then you will need to use the feature plugin for your desired feature module:

Each feature module will need to have a reference to your base module (in this diagram, the app module) — the feature module in this case will only contain the required code for the implementation of that feature, any code that is required from the core of your app will be obtained from the base module reference.

Dynamic support application

These kind of modules can be used to decouple specific features and resources of your application into their own module, to then be used as part of the new App Bundle format which allows us to dynamically deliver individual features to users. This means we can reduce the initial install size of our applications, instead allowing users to download specific features at run-time as and when they are required.

Just like the instant app focused feature module, these dynamic-feature modules will contain pure feature implementations whilst still having a reference to the base module of the application. The only difference within this module is that the manifest file contained within it has some additional information regarding the distribution of this module.

We can define a module as a dynamic feature module by using the provided plugin below:

Note: In future app bundles will provide support for instant apps.

Instant App Module

Last but not least, if you’re currently wanting to support instant apps then your application will need to be provide an instant module.

The contents of this module will be pretty empty most of the time — this is because the responsibility of the Instant Module is to simply build the instant app when request. Therefore, its sole purpose is to consume the feature modules that have been referenced as a dependency. When defining an instant module you will need to use the instant app plugin in your modules build.gradle file:

The aim of this article was to provide a brief overview of the different modules that are available for android projects, as well as plant some seeds as to how you could approach modularization within your app. If you have any questions about modularization then please do reach out 🙂

Источник

Оцените статью