https://github.com/hossain-khan/android-compose-app-template
An Android App template that is preconfigured with Circuit UDF architecture.
https://github.com/hossain-khan/android-compose-app-template
android-architecture android-circuit android-template circuit compose compose-circuit-udf jetpack-compose udf
Last synced: about 2 months ago
JSON representation
An Android App template that is preconfigured with Circuit UDF architecture.
- Host: GitHub
- URL: https://github.com/hossain-khan/android-compose-app-template
- Owner: hossain-khan
- License: mit
- Created: 2024-11-09T17:30:57.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2026-04-13T20:28:08.000Z (2 months ago)
- Last Synced: 2026-04-13T22:27:53.842Z (2 months ago)
- Topics: android-architecture, android-circuit, android-template, circuit, compose, compose-circuit-udf, jetpack-compose, udf
- Language: Kotlin
- Homepage:
- Size: 951 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Android - Circuit App Template
An Android App template that is preconfigured with ⚡️ Circuit UDF architecture.
> [!CAUTION]
> Since [`1.0.0`](https://github.com/hossain-khan/android-compose-app-template/releases/tag/1.0.0) release this this template has extended it's feature set
> and does not adhere to templating realm any more. If you plan to use latest version, you may have to spend extra time deleting features that you don't want.
> Browse the 🏷️ [1.0](https://github.com/hossain-khan/android-compose-app-template/tree/1.0.0) tagged release to read original instructions.
## What do you get in this template? 📜
* ✔️ [Circuit](https://github.com/slackhq/circuit) library setup for the app
* ✔️ [Metro](https://zacsweers.github.io/metro/) Dependency Injection for all Circuit Screens & Presenter combo
* ✔️ [OkHttp](https://square.github.io/okhttp/) & [Retrofit](https://square.github.io/retrofit/) networking with [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) and sample API implementation
* ✔️ GitHub Actions for CI and automated release builds
* ✔️ Automated APK/AAB builds with keystore signing (see [RELEASE.md](RELEASE.md))
* ✔️ [Google font](https://github.com/hossain-khan/android-compose-app-template/blob/main/app/src/main/java/app/example/ui/theme/Type.kt#L9-L14) for choosing different app font.
* ✔️ `BuildConfig` turned on with example of reading config from `local.properties` file.
* ✔️ [Kotlin formatter](https://github.com/jeremymailen/kotlinter-gradle) plugin for code formatting and linting
* ✔️ [Work Manager](https://developer.android.com/develop/background-work/background-tasks/persistent) for scheduling background tasks
* ✔️ [Dev Container](.devcontainer) for a ready-to-use Android development environment in VS Code or GitHub Codespaces
> [!WARNING]
> _This template is only for Android app setup. If you are looking for a multi-platform supported template,_
> _look at the official [Circuit](https://github.com/slackhq/circuit) example apps included in the project repository._
### Post-process after cloning 🧑🏭
1. Checkout the cloned repo
2. Navigate to repo directory in your terminal
You have **two options** for customizing this template:
Option 1: Automated Customization (Recommended)
#### Option 1: Automated Customization (Recommended) 🤖
Run the setup script to automatically handle most of the configuration:
**Script Usage:**
```bash
./setup-project.sh [flags]
```
**Parameters:**
- `` - Your app's package name in reverse domain notation (e.g., `com.mycompany.appname`)
- `` - Your app's class name in **PascalCase** (e.g., `TodoApp`, `NewsApp`, `MyPhotos`)
- Used to rename `CircuitApp` → `{AppName}App`
- Becomes your main Application class name
- Sets app display name in `strings.xml`
- Used in git commit messages
**Examples:**
```bash
# Basic usage - keeps examples and WorkManager by default
./setup-project.sh com.mycompany.appname MyAppName
# Remove WorkManager if you don't need background tasks
./setup-project.sh com.mycompany.appname MyAppName --remove-workmanager
# Remove example screens and data layer for a clean starting point
./setup-project.sh com.mycompany.appname MyAppName --remove-examples
# Keep the script for debugging (useful during development)
./setup-project.sh com.mycompany.appname MyAppName --keep-script
```
**What the script does automatically:**
- Renames package from `app.example` to your preferred package name
- Preserves subdirectory structure (`ui/theme/`, `di/`, `circuit/`, `work/`, `data/`)
- Updates app name and package ID in XML and Gradle files
- Renames `CircuitApp` to `YourAppNameApp`
- Keeps WorkManager files by default (use `--remove-workmanager` to exclude)
- Keeps example screens by default (use `--remove-examples` to exclude)
- Creates a fresh git repository with descriptive initial commit
- Removes template-specific files
Option 2: Manual Customization 🔧
#### Option 2: Manual Customization 🔧
If you prefer manual control, complete these tasks:
* [ ] Rename the package from **`app.example`** to your preferred app package name.
* [ ] Update directory structure based on package name update
* [ ] Update app name and package id in XML and Gradle
* [ ] Rename `CircuitApp***` to preferred file names
* [ ] Remove `Example***` files that were added to showcase example usage of app and Circuit.
* [ ] Remove WorkManager and Worker example files if you are not using them.
Additional Manual Steps (Both Options) 📝
#### Additional Manual Steps (Both Options) 📝
These still need to be done manually after using the script:
* [ ] Update `.editorconfig` based on your project preference
* [ ] Update your app theme colors (_use [Theme Builder](https://material-foundation.github.io/material-theme-builder/)_)
* [ ] Generate your app icon (_use [Icon Kitchen](https://icon.kitchen/)_)
* [ ] Update/remove repository license
* [ ] Configure [renovate](https://github.com/apps/renovate) for dependency management or remove [`renovate.json`](https://github.com/hossain-khan/android-compose-app-template/blob/main/renovate.json) file
* [ ] Choose [Google font](https://github.com/hossain-khan/android-compose-app-template/blob/main/app/src/main/java/app/example/ui/theme/Type.kt#L16-L30) for your app, or remove it.
* [ ] Verify Android Gradle Plugin (AGP) version compatibility with your development environment in `gradle/libs.versions.toml`
* [ ] **(Optional)** Set up production keystore for release builds - see [RELEASE.md](RELEASE.md) for automated APK signing
## Dev Container 🐳
This template includes a [Dev Container](.devcontainer) configuration for a ready-to-use Android development environment.
### Features
- **Base Image**: Java 21 (Bookworm)
- **Android SDK**: Automatically installed via post-create script (API 36, Build Tools 36.0.0)
- **VS Code Extensions**: Kotlin, Gradle, Java, and GitHub Copilot support
- **ADB Access**: Configured with `--privileged` mode to allow connecting physical Android devices
### Usage
1. Open the project in VS Code
2. When prompted, click **"Reopen in Container"** (or run `Dev Containers: Reopen in Container` from the Command Palette)
3. Wait for the container to build and the post-create script to complete
You can also open this project directly in [GitHub Codespaces](https://github.com/features/codespaces).
### Available Commands
```bash
# Build the project
./gradlew build
# Run tests
./gradlew test
# Format Kotlin code
./gradlew formatKotlin
# Lint Kotlin code
./gradlew lintKotlin
```
## Demo 📹
Here is a demo of the template app containing screens shown in the 📖 [circuit tutorial](https://slackhq.github.io/circuit/tutorial/) documentation.
The demo showcases the basic Circuit architecture pattern with screen navigation and state management.
https://github.com/user-attachments/assets/56d6f28b-5b46-4aac-a30e-80116986589e
### Templated Apps
Here are some apps that has been created using the template.
| 📱 App | Repo URL |
| ------ | ------- |
|
Weather Alert | https://github.com/hossain-khan/android-weather-alert |
|
Remote Notify | https://github.com/hossain-khan/android-remote-notify |
|
TRMNL Display | https://github.com/usetrmnl/trmnl-android |
|
TRMNL Buddy | https://github.com/hossain-khan/trmnl-android-buddy |
|
Math Pup Tutor | https://github.com/hossain-khan/kids-math-tutor |
## 📓 Additional References
Metro Usage
## Metro Dependency Injection 🔧
This template uses [Metro](https://zacsweers.github.io/metro/latest/) (v0.10.4) - a modern, multiplatform Kotlin dependency injection framework.
> **What is Dependency Injection?** DI is a design pattern that provides objects (dependencies) to a class rather than having the class create them itself. This makes code more testable, maintainable, and modular.
Metro combines the best features of:
- **Dagger**: Lean, efficient generated code with compile-time validation
- **kotlin-inject**: Simple, Kotlin-first API design
- **Anvil**: Powerful aggregation and contribution system
### Key Metro Features Used
The template demonstrates several Metro patterns:
- **[Dependency Graphs](https://zacsweers.github.io/metro/latest/dependency-graphs/)**: `AppGraph` is the root DI component scoped to the application lifecycle
- **[Constructor Injection](https://zacsweers.github.io/metro/latest/injection-types/#constructor-injection)**: Activities and other classes use constructor-based DI
- **[Aggregation](https://zacsweers.github.io/metro/latest/aggregation/)**: `@ContributesTo` automatically contributes bindings to the graph without explicit wiring
- **[Multibindings](https://zacsweers.github.io/metro/latest/bindings/#multibindings)**: Activity and Worker factories use map multibindings for flexible injection
- **[Assisted Injection](https://zacsweers.github.io/metro/latest/injection-types/#assisted-injection)**: Workers mix runtime parameters with injected dependencies
- **[Scopes](https://zacsweers.github.io/metro/latest/scopes/)**: `@SingleIn(AppScope::class)` ensures singleton instances
### Metro 0.10.x Modern Patterns
**Since Metro 0.10.0**, the `contributesAsInject` feature is enabled by default, making `@Inject` implicit on:
- `@ContributesBinding`
- `@ContributesIntoMap`
- `@ContributesIntoSet`
This means you no longer need to explicitly annotate contributing classes with `@Inject` - it's automatic! ✨
### Metro Implementation Examples
Below are simplified examples from the template. See the actual implementation files for complete details.
```kotlin
// AppGraph - Root dependency graph
@DependencyGraph(scope = AppScope::class)
@SingleIn(AppScope::class)
interface AppGraph {
val circuit: Circuit
val workManager: WorkManager
// ... other graph accessors
@DependencyGraph.Factory
interface Factory {
fun create(@ApplicationContext @Provides context: Context): AppGraph
}
}
// Activity with constructor injection (no @Inject needed!)
@ActivityKey(MainActivity::class)
@ContributesIntoMap(AppScope::class, binding = binding())
class MainActivity(
private val circuit: Circuit,
) : ComponentActivity() {
// ... activity implementation
}
// Worker with assisted injection (requires additional annotations for multibinding)
@AssistedInject
class SampleWorker(
context: Context,
@Assisted params: WorkerParameters,
) : CoroutineWorker(context, params) {
// ... worker implementation
// Note: Requires @WorkerKey and @AssistedFactory annotations
// See app/src/main/java/app/example/work/SampleWorker.kt for complete example
}
```
For complete Metro documentation and advanced features, see the [official Metro documentation](https://zacsweers.github.io/metro/latest/).