Blog Infos
Author
Published
Topics
, , , ,
Published

Photo by Barn Images on Unsplash

Creating reusable tools is part of being a professional Android developer. Over time, many of us accumulate utility classes, wrappers, and internal helpers that could easily be shared between projects — yet they often stay buried in the utils folder of a single app.

Publishing a proper SDK sounds like something for big companies or platform teams, but it doesn’t have to be

The goal of this article is to walk through the full process of building and publishing your own SDK — from idea to public usage. No magic, no scripts, no hidden steps.

We’ll build a small but practical SDK — a lightweight TimeTracker — and use it to explore:

  • Creating a clean library module
  • Designing a reusable public API
  • Publishing the SDK to GitHub + JitPack
  • Integrating it into a real Compose-based app
  • Writing documentation and examples

For publishing, I’m using JitPack, which builds your SDK directly from a GitHub repository. It’s perfect for internal tools, side projects, open-source libraries, or even production SDKs that don’t require the full rigor of Maven Central.

If you’re building something bigger or for wide distribution, then Maven Central is the more scalable and enterprise-ready option — but it comes with more setup and release overhead.

This article focuses on clarity and practicality. Whether you’re new to SDK development or just never had the time to set it up before, this is a working, repeatable example you can build upon.

Step 1 — Setting Up the Project and Library Module

The first step is to create a new Android project where we’ll build our SDK.
In real-world cases, you might extract SDK functionality from an existing app, but here we’ll start clean to focus purely on structure.

We’ll use Android Studio to:

  • Create a new Android project
  • Add a separate library module that will become our SDK
  • Keep our SDK code fully isolated and reusable

Tip: Using a library module helps keep concerns separated — your app remains the consumer, and your SDK becomes the provider.

1. Create a new Android project

Open Android Studio and choose “New Project” → No Activity.
You can name the project something like TimeTrackerSDK.

Use Kotlin as the language and set minSdk to 21 or higher.

2. Add a new module: Android Library

Once the base project is created:

  • Go to File > New > New Module…
  • Select Android Library
  • Set the module name to timetracker
  • Set the package name to something like com.example.timetracker
  • Click Finish

This creates a separate module that can be compiled into a .aar file and published independently.

Bonus: You can keep this SDK inside a monorepo or extract it into its own GitHub repository later. Both approaches are valid, depending on your project needs.

 

Step 2 — Writing the SDK Logic and Public API

With your library module set up, it’s time to write the actual SDK logic. We’ll keep it simple: a lightweight utility that measures how long certain blocks of code take to execute.

The goal is to provide a clean and reusable API that developers can drop into any project with zero setup and full control over logging and production safety.

1. Create the SDK entry point

Inside the timetracker module, create a new Kotlin file:

timetracker/src/main/java/com/example/timetracker/TimeTracker.kt

Paste the following code:

 

package com.example.timetracker

import android.util.Log

/**
 * TimeTracker is a lightweight utility for measuring execution time of code blocks or operations.
 * It can be used in both development and production environments.
 */
object TimeTracker {

    private val startTimes = mutableMapOf<String, Long>()
    private val durations = mutableMapOf<String, Long>()

    /** Enable or disable tracking globally. */
    var isEnabled: Boolean = true

    /**
     * Optional custom logger.
     * Default: logs to Logcat with tag "TimeTracker"
     */
    var logger: ((String, String) -> Unit)? = { tag, message ->
        Log.d(tag, message)
    }

    /** Starts tracking a tag */
    fun start(tag: String) {
        if (!isEnabled) return
        startTimes[tag] = System.currentTimeMillis()
        logger?.invoke("TimeTracker", "Started timer for [$tag]")
    }

    /** Stops tracking a tag and calculates duration */
    fun stop(tag: String) {
        if (!isEnabled) return
        val startTime = startTimes[tag]
        if (startTime != null) {
            val duration = System.currentTimeMillis() - startTime
            durations[tag] = duration
            logger?.invoke("TimeTracker", "Stopped timer for [$tag], duration: ${duration}ms")
        } else {
            logger?.invoke("TimeTracker", "No start time found for tag: $tag")
        }
    }

