{"id":25615188,"url":"https://github.com/wednesday-solutions/android-template","last_synced_at":"2025-04-13T21:13:11.067Z","repository":{"id":37867013,"uuid":"301701132","full_name":"wednesday-solutions/android-template","owner":"wednesday-solutions","description":"An Android template application showcasing: Multi modular clean architecture, reactive patterns, dependency injection, integration with jetpack libraries, testing and CI/CD.","archived":false,"fork":false,"pushed_at":"2024-07-10T07:09:53.000Z","size":957,"stargazers_count":21,"open_issues_count":1,"forks_count":8,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-13T21:13:07.811Z","etag":null,"topics":["android","android-boilerplate","android-template","architecture","clean-architecture","coroutines","material-design","testing"],"latest_commit_sha":null,"homepage":"https://wednesday.is/building-products/?utm_source=github\u0026utm_medium=android-template","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wednesday-solutions.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-10-06T11:16:05.000Z","updated_at":"2025-04-03T14:03:51.000Z","dependencies_parsed_at":"2024-07-10T09:10:25.270Z","dependency_job_id":null,"html_url":"https://github.com/wednesday-solutions/android-template","commit_stats":null,"previous_names":[],"tags_count":6,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wednesday-solutions%2Fandroid-template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wednesday-solutions%2Fandroid-template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wednesday-solutions%2Fandroid-template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wednesday-solutions%2Fandroid-template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wednesday-solutions","download_url":"https://codeload.github.com/wednesday-solutions/android-template/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248782260,"owners_count":21160717,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-boilerplate","android-template","architecture","clean-architecture","coroutines","material-design","testing"],"created_at":"2025-02-22T03:18:49.937Z","updated_at":"2025-04-13T21:13:11.040Z","avatar_url":"https://github.com/wednesday-solutions.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg align=\"left\" src=\"android_template_github.svg\" width=\"480\" height=\"540\" /\u003e\n\n\u003cdiv\u003e\n  \u003ca href=\"https://www.wednesday.is/?utm_source=github\u0026utm_medium=android-template\" align=\"left\" style=\"margin-left: 0;\"\u003e\n    \u003cimg src=\"https://uploads-ssl.webflow.com/5ee36ce1473112550f1e1739/5f5879492fafecdb3e5b0e75_wednesday_logo.svg\"\u003e\n  \u003c/a\u003e\n  \u003cp\u003e\n    \u003ch1 align=\"left\"\u003eAndroid Template\n    \u003c/h1\u003e\n  \u003c/p\u003e\n  An Android template application showcasing: Multi modular clean architecture, reactive patterns, dependency injection, integration with jetpack libraries, testing and CI/CD.\n\n  ___\n\n\n  \u003cp\u003e\n    \u003ch4\u003e\n      Expert teams of digital product strategists, developers, and designers.\n    \u003c/h4\u003e\n  \u003c/p\u003e\n\n  \u003cdiv\u003e\n    \u003ca href=\"https://www.wednesday.is/contact-us/?utm_source=github\u0026utm_medium=android-template\" target=\"_blank\"\u003e\n      \u003cimg src=\"https://uploads-ssl.webflow.com/5ee36ce1473112550f1e1739/5f6ae88b9005f9ed382fb2a5_button_get_in_touch.svg\" width=\"121\" height=\"34\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/wednesday-solutions/\" target=\"_blank\"\u003e\n      \u003cimg src=\"https://uploads-ssl.webflow.com/5ee36ce1473112550f1e1739/5f6ae88bb1958c3253756c39_button_follow_on_github.svg\" width=\"168\" height=\"34\"\u003e\n    \u003c/a\u003e\n  \u003c/div\u003e\n\n  ___\n\n  \u003cspan\u003eWe’re always looking for people who value their work, so come and join us. \u003ca href=\"https://www.wednesday.is/hiring/?utm_source=github\u0026utm_medium=android-template\"\u003eWe are hiring!\u003c/a\u003e\u003c/span\u003e\n\u003c/div\u003e\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n## Getting Started\n- Open the project in Android Studio and sync dependencies with gradle.\n- Run the app by pressing the run button in android studio or by pressing `control + R`.\n- Go through and setup the scripts in the [scripts](https://github.com/wednesday-solutions/android-template/tree/master/scripts) directory.\n\n#### App Secrets\nSensitive 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.\nLook at the [`local.skeleton.properties`](local.skeleton.properties) file for all the keys you need to include in your `local.properties` file.\n\nYou can get the Open Weather API key from [openweathermap.org](https://openweathermap.org/appid).\n\n## Architecture\nThe 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`](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html).\n\n### Layers\nThe architecture is separated into the following layers\n- `presentation`: All UI and state management elements like Activities / Fragments (soon composables), View Models, Components, etc.\n- `navigation`: navigators to navigate between Screens.\n- `interactor`: provides feature specific functionality and handle coroutine contexts.\n- `domain`: use cases for individual pieces of work.\n- `repository`: repositories to manage various data sources.\n- `service`: services provide access to external elements such as databases, apis, etc.\n\n### Module Structure\n\n**Each layer has 3 modules:**\n- A module for the interfaces. These modules have no suffix. For example: [service](service)\n- A module for the implementation. These modules are suffixed with `-impl`. For example: [service-impl](service-impl)\n- A module for Dependency Injection. These modules are suffixed with `-di`. For example: [service-di](service-di)\n\n#### Entity Modules\nThe layers `presentation`, `domain` and `services` each have an `entity` module as well.\n- [`presentation-entity`](presentation-entity): Data Classes that model the visual elements used by the widgets.\n- [`domain-entity`](domain-entity): Data classes for performing business logic manipulations. They act as a abstraction to hide the local and remote data models.\n- [`service-entity`](service-entity): Contains local models (data classes for the database) and remote models (data classes for the api).\n\n#### Entity Naming Convention\n- Presentation entities are prefixed with `UI` (eg: UICity).\n- Domain entities do not have any prefix. (eg: City).\n- Service entities are of 2 types:\n  - Local / Database entities are prefixed with `Local` (eg: LocalCity).\n  - Remote / API entities are prefixed with `Remote` (eg: RemoteCity).\n\n#### Inter-module Dependencies\nThere is a pattern in which all these modules depend on each other.\n\n- The `interface` module in a layer is just the name of the layer.\n \u003e Example: `repo-interface` is just `repo`\n\n- The `implementation` module in a layer is just the name of the layer, suffixed by `-impl`.\n \u003e Example: `repo-implementation` is just `repo-impl`\n\n- The `implementation` modules depend on the `interface` modules of the same layer and the layer directly below it.\n\u003e Example: [`repo-impl`](repo-impl) depends on [`repo`](repo) and [`service`](service).\n- The `interface` modules may depend on the `interface` modules of the layer below.\n\u003e Example: [`repo`](repo) depends on [`service`](service).\n- The `di` modules depend on the `interface` and `implementation` modules of the same layer. And may also depend on the `interface` module of the layer below.\n\u003e Example: [`repo-di`](repo-di) depends on [`repo`](repo), [`repo-impl`](repo-impl) and [`service`](service).\n\nApart 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.\n\n## Gradle setup\n- All the dependencies are listed in the `buildSrc` module in the [`Dependencies.kt`](buildSrc/src/main/java/Dependencies.kt) file..\n- Android related setup like build types and flavors is in [`android.gradle`](android.gradle) which is imported in each module.\n- Linting setup is done in [`lint.gradle`](lint.gradle) which is imported in each module.\n- The `build.gradle.kts` files for each module are renamed to `module-name.gradle.kts` so that it is easy to locate them. For example, the gradle file for `service` module is called `service.gradle.kts`.\n\n## Understanding the Presentation Layer\nThe presentation layer houses all the visual components and state management logic.\n\nThe [`base`](presentation/src/main/java/com/wednesday/template/presentation/base) directory has all the reusable and common elements used as building blocks for the UI like common components, base classes, extensions, etc.\n\n### View Model\nEach `View Model` is a sub class of the `BaseViewModel`. The [`BaseViewModel`](presentation/src/main/java/com/wednesday/template/presentation/base/viewmodel/BaseViewModel.kt). View Models also have the [`SavedStateHandle`](https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate) injected into them. \n\nView Model exposes a LiveData of [`ScreenState`](#screen-state) from the SavedStateHandle. Along with the ScreenState it also exposes a LiveData of [`Effect`](#effect). \n\nImplementations of the BaseViewModel can also choose to handle [`Intents`](#intent).\n\n### Screen State\n[`ScreenState`](presentation-entity/src/main/java/com/wednesday/template/presentation/screen/ScreenState.kt) encapsulates all the state required by a Fragment. State is any data that represents the current situation of a Page.\n\nFor example, the [`HomeScreenState`](presentation/src/main/java/com/wednesday/template/presentation/weather/home/HomeScreenState.kt) holds the state required by the [`HomeFragment`](presentation/src/main/java/com/wednesday/template/presentation/weather/home/HomeFragment.kt).\n\n### Effect\n[`Effects`](presentation/src/main/java/com/wednesday/template/presentation/base/effect/Effect.kt) 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.\n\nShowing a snackbar or hiding the keyboard are examples of an effect.\n\n\n### Intent\nIntent is any action takes place on fragment. It may or may not be user initiated.\n\n[`SearchScreenIntent`](presentation/src/main/java/com/wednesday/template/presentation/weather/search/SearchScreenIntent.kt) has the actions that can happen on the [`SearchFragment`](presentation/src/main/java/com/wednesday/template/presentation/weather/search/SearchFragment.kt).\n\n### Components\nComponents are reusable parts of UI. Components can be used in any fragment using the `by composable` delegate provided by the `BaseFragment`.\n\nComponents 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.\n\n### Fragment \nEach Fragment must extend the `BaseFragment`. \nThe `BaseFragment` provides the [`ViewModel`](#view-model) with the navigator and the [`Screen`](#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.\n\nEach Fragment may receive the [`Screen`](#screen) as arguments when navigating.\n\n### Screen\nA [`Screen`](presentation-entity/src/main/java/com/wednesday/template/presentation/screen/Screen.kt) 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`.\n\n## Flavors\nThe template comes with built-in support for 3 flavors\n- Dev - This flavour is used across the development stage \n- QA - This flavour would be used when the app is under review by the QA Team or the Project Manager\n- Prod - This flavour would be used when the app is ready to be deployed to a store or shipped to the user\n\n\u003e Note: Flavour specific configurations can be made in the [app.gradle](app/app.gradle) file under the `buildTypes` block\n\n\n \n## Content\nThe Android Template contains:\n- An [`Android 12`](https://www.android.com/intl/en_in/) application.\n- Built-in support for 3 [`flavors`](https://developer.android.com/studio/build/build-variants) - `dev`, `qa` and `prod`.\n- A [`reactive base architecture`](#architecture) for your application.\n- [`Room`](https://developer.android.com/training/data-storage/room) as local persistent database.\n- [`Retrofit`](https://square.github.io/retrofit/) for api calls.\n- [`Kotlinx serialization`](https://github.com/Kotlin/kotlinx.serialization) for json conversion.\n- [`Koin`](https://insert-koin.io/) for dependency injection.\n- [`Timber`](https://github.com/JakeWharton/timber) for logging.\n- [`Chucker`](https://github.com/ChuckerTeam/chucker) for on device api call logging.\n- [`Ktlint`](https://ktlint.github.io/) for linting the codebase.\n\n## Continuous Integration and Deployment\nThe Android template comes with built in support for CI/CD using Github Actions.\n\n### CI\nThe [`CI`](.github/workflows/ci.yml) workflow performs the following checks on every pull request:\n- Lints the code with `./gradlew lintRelease`.\n(As an additional process, we also run `./gradlew ktlint` which is based on the [Ktlint](https://github.com/pinterest/ktlint) Kotlin linter)\n- Runs tests using `./gradlew testDebugUnitTest`.\n- Build the android app as the `dev` flavor to check if the building process works.\n\n### CD\nThe [`CD`](.github/workflows/cd.yml) workflow performs the following actions:\n- Bump the `versionCode` by 1. For details read [Version your app](https://developer.android.com/studio/publish/versioning)\n- Build a release apk (`prod` flavor).\n- Sign the apk using `apksigner`\n- Upload apk to app center.\n- Upload apk as artifact to release tag.\n- Commit the updated version to git.\n\n\u003e `Note`: It is recommended to keep your keystore and its essentials like: alias, password safe and encrypted, inside your [Github Secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets)\n\n### Android CD setup\nFor the android CD workflow to run, we need to perform the following setup steps:\n- Follow these instructions to [generate an upload keystore](https://developer.android.com/studio/publish/app-signing#generate-key). Note down the `store password`, `key alias` and `key password`. You will need these in later steps.\n- Use `openssl` to convert the `jks` file to `Base64`.\n```shell\nopenssl base64 \u003c android_template_keystore.jks | tr -d '\\n' | tee android_template_keystore_encoded.txt\n```\n- Store the `base64` output on [`Github Secrets`](https://docs.github.com/en/actions/security-guides/encrypted-secrets) with the key name `KEYSTORE`.\n- Save the `store password` in github secrets with key name `KEYSTORE_PASSWORD`.\n- Save the `key alias` in github secrets with key name `KEY_ALIAS`.\n- Save the `key password` in github secrets with key name `KEY_PASSWORD`.\n- [Create a distribution on app center](https://docs.microsoft.com/en-us/appcenter/distribution/) and get the upload key. You can get it from from [Settings](https://appcenter.ms/settings).\n- Save the app center upload key on github secrets with key name `APP_CENTER_USER_API_TOKEN`.\n- Save the group name as `GROUP_NAME` inside github secrets. Example: `Testers`\n- Save the organisation name as `ORG_NAME` inside github secrets. Example: `Wednesday Solutions`\n- Save the app name as `APP_NAME` inside github secrets. Example: `Android Template`\n\n\u003e `Caution`: Respect the of the value inside secrets or else AppCenter APIs might have problems looking for your app\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwednesday-solutions%2Fandroid-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwednesday-solutions%2Fandroid-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwednesday-solutions%2Fandroid-template/lists"}