android-template
android-template copied to clipboard
An Android template application showcasing: Multi modular clean architecture, reactive patterns, dependency injection, integration with jetpack libraries, testing and CI/CD.
Android Template
An Android template application showcasing: Multi modular clean architecture, reactive patterns, dependency injection, integration with jetpack libraries, testing and CI/CD.
Expert teams of digital product strategists, developers, and designers.
We’re always looking for people who value their work, so come and join us. We are hiring!
Getting Started
- Open the project in Android Studio and sync dependencies with gradle.
- Run the app by pressing the run button in android studio or by pressing
control + R. - Go through and setup the scripts in the scripts directory.
App Secrets
Sensitive information such as the api keys is managed via local.properties file. This file in not checked into version control to keep the sensitive information safe. If you want to run the project locally you need to add your own api keys.
Look at the local.skeleton.properties file for all the keys you need to include in your local.properties file.
You can get the Open Weather API key from openweathermap.org.
Architecture
The architecture of the template facilitates separation of concerns and avoids tight coupling between it's various layers. The goal is to have the ability to make changes to individual layers without affecting the entire app. This architecture is an adaptation of concepts from The Clean Architecture.
Layers
The architecture is separated into the following layers
presentation: All UI and state management elements like Activities / Fragments (soon composables), View Models, Components, etc.navigation: navigators to navigate between Screens.interactor: provides feature specific functionality and handle coroutine contexts.domain: use cases for individual pieces of work.repository: repositories to manage various data sources.service: services provide access to external elements such as databases, apis, etc.
Module Structure
Each layer has 3 modules:
- A module for the interfaces. These modules have no suffix. For example: service
- A module for the implementation. These modules are suffixed with
-impl. For example: service-impl - A module for Dependency Injection. These modules are suffixed with
-di. For example: service-di
Entity Modules
The layers presentation, domain and services each have an entity module as well.
presentation-entity: Data Classes that model the visual elements used by the widgets.domain-entity: Data classes for performing business logic manipulations. They act as a abstraction to hide the local and remote data models.service-entity: Contains local models (data classes for the database) and remote models (data classes for the api).
Entity Naming Convention
- Presentation entities are prefixed with
UI(eg: UICity). - Domain entities do not have any prefix. (eg: City).
- Service entities are of 2 types:
- Local / Database entities are prefixed with
Local(eg: LocalCity). - Remote / API entities are prefixed with
Remote(eg: RemoteCity).
- Local / Database entities are prefixed with
Inter-module Dependencies
There is a pattern in which all these modules depend on each other.
- The
interfacemodule in a layer is just the name of the layer.
Example:
repo-interfaceis justrepo
- The
implementationmodule in a layer is just the name of the layer, suffixed by-impl.
Example:
repo-implementationis justrepo-impl
- The
implementationmodules depend on theinterfacemodules of the same layer and the layer directly below it.
Example:
repo-impldepends onrepoandservice.
- The
interfacemodules may depend on theinterfacemodules of the layer below.
Example:
repodepends onservice.
- The
dimodules depend on theinterfaceandimplementationmodules of the same layer. And may also depend on theinterfacemodule of the layer below.
Example:
repo-didepends onrepo,repo-implandservice.
Apart from these, the layer that have entity modules depend on entity module of the same layer. The layers that don't have entity modules depend on the entity modules of the layer above and below.
Gradle setup
- All the dependencies are listed in the
buildSrcmodule in theDependencies.ktfile.. - Android related setup like build types and flavors is in
android.gradlewhich is imported in each module. - Linting setup is done in
lint.gradlewhich is imported in each module. - The
build.gradle.ktsfiles for each module are renamed tomodule-name.gradle.ktsso that it is easy to locate them. For example, the gradle file forservicemodule is calledservice.gradle.kts.
Understanding the Presentation Layer
The presentation layer houses all the visual components and state management logic.
The base directory has all the reusable and common elements used as building blocks for the UI like common components, base classes, extensions, etc.
View Model
Each View Model is a sub class of the BaseViewModel. The BaseViewModel. View Models also have the SavedStateHandle injected into them.
View Model exposes a LiveData of ScreenState from the SavedStateHandle. Along with the ScreenState it also exposes a LiveData of Effect.
Implementations of the BaseViewModel can also choose to handle Intents.
Screen State
ScreenState encapsulates all the state required by a Fragment. State is any data that represents the current situation of a Page.
For example, the HomeScreenState holds the state required by the HomeFragment.
Effect
Effects are events that take place on a fragment that are not part of the state of the screen. These usually deal with UI elements that are not part of the xml layout.
Showing a snackbar or hiding the keyboard are examples of an effect.
Intent
Intent is any action takes place on fragment. It may or may not be user initiated.
SearchScreenIntent has the actions that can happen on the SearchFragment.
Components
Components are reusable parts of UI. Components can be used in any fragment using the by composable delegate provided by the BaseFragment.
Components can be anything from a simple component to hide and show the loading indicator to a complex component like ListComponent that can manage normal and nested recycler view efficiently.
Fragment
Each Fragment must extend the BaseFragment.
The BaseFragment provides the ViewModel with the navigator and the Screen. It listens to the screen state and effect live data from the view model and notifies the fragment about it. It also binds and unbinds all the components in the appropriate lifecycle callbacks.
Each Fragment may receive the Screen as arguments when navigating.
Screen
A Screen is a class that represents a Fragment in the context of navigation. It holds the path or id used by the navigator to navigate to a Fragment and also holds any arguments required to navigate to that Fragment.
Flavors
The template comes with built-in support for 3 flavors
- Dev - This flavour is used across the development stage
- QA - This flavour would be used when the app is under review by the QA Team or the Project Manager
- Prod - This flavour would be used when the app is ready to be deployed to a store or shipped to the user
Note: Flavour specific configurations can be made in the app.gradle file under the
buildTypesblock
Content
The Android Template contains:
- An
Android 12application. - Built-in support for 3
flavors-dev,qaandprod. - A
reactive base architecturefor your application. Roomas local persistent database.Retrofitfor api calls.Kotlinx serializationfor json conversion.Koinfor dependency injection.Timberfor logging.Chuckerfor on device api call logging.Ktlintfor linting the codebase.
Continuous Integration and Deployment
The Android template comes with built in support for CI/CD using Github Actions.
CI
The CI workflow performs the following checks on every pull request:
- Lints the code with
./gradlew lintRelease. (As an additional process, we also run./gradlew ktlintwhich is based on the Ktlint Kotlin linter) - Runs tests using
./gradlew testDebugUnitTest. - Build the android app as the
devflavor to check if the building process works.
CD
The CD workflow performs the following actions:
- Bump the
versionCodeby 1. For details read Version your app - Build a release apk (
prodflavor). - Sign the apk using
apksigner - Upload apk to app center.
- Upload apk as artifact to release tag.
- Commit the updated version to git.
Note: It is recommended to keep your keystore and its essentials like: alias, password safe and encrypted, inside your Github Secrets
Android CD setup
For the android CD workflow to run, we need to perform the following setup steps:
- Follow these instructions to generate an upload keystore. Note down the
store password,key aliasandkey password. You will need these in later steps. - Use
opensslto convert thejksfile toBase64.
openssl base64 < android_template_keystore.jks | tr -d '\n' | tee android_template_keystore_encoded.txt
- Store the
base64output onGithub Secretswith the key nameKEYSTORE. - Save the
store passwordin github secrets with key nameKEYSTORE_PASSWORD. - Save the
key aliasin github secrets with key nameKEY_ALIAS. - Save the
key passwordin github secrets with key nameKEY_PASSWORD. - Create a distribution on app center and get the upload key. You can get it from from Settings.
- Save the app center upload key on github secrets with key name
APP_CENTER_USER_API_TOKEN. - Save the group name as
GROUP_NAMEinside github secrets. Example:Testers - Save the organisation name as
ORG_NAMEinside github secrets. Example:Wednesday Solutions - Save the app name as
APP_NAMEinside github secrets. Example:Android Template
Caution: Respect the of the value inside secrets or else AppCenter APIs might have problems looking for your app