My Android project template

4 minute read

Have you ever experienced something like this:

  1. Have a great idea for a weekend project
  2. Create a new repository
  3. Setup a proper CI to build your project
  4. Setup a code formatter to enforce code-style
  5. Start reading articles about [tool name here]
  6. Weekend is over 😅
  7. Repeat

That’s how a lot of side-projects of mine died in the past.

I love developer-tools such as CIs and static-analysis tools. They’re crucial to deliver good quality code, and I can’t imagine working without them. They’re generally the first thing I set up before starting a new project.

Unfortunately, setting up such tools can be time-consuming, especially if you’re not familiar with a specific tool and how to configure it.

That’s why throughout the years I crafted my own project templates. They help me kick off a project if I have a new idea in mind, without having to spend time configuring everything from scratch.

Recently I’ve spent some time polishing them and open-sourcing some of them. They’re now available for everyone to use with Github templates with just one click.

Here you can find my Android App/Library template: cortinico/kotlin-android-template

In this blog-post, I will walk you through the steps I do before starting an Android project and that you can find already applied in the linked template.

1. Format: ktlint

The clear choice I made in this template is to have it as a 100% Kotlin template. I believe that in 2020 is safe to assume that you can start your new Android project with Kotlin only.

I generally don’t start writing code without a good formatter to support me. Having several comments on your pull-requests about where to place parenthesis or extra white-spaces can be pretty annoying. A formatter can help you ship beautified code and avoid useless discussions.

For Kotlin my preferred formatter is ktlint.

I use the ktlint-gradle plugin to integrate it into my build. With that, running:

./gradlew ktlintFormat

will reformat the entire codebase.

Ktlint-gradle comes with other tasks that can help speed-up developer’s productivity with IntelliJ integration and pre-commit hooks:

# Will update IntelliJ/AndroidStudio reformat rules to
# match the ktlint style.
./gradlew ktlintApplyToIdea

# Will set up a pre-commit hook that will run 
# reformat the code before a git commit.
./gradlew addKtlintFormatGitPreCommitHook

If you happen to use Gradle Kotlin DSL, ktlint will conveniently reformat also your .gradle.kts file.

2. Analyze: detekt & lint

Other than beautified, we want our code to be bug-free.

That’s where static analyzers can help spot bugs before the code goes to production. I always configure those two static analyzers on my projects:

  • (Android) Lint: A language agnostic analyzer that will help you spot Android-specific bugs (e.g., unused resources or hard-coded text).
  • Detekt: A Kotlin specific analyzer that can help you find potential errors or anti-patterns in your Kotlin code.

Lint is available out of the box directly inside Android Studio.

Detekt is instead a command-line tool and can be included in the build with a Gradle plugin.

Once set up, invoking:

./gradlew detekt

is enough to run the static analyzer on the whole codebase.

I personally find useful also the detekt IntelliJ plugin. It will run the detekt inspection directly inside Android Studio without having to run an extra task.

detekt idea plugin
Example of a Detekt warning in Android Studio

3. Manage dependencies: buildSrc

I prefer to use the Gradle Kotlin DSL to write my build files. It comes with nice features such as auto-completion and semantic editing.

To manage dependencies I use the buildSrc included build. This allows organizing libraries and versions with a Dependencies.kt file such as:

object Versions {
    const val APPCOMPAT = "1.1.0"
    const val CORE_KTX = "1.2.0"
    const val JUNIT = "4.13"
}
object SupportLibs {
    const val ANDROIDX_APPCOMPAT = "androidx.appcompat:appcompat:${Versions.APPCOMPAT}"
    const val ANDROIDX_CORE_KTX = "androidx.core:core-ktx:${Versions.CORE_KTX}"
}
object TestingLib {
    const val JUNIT = "junit:junit:${Versions.JUNIT}"
}

Those versions and coordinates are available to every build script in the project. Declaring a dependency is as easy as:

buildsrc-deps-autocomplete
Autocompleting dependencies with buildSrc and Kotlin DSL

Moreover, I’m using the Gradle Plugin DSL to apply Gradle plugins instead of the old apply: statement.

Setting up a new module is a matter of just:

plugins {
    id("com.android.library")
    kotlin("android")
}

The buildscript {} block is not needed anymore. Plugin versions are defined in the top-level build.gradle.kts file, while repositories are declared in the settings.gradle.kts file.

4. Build: Github Actions

To build and test my project, I always set up a continuous integration environment. This allows running tests in isolation and ensuring consistent code formatting/static analysis on every commit.

I’ve tried several CI services in the last years, but recently I’ve migrated a lot of my projects to Github Actions.

In the template you can find two Github Actions workflows:

Those workflows will run automatically for every new Pull Request and for every push.

Github Actions integrates well with Github templates: when you create a new repo from my template, you will have a CI setup already running, and you don’t need to set up extra services or create other accounts.

github actions screenshot
A sample build from Github Actions

5. Conclusion: Maintain a template

Whenever I start a new project, I make sure to spend some time to update my templates to the latest market standards and tooling versions. I personally found project templates useful in several occasions:

  • When kicking off a new project, they get you started in some seconds and let you prototype fast your idea.
  • When submitting bugreports to open-source projects, they let you create an empty project to easily showcase how to reproduce a failure scenario.
  • When working on other projects, I often come back to my template to check how I configured a specific tool. They serve as documentation for my preferred setup.

I hope you found my template useful, and you get inspired to create your own. 💪

If you want to talk more about this, you can find me as @cortinico on Twitter .

Categories:

Posted:

Leave a comment