Mr.AndroidShin / Dev Tools

By a solo Android developer

Small, fast tools for
Android & Jetpack Compose.

No sign-up, no clutter. Convert colors, size up your builds, and sort out Gradle versions — the everyday chores, done in one tap. Built and battle-tested while shipping real apps to Google Play.

Live tools
Live Color

Jetpack Compose Color Converter

HEX to Color(0xFF…), plus XML, RGBA, HSL, an alpha slider and a WCAG contrast check.

Live Layout

dp / sp / px Converter

Convert dp, sp and px across every density bucket (mdpi–xxxhdpi), with a font-scale option for text.

Live Revenue

AdMob eCPM & Revenue Calculator

Project daily, monthly and yearly ad revenue from DAU, impressions and eCPM — and calculate eCPM from earnings.

Live Reference

API Level ↔ Version ↔ Codename

Search any Android API level, version, codename or VERSION_CODES constant. Current to API 37.

Live Data

JSON Formatter & Validator

Pretty-print, validate and minify JSON with clear error messages. Runs entirely in your browser.

Live Auth

JWT Decoder

Read a token's header and payload, with expiry and issued-at shown as dates. Decodes locally — no upload.

Live Time

Unix Timestamp Converter

Convert epoch ↔ date in local time and UTC, seconds or milliseconds, with a live current timestamp.

Live Assets

App Icon Generator

One square image → ic_launcher in every density (mdpi–xxxhdpi), round icons and the 512px Play icon, zipped.

Live Utility

QR Code Generator

Turn a Play Store link or any text into a QR code and download a crisp PNG. Runs entirely in your browser.

Live Resources

strings.xml Escaper

Paste plain text → a properly escaped Android string resource. Fixes apostrophes, quotes, ampersands and more.

Live Accessibility

Color Contrast Checker

Check text vs background against WCAG AA/AAA. Live ratio, pass/fail, and a preview — all in the browser.

Live Photography

Exposure Calculator

Phone Pro mode: set a shot, see every shutter/ISO pair with the same brightness. Freeze motion or cut noise.

Live Encoding

Base64 Encoder / Decoder

Encode and decode Base64 with correct UTF-8 handling, URL-safe mode and data URIs. Runs in your browser.

Ad slot — insert your AdSense unit here
Field log — long-form
Field log Play Console

Where to actually find 12 testers

The hard part of the closed-testing rule isn't the number — it's finding twelve real opt-ins who stay. Where to look, and how to keep them.

Field log Backend

Firebase Functions vs a cheap VPS

Does your app even need a server? And if so, when serverless wins, when a small VPS is the better call, and how to choose without over-building.

Field log Monetization

My AdMob revenue looked broken — it was volume

The four dashboard numbers that prove your ads work, and why near-zero earnings are almost always traffic, not config.

Field log Security · AI

Calling an LLM without shipping your API key

Why a key in buildConfigField ends up in the APK, and the server-proxy pattern that keeps it out of users' hands.

Field log ARCore

Measuring a child's height with ARCore

Plane drift, the top-of-head problem, and why a humble calibration step carried more than any clever vision math.

Field log Migration

Migrating 10 apps to target API 36 in one weekend

The full version chain, every error I actually hit, and the two that cost the most time even though neither was a code bug.

Field log Play Console

The 12-tester, 14-day gate: what resets the clock

What "opted in" really counts, the re-apply trap that restarts your 14 days, and the mistakes that quietly drop you below 12.

Field log Hardware · BLE

Fighting engine vibration in a BLE brake sensor

Why a running engine breaks naive brake detection, and the signal-processing and mounting changes that finally made it reliable.

Field log Localization

My app shipped English-only despite full translations

How App Bundle per-language splits strand your translations, how I reproduced it locally, and the two reliable fixes.

Guides
Read Hosting

When to move off free hosting

When free tiers stop being enough, when a VPS actually makes sense, and why DigitalOcean is a clean first cloud — honest pricing and alternatives included.

Read Gradle

minSdk vs targetSdk vs compileSdk

What each SDK setting actually controls, how they relate, and how to choose sensible values.

Read App Bundle

Fix missing translations in an AAB

Why language splitting shows English instead of your translations — and the one-line fix.

Read Play Console

Closed testing: 12 testers for 14 days

Who the rule applies to, how to set it up, and why apps still get rejected after the 14 days are up.

Read Play Console

Play App Signing explained

Upload key vs app signing key, what happens if you lose your upload key, and how to keep your keystore safe.

Read Play Console

AAB vs APK, explained

What the App Bundle is, why Play wants it, how users still get an APK, and when to build an APK yourself.

Read Photography

Phone Pro mode: setting exposure

What ISO, shutter and exposure compensation do, how to read the meter, and starting settings for common scenes.

Open Community

Beta testers wanted — help each other launch