    /** Returns duration in milliseconds for a tag, or null if not available */
    fun getDuration(tag: String): Long? {
        return if (isEnabled) durations[tag] else null
    }

    /** Logs all recorded durations */
    fun printAllDurations() {
        if (!isEnabled) return
        durations.forEach { (tag, duration) ->
            logger?.invoke("TimeTracker", "[$tag] took ${duration}ms")
        }
    }

    /** Clears all start times and durations */
    fun reset() {
        startTimes.clear()
        durations.clear()
        logger?.invoke("TimeTracker", "All timers cleared")
    }

    /**
     * Measures execution time of a code block automatically.
     * Usage:
     * TimeTracker.measure("load_data") {
     *     // Your logic
     * }
     */
    inline fun <T> measure(tag: String, block: () -> T): T {
        start(tag)
        val result = block()
        stop(tag)
        return result
    }
}

 

2. What this SDK does

  • start(tag) — Starts tracking a named block of code.
  • stop(tag) — Stops tracking and records the time duration.
  • getDuration(tag) — Returns the duration in milliseconds.
  • measure(tag) { ... } — Automatically wraps a code block and logs duration.
  • isEnabled — Allows enabling/disabling the entire SDK (useful for release builds).
  • logger — Pluggable logging function for redirecting output to Logcat, Crashlytics, etc.

3. Why this qualifies as an SDK

At a glance, this might look like a utility class — but it’s more than that:

  • It encapsulates its own internal state.
  • It provides a public API with no external dependencies.
  • It can be used across any project without modification.
  • It supports production toggles and logging injection.

That’s what makes it an SDK: it’s a ready-to-use, drop-in tool that works independently of your app’s architecture.

Step 3 — Publishing the SDK with JitPack

Now that your SDK is working locally, the next step is to make it reusable in other projects.
There are multiple ways to publish an Android SDK — you can push to an internal Maven repo, upload to Maven Central, or distribute a .aar manually.

But for open-source or lightweight public libraries, JitPack is by far the easiest and fastest way to publish directly from GitHub — with zero boilerplate.

What is JitPack?

JitPack is a free service that builds your GitHub repository on demand and serves it as a Maven/Gradle dependency. You tag a release, JitPack builds it, and anyone can import it via:

implementation 'com.github.username:repository:tag'

It’s ideal for:

  • Open-source utilities and tools
  • Demo libraries
  • Internal SDKs
  • Quick experiments that don’t need Maven Central

1. Push your SDK to GitHub

If you haven’t already, create a new GitHub repository and push your SDK project to it:

git init
git remote add origin https://github.com/yourname/TimeTrackerSDK.git
git add .
git commit -m "Initial commit"
git push -u origin main

Make sure your TimeTracker.kt lives in a proper library module (not the app module).

2. Tag a release

JitPack builds your library based on tags. Once your code is on GitHub, create a release tag:

git tag v1.0.0
git push origin v1.0.0

This tag will be used as the version in Gradle.

3. Open your project on JitPack

Go to https://jitpack.io
Paste your GitHub repo URL, and hit “Look Up”.

You should see your latest tag and a green “Published” status.

4. Add JitPack to your consumer project

In the app where you want to use the SDK, update your build.gradle:

repositories {
    maven { url 'https://jitpack.io' }
}

Then add the dependency:

dependencies {
    implementation("com.github.yourname:TimeTrackerSDK:v1.0.0")
}

5. Done. You’re using your own SDK!

You can now call TimeTracker.start()TimeTracker.measure(), etc. in any project — just like any other dependency.

This setup is fully reproducible. Every time you push a new tag, JitPack will build and serve a new version automatically.

For production-scale libraries or SDKs intended for wide public distribution (like on Maven Central), you’ll want a more formal setup — with artifact signing, metadata, and hosting. But for most cases, JitPack is more than enough.

 

Step 4 — Using the SDK in a Real Compose-Based App

