MyFamilyTracker
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
After 13 years running 22+ Android apps solo from Bangkok, I break down the unglamorous maintenance systems—Gradle conventions, CI pipelines, versioning discipline—that keep everything alive.
On this page
I don't write features anymore. I patch crashes at 2 AM. I bump SDK versions before Google sunsets them. I review dependency updates that nobody asked for. Maintaining 22 apps is the least sexy work in tech—and it's the only reason any of them still exist.
When I started SudarshanTechLabs from a coworking space in Bangkok, I thought shipping fast was the game. Build the app, push to Play Store, move on. That lasted about six months. Then Android 14 dropped. Then Google deprecated WebViewCustomization. Then one of my apps started force-closing on Samsung devices with one UI 6.3. Twenty-two apps means twenty-two surfaces for decay.
Every app you own carries a recurring cost. Not in money—mostly in decisions. Each release cycle demands a version bump, a changelog entry, a build verification, a Play Store submission. Multiply that by 22 and you're drowning in mechanical work that has nothing to do with code quality.
I tracked my maintenance hours for three months across all apps. Here's the split:
| Task | Hours per Month (avg) | % of Dev Time |
|---|---|---|
| New feature development | 12 | 20% |
| Bug fixes from user reports | 18 | 30% |
| Dependency & SDK updates | 14 | 23% |
| CI/CD pipeline fixes | 8 | 13% |
| Play Store asset updates | 6 | 10% |
| Misc (signing, analytics, ads) | 5 | 4% |
[!IMPORTANT] If you're a solo developer, dependencies and SDK updates alone will consume a quarter of your time. Automate or die.
The takeaway is brutal: 77% of my hours go to keeping the lights on. Feature work is the reward, not the default.
I enforce a strict versioning and dependency convention across every module in every app. Every project shares the same
versions.toml[versions]
agp = "8.7.3"
kotlin = "2.0.21"
composeBom = "2024.12.01"
hilt = "2.52"
room = "2.6.1"
coroutines = "1.9.0"
[libraries]
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "coroutines" }Every app pulls from this file. When I need to bump Hilt across 22 apps, I change one line and run a script.
#!/bin/bash
# update-all.sh — run from project root
for dir in apps/*/; do
echo "Updating $dir..."
(cd "$dir" && ./gradlew dependencyUpdates --init-script update.gradle)
doneThis alone cut my per-app update time from 20 minutes to 5. Multiply by 22 and you save hours per cycle.
[!TIP] Keep a single
in a shared repo. Reference it viacodeversions.tomlin each app. Never hardcode versions insidecode../versions.toml.codebuild.gradle.kts
I run GitHub Actions on every push to
mainname: Build and Test All Apps
on:
push:
branches: [main]
jobs:
build-test:
runs-on: ubuntu-latest
strategy:
matrix:
app: [app1, app2, app3, app4, app5, app6, app7, app8, app9, app10]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "temurin"
- name: Build and Test
run: |
cd apps/${{ matrix.app }}
./gradlew assembleDebug testDebugUnitTest
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.app }}-debug
path: apps/${{ matrix.app }}/build/outputs/apk/debug/*.apkI don't test every app on every push. I rotate a subset weekly. Full matrix runs on release branches only. This keeps CI costs under $30/month while catching 90% of regressions.
[!WARNING] Don't run full instrumented test matrices on every push. Your CI bill will eat your margins. Reserve full test runs for release candidates.
I also maintain a
health-check.sh#!/bin/bash
# health-check.sh
echo "Running pre-push checks..."
for app in apps/*/; do
echo "Checking $app..."
(cd "$app" && ./gradlew lintVitalRelease --quiet)
if [ $? -ne 0 ]; then
echo "Lint failed for $app. Fix before pushing."
exit 1
fi
done
echo "All apps passed lint."This catches dependency conflicts, unused resources, and API mismatches before they hit CI.
With 22 apps, crash reporting is not optional. I use Firebase Crashlytics across every app with a unified alerting rule. All apps send crashes to a single Firebase project organized by app ID.
I set a threshold alert: if any app exceeds 0.5% crash rate over a 24-hour window, I get a Slack notification.
// BaseApplication.kt — shared across all apps
class BaseApplication : Application() {
override fun onCreate() {
super.onCreate()
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(BuildConfig.DEBUG.not())
FirebaseCrashlytics.getInstance().log("App started: ${BuildConfig.FLAVOR}-${BuildConfig.BUILD_TYPE}")
}
}I wrote a small Kotlin script that queries the Firebase REST API weekly and dumps a crash summary into a Google Sheet. This replaces manual dashboard checks.
[!NOTE] Keep crash rate alerts low (0.5% threshold). High thresholds mean you're ignoring problems until users leave reviews.
Every app update requires Play Store metadata. Screenshots need refreshing when UI changes. Promotional graphics need updating for seasonal campaigns. For 22 apps, this is a full day of work per quarter.
I batch metadata updates. Every first Monday of the month, I spend 4 hours updating changelogs, screenshots, and descriptions for all apps that shipped changes that month. I maintain a simple CSV tracker:
| App Name | Last Updated | Next Screenshot Refresh | Open Bugs |
|---|---|---|---|
| AppOne | 2026-05-20 | 2026-06-15 | 0 |
| AppTwo | 2026-05-22 | 2026-06-15 | 2 |
| AppThree | 2026-05-28 | 2026-07-01 | 0 |
This tracker lives in the repo's root. I update it during my monthly batch session. No app falls through the cracks.
versions.tomlSudarshan Chaudhari
AI Systems Builder / Product Engineer
Bangkok, Thailand
Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.
Related Posts
Related Apps
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
Building something? Available for Android dev and QA consulting.
Work with meComments — powered by Giscus
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
ReadPrivate dream journal — structured entry capture, pattern tagging, and optional Claude-powered insight generation. All data stays on-device by default.
ReadWorkout tracker — exercise logging with set/rep/weight history, goal progression, and local Room DB persistence. No account, no cloud sync required.
Read