Join the tester group to help pass a closed test, and submit your own app so we test each other's. Mutual, no cost.

Debugging log
War story Build

targetSdk 36 build errors, and their fixes

The real errors from bumping to API 36 — AGP/Gradle/Kotlin chain, lint-vital failures, a Windows file lock — each with the fix.

War story Play Console

Production access "needs more testing"

Usually not a rejection — it's the 14-day clock restarting. Why it happens and how to stop re-triggering it.

War story Play Console

Internal vs closed testing: which counts

Only one track satisfies the 12-tester production requirement. What each is for, and the mistake of testing on the wrong one.

War story Play Console

What if you miss the target API 36 deadline?

Your live app stays up — you just can't ship updates. Exactly what's blocked, what isn't, and how to request an extension.

War story Billing

Play Billing 8: removed & changed APIs checklist

Grep your billing code against this list: what changed, what's gone, and the five things you don't need to touch.

War story Play Console

The target API 36 deadline (Aug 31)

What the Android 16 requirement actually blocks, and the AGP/Gradle chain reaction one line sets off. From migrating ten apps.

War story Billing

Play Billing Library 8 migration

The one breaking change that touched every app: queryProductDetailsAsync now returns a result object, not a List.

War story UI

Content hidden behind the status bar

Edge-to-edge is enforced on API 35/36. Enable it and consume window insets so your toolbar and buttons stop getting clipped.

War story Gradle

Requires compiling against a newer API

A library bump forced a compileSdk bump. What checkDebugAarMetadata enforces, and why raising compileSdk is safe.

War story Build

More than one file found with path META-INF/…

Two dependencies shipped the same metadata file. The packaging { resources { } } fix — and when not to pickFirst.

War story Gradle

Gradle ran out of heap

"JVM heap space is exhausted." How to size org.gradle.jvmargs correctly instead of just cranking it to the max.

War story Build

Cannot fit classes in a single dex file

The 64K method-reference limit, when multidex is the fix, and why shrinking with R8 is often the better one.

War story Compose

@Composable invocations can only happen from a @Composable

Why Compose rejects composable calls in onClick, coroutines and helpers — and the state-driven fix.

War story Resources

AAPT2 error: check logs for details

The message hides the real cause. How to surface the actual error line and fix the common culprits.

War story App Bundle

My app shipped in English only

Translations worked in debug but the released bundle served English. What I ruled out, the real cause, and the one-line fix.

War story AdMob

Don't ship real AdMob IDs in a closed test

Closed-test taps on live ads are real traffic. Use demo units or test devices so you don't get flagged for invalid activity.

War story Gradle

Firebase broke my build with a Kotlin error

What "incompatible version of Kotlin" means, why a Firebase BoM bump triggers it, and how to line the versions back up.

War story Gradle

Inconsistent JVM-target compatibility

Gradle stopped my build because Java and Kotlin targeted different JVM versions. Why they drift, and the one-line toolchain fix.

War story Release build

Debug works, release crashes

The release build crashed on launch while debug was fine. It was R8 stripping classes I use via reflection — and the keep rules that fixed it.

War story Gradle

"Duplicate class" found in modules

One new dependency pulled the same library in twice. How to find the two culprits and exclude the duplicate.

War story Install

INSTALL_FAILED_UPDATE_INCOMPATIBLE

Android refused the install because the APK was signed with a different key than the copy on the device. Why, and the safe fixes.

War story Compose

@Preview fails but the app runs

The preview pane showed a render error while the app ran fine. Why previews break — ViewModels, context, real data — and the split that fixes it.

War story Firebase

Default FirebaseApp is not initialized

Firebase crashed on the first call. Usually the google-services plugin or config file is the missing piece — here's the checklist.

War story Manifest

Manifest merger failed

A library set the same attribute to a different value than my app. What the merged manifest is, and how tools:replace resolves it.

War story Gradle

SDK location not found

A fresh clone wouldn't build: local.properties never travels with the repo. Why that's correct, and the right way to fix it.

War story Networking

Cleartext HTTP traffic not permitted

Android blocks plain HTTP by default. Why usesCleartextTraffic=true is the wrong fix, and how to scope it to a dev server.

War story Signing

Keystore was tampered with

The scariest message in Android signing almost always just means a wrong password. How to tell which one, with keytool.

Coming soon
Soon Build

AGP · Kotlin · Compose Version Check

Find a compatible set of Gradle plugin, Kotlin and Compose compiler versions.

Why these tools exist

Every one of these started as a chore I hit while building and publishing my own Android apps — pasting a hex into a Color(0xFF…) literal, checking whether a color passed contrast, working out which Kotlin version a Compose compiler wants. Instead of searching each time, I turned them into small single-purpose pages that load fast, run entirely in your browser, and never ask you to sign in. New tools land here as I build them.

Ad slot — insert your AdSense unit here