With the SDK published and available via JitPack, it’s time to test it in a real-world project.

In this step, we’ll:

  • Create a simple Jetpack Compose app
  • Import the SDK as a dependency
  • Use TimeTracker to measure screen setup time and logic execution
  • Log the results using Logcat

1. Create a new Android project with Jetpack Compose

In Android Studio:

  • Select New Project → Empty Compose Activity
  • Use Kotlin and set minSdk to 21+
  • Name the project TimeTrackerDemoApp (or whatever you like)

Once the project is created, open the root-level build.gradle (or settings.gradle.kts) and make sure you have:

repositories {
    google()
    mavenCentral()
    maven { url 'https://jitpack.io' } // Add this line
}

2. Add the SDK dependency

Open app/build.gradle and add:

dependencies {
    implementation("com.github.yourname:TimeTrackerSDK:v1.0.0")
}

Replace yourname with your actual GitHub username.

Sync the project.

3. Use the SDK in your MainActivity.kt

Here’s an example of how you might use TimeTracker inside a Compose activity to measure screen setup time:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Enable tracking in debug mode only
        TimeTracker.isEnabled = BuildConfig.DEBUG
        TimeTracker.logger = { tag, msg -> Log.d(tag, msg) }

        // Measure how long the screen takes to set up
        TimeTracker.measure("MainScreenSetup") {
            setContent {
                TimeTrackerDemoAppTheme {
                    Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                        Greeting(
                            name = "Compose",
                            modifier = Modifier.padding(innerPadding)
                        )
                    }
                }
            }
        }
    }
}

When you run the app, you should see output like this in Logcat:

 

4. Optional: Use inside a Composable

If you want to measure time inside a @Composable, wrap the logic in a LaunchedEffect block:

@Composable
fun Greeting(name: String) {
    LaunchedEffect(Unit) {
        TimeTracker.measure("GreetingRender") {
            delay(100) // simulate some rendering logic
        }
    }

    Text("Hello $name!")
}

Never call TimeTracker directly in @Composable scope unless you’re using it within side-effects like LaunchedEffectSideEffect, etc.

You’ve now successfully:

  • Built a reusable SDK
  • Published it to JitPack
  • Imported it into another project
  • Used it inside a real Compose app

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

No results found.

Jobs

Step 5 — Writing Documentation and README

Your SDK is now working, published, and integrated — but it’s not truly finished until it’s documented.

Even for small, internal tools, a well-written README.md:

  • Helps others (or your future self) understand and use the SDK quickly
  • Makes the code feel professional and trustworthy
  • Serves as the “homepage” for your project when shared on GitHub or JitPack

You don’t need anything complex. Just enough to explain what it is, how to install it, and how to use it.

Here’s the actual README from TimeTrackerSDK

Instead of inventing a fake example, here’s the real README.md from the GitHub repository I created as part of this article:

🔗 TimeTrackerSDK

It includes installation via JitPack, usage in Activities, ViewModels, and Jetpack Compose, production tips, and real code examples.

 

Conclusion — A Reproducible Path to Your First Android SDK

In this guide, we walked through the full process of building and publishing a real Android SDK — from scratch.

We covered:

  • Creating a clean library module for reusable logic
  • Designing a public API that’s easy to consume
  • Publishing the SDK to GitHub using JitPack
  • Integrating it into a real Jetpack Compose app
  • Writing documentation that makes the SDK usable by others

The result:
A working example you can study, fork, or adapt to your own needs:

Whether you’re planning to share internal tooling across apps, contribute to open source, or just explore modular Android architecture — building your own SDK is a great way to level up your skills and your codebase.

The best part?
This process is 100% repeatable. You can follow the same structure to turn any reusable logic — from UI components to analytics wrappers — into a proper, documented SDK.

Found this useful?

👏 Drop a few claps to help more Android devs discover it
💬 Share your thoughts or questions in the comments
🔗 Connect with me on LinkedIn

Thanks for reading — and good luck with your SDKs! 🚀

This article was previously published on proandroiddev.com.

Menu