A starting point for creating a new android app repo, with many tools and patterns for modern Android development already implemented, such as:
- Compose
- Jetpack Navigation
- Made more modular using Destinations
- Deep link support
- Koin dependency injection
- ktlint and EditorConfig for code style
- Idea/Studio run configurations for checking and autoformat included
- Timber for logging
- Multi-module project structure
- Dokka for documentation generation
- Idea/Studio run configuration for generating docs included
- Gradle convention plugins to simplify creating new:
- App modules
- Library modules
- Modules with Compose
- Dynamic signing configuration
And more to come
This repo follows the ConventionalCommits v1.0.0 specification for commit formatting. For cleanliness, ease of reading, and easy changelog generation, it is recommended that you maintain this after starting a new project with this template.
This template uses a multi-module structure to encourage separation of different components.
The "app" module is included as a starting point for your new app. After cloning this template, the first thing you should do is change the package name to a more suitable one.
- Open
app/build.gradle
and change the namespace and applicationId - Move
MainActivity.kt
to a path that matches your package name
When using this template, the App module should only contain your activity class and a list of
destinations
, screens that are registered as navigable routes. All app functionality should be
implemented in feature
modules.
The build-logic
directory is for code that is used in building your app, not a part of the
app itself.
The build-logic:convention
module provides a set of gradle plugins that simplify creating new
modules. These include plugins for creating new:
- Application Modules
- Library Modules
- Test Modules
- Compose Modules
These plugins can be combined to suit your needs, which the exception that a module can only be an
application or a library, not both. For example, if you are creating a new core
module that has
tests for its functionality, the build.gradle
would look something
like:
plugins {
alias(libs.plugins.modular.android.library)
alias(libs.plugins.modular.android.test)
}
android {
namespace = "core.my-module"
}
No further configuration is necessary, unless there are any external dependencies that are needed.
The core
directory holds modules that provide functionality that can be reused across multiple
modules. This includes things like repositories, API accessors, and common Composables.
The core:lifecycle
module holds lifecycle-related components that can be used or referenced across
multiple app modules or features. By default this includes:
MainApplication
, the commonApplication
class used across app modules, which holds:- Timber Tree configuration
- Koin Dependency registration
TemplateActivity
, an open implementation ofComponentActivity
that supports:- :aunching to a deep-linked route
The 'core:ui' module is a module used for common UI definitions throughout the app, such as the
theme, ui-related constants, an common composables. It also includes the Destination
class, which
allows for modular registration of navigable routes. If you end up modifying Destination
to
support a Jetpack Navigation feature that is not currently supported, consider contributing it back
to this template.
The core:util
module is empty, but is meant for statically defined functions and one-offs used
in other modules.
The feature
directory holds modules that implement "features". In the context of this template, a
feature refers to a user-facing screen, set of related screens, or a user flow. Each feature should
define one destination
, which is the entry point for navigating to that feature in app. Features
can navigate between one another, but should not have any build time dependency on one another. For
cleanliness, feature
modules should only depend on core
modules and external libraries.
This template supports providing custom signing config(s) via the keystore.properties
pattern. If
keystore.properties
exists in the root of the project, the values defined in it will be used for
the app module's signing config(s), otherwise the default is used.
keystore.properties
supports both a singular signing config, and per-variant signing configs. As
an example, the following keystore.properties
uses the generic config for all variants except
release, which has its own signing config defines.
storePassword=example
keyPassword=example
keyAlias=example
storeFile=example.keystore
release.storePassword=example
release.keyPassword=example
release.keyAlias=example
release.storeFile=release.keystore