Skip to main content

SBPO Consulting · Mobile

Android app development for the devices people actually own

Android is not one device. It is thousands of them, across a decade of OS versions, several manufacturer software layers and screen shapes that change while the app is running. Building well here means planning for that spread deliberately, rather than discovering it in the crash reports.

Where we come in

The android problems this solves

  • The app is stable on the team's Pixels and generates most of its crash reports from manufacturers nobody in the office owns.
  • Your Android build is years behind the iOS one because it was treated as the second platform from the start.
  • You have an ageing Java codebase, the original developer has moved on, and nobody wants to touch it.
  • Google Play has started warning you about a target API level deadline and you are not sure what happens if you miss it.
  • Store reviews mention battery drain or the app freezing, and you have no data that tells you where.
  • The app looks like an iPhone app that has been resized, and Android users say so in the reviews.

Android needs its own plan, not a port

The most common way an Android app goes wrong is that it was never planned as an Android app. It was planned as an iOS app, built first, and then translated — same navigation, same gestures, same assumption of a narrow, well-behaved set of devices.

Android does not reward that. It runs on hardware from a large number of manufacturers, each with its own software layer on top of the operating system, its own approach to killing background processes, and its own camera and power management behaviour. The screen might fold. The system font might be set two sizes larger than your designer imagined. The device might have been good in 2021 and be running an OS three versions behind today.

None of this makes Android harder in a mysterious way. It makes it harder in a specific, plannable way, which is the useful news: the failures are predictable enough to design against if you decide to.

Kotlin and Jetpack Compose as the default

We build in Kotlin unless there is a concrete reason not to, and the reason is not fashion. Android has been officially Kotlin-first since 2019, meaning Jetpack libraries, documentation, samples and tooling are designed for Kotlin with Java support trailing behind. Google’s own comparison puts apps written in Kotlin at twenty per cent less likely to crash, which is largely the compile-time null safety doing its job on the single most common crash class in Android’s history.

Jetpack Compose is the interface layer. Declarative UI removes an entire family of bugs around view state getting out of sync with data, and it makes theming genuinely systemic: colour roles, typography and shape are defined once and every screen inherits them. That is what makes dark theme, dynamic colour and large-text support properties of the app rather than three separate retrofits.

Compose interoperates with the older View system in both directions, which matters for existing apps. A screen at a time is a viable migration path, and it is nearly always the right one, because a total rewrite trades a known set of small problems for an unknown set of large ones.

Designing to Material Design 3

Material Design 3 is not decoration, it is a set of conventions your users have already learned from every other app on their phone. Navigation placement, the behaviour of the system back gesture, how a sheet dismisses, where a floating action button belongs — these are expectations, and violating them is expensive in reviews.

Working within the system also handles a set of requirements you would otherwise meet individually: dynamic colour derived from the user’s wallpaper, dark theme that is a real theme rather than an inverted palette, and components that already scale with the system font size. Where the interaction design is the substantial part of a project, we run it as design work in its own right, using Material as the grammar rather than the whole vocabulary.

Fragmentation, handled as a plan rather than a worry

“Android fragmentation” is usually said in a tone of complaint, which is not useful. Treated as a scoping exercise it becomes tractable.

We start with your data. OS version distribution, manufacturer mix, screen size and density classes, and memory profile from your existing analytics — or from your target market if the app is new. That evidence sets three things: the minimum SDK, the device matrix that will be physically tested, and the list of what is explicitly out of scope.

Every one of those is a cost decision. Supporting an Android version two years older extends your reach and costs testing time and compatibility branches. Supporting foldables and tablets properly means designing adaptive layouts rather than stretching a phone layout across a large screen. Wear OS or Android Auto are separate products with their own review criteria, not a checkbox. We would rather have that conversation with numbers at the start than have it as a change request halfway through.

Google Play’s own delivery model helps on the size side. App bundles have been the required publishing format for new apps since August 2021, and they let Play generate device-specific downloads rather than shipping every user every resource and every architecture.

Architecture that survives a handover

The architecture question we care most about is not which pattern, it is whether a competent Android engineer who has never met us can open the project and understand it in a morning.

In practice that means a unidirectional data flow with view models holding state, a repository boundary so the interface layer does not know or care whether data came from the network or from local storage, coroutines and flows for asynchronous work, and dependency injection where it removes real coupling rather than because a diagram wanted a box. Modularisation happens when build times or team size actually justify it. A four-screen app split into eleven Gradle modules is not architecture, it is a tax.

Local persistence generally means Room, network access Retrofit, deferred and constrained work WorkManager — the boring, well-documented choices, because an app that outlives its original team is worth more than an app that showcases one.

Security follows the same principle of being checkable. Credentials belong in the platform keystore rather than in shared preferences, transport security is configured explicitly, and where an app has something worth attacking — payments, licensing, gated content — the Play Integrity API can tell your server whether the request came from an unmodified build on a genuine device, installed by an account that actually obtained it from Google Play. We review this against the OWASP Mobile Application Security Verification Standard so the discussion cites a published document rather than our opinion.

Selling digital goods through Google Play

If the app sells digital content or subscriptions, Google Play’s billing system is not an integration you can defer. It is a policy requirement for digital goods, it carries its own version deadlines — new apps and updates must use Billing Library version 8 or later from 31 August 2026 — and it is the part of the app where bugs turn into refunds.

The work that actually repays effort is in the states nobody demonstrates: a purchase interrupted by a lost connection, an entitlement restored on a new device, a subscription that lapses and resumes, an upgrade mid-period, a refund issued from the Play side. Entitlement is verified server-side using the Play Developer API rather than trusted from the client, with real-time developer notifications keeping your records aligned with Google’s. Physical goods and services are a different matter entirely and belong outside the billing system, which is a distinction worth confirming before your business model assumes otherwise.

Performance, battery and the numbers Play watches

Android measures your app whether you do or not, and it acts on the results.

Google Play’s Android vitals tracks core vitals including the user-perceived crash rate and the user-perceived ANR rate, with bad-behaviour thresholds set at 1.09% and 0.47% respectively over a rolling 28-day window. Exceed them and Play can reduce your store visibility and show users a warning on the listing. Excessive wake locks and memory usage sit alongside those as further quality signals.

That reframes performance work. Frame rendering, startup time, background work scheduling and wake lock discipline are not polish to be done if there is budget left — they feed a metric that determines how findable the app is. Google’s core app quality guidelines are similarly concrete: frames rendered within the 16ms budget for smooth scrolling, and visible feedback if startup takes more than a couple of seconds.

The practical consequence in our process is that staged rollout is a control rather than a ceremony. Crash and ANR rates are checked at each rollout increment, and a regression stops the release rather than being noted for next time.

Accessibility on Android

Accessibility on Android is largely a matter of doing four things consistently, and inherited apps usually fail at all four.

Every interactive element needs a content label, decorative images need to be explicitly marked as decorative so TalkBack skips them, headings and panes need semantic marking so a screen reader user can navigate structurally, and layouts need to survive the largest system font scale without clipping. Touch targets have a stated minimum of 48dp in Google’s core app quality guidelines, and text contrast of 4.5:1 for small text and 3:1 for large text.

Compose makes most of this a matter of setting semantics properly, which is cheap during development and irritating afterwards. We test with TalkBack running rather than relying on an automated scan, because the common failures — an unlabelled icon button, a form where focus order makes no sense — are obvious in thirty seconds of real use and invisible to a linter.

Testing and release through Play Console

Unit tests cover logic, instrumentation tests cover the journeys that matter commercially, and both run as part of the release process rather than when someone remembers. Beyond that, physical devices from the lower end of your support matrix, plus a cloud device lab for breadth.

Google Play’s release tracks then do the rest of the work. Internal testing distributes to up to 100 testers for quick quality checks, closed testing supports much larger invited groups, and open testing exposes a build publicly before production. Used in sequence with a staged production rollout, this catches manufacturer-specific problems while the affected population is small enough to be an inconvenience.

The listing itself deserves separate attention: install rate is a ranking input on Play, and store listing optimisation is a different discipline from building the app.

The deadlines you cannot ignore

Android maintenance runs on a published calendar, which is at least honest of it.

Target API level requirements are the big one. From 31 August 2026 new apps and updates must target Android 16 (API level 36) or higher, with different levels for Wear OS, TV, Automotive and XR, and existing apps must target at least Android 15 to remain available to new users on newer devices. Extensions can be requested through Play Console, which buys time rather than removing the obligation. Apps selling digital goods have a parallel obligation to keep the Play Billing Library current — version 8 or later for new apps and updates from the same date.

We map these against your release schedule at the start of an engagement so they become planned work. It is a dull thing to be good at, and it is the difference between an app that is still installable in three years and one that quietly is not.

How Android fits with the rest

Most organisations are not building for Android in isolation. If both platforms are in scope, the iOS side has a different set of constraints — review, privacy declarations and an annual OS cadence of its own — and a single shared codebase is worth considering before you commit to two teams. The overall trade-offs sit on our mobile app development page, which is the right place to start if the platform decision is still open.

If you already have an Android app and mainly want to know how bad it is, an audit is a reasonable first conversation and does not commit you to a rebuild.

Scope

What our android app development services include

Every engagement is scoped in writing before it starts. These are the artefacts that leave our hands and become yours.

  1. A production Android app in your repository

    Kotlin source, Gradle configuration, signing set up for release, and documentation that lets an engineer who has never seen the project produce a signed build on their first day.

  2. Android App Bundle configured for Play delivery

    Release artefacts published as app bundles so Google Play generates optimised downloads per device configuration, with Play App Signing set up and the upload key recorded and handed to you.

  3. A device and OS support matrix, agreed in writing

    The minimum SDK, the target SDK, the manufacturers and screen classes in scope, and the ones deliberately excluded. Every one of those is a cost decision, so each is made openly rather than by default.

  4. Material Design 3 screens with themed light and dark modes

    Layouts built from the design system with typography, colour roles and components defined once, including dark theme and large-text behaviour rather than a light-mode design that degrades when the system changes.

  5. Automated test suite and instrumentation coverage

    Unit tests for logic, instrumentation tests for the critical journeys, and a run configuration that executes them on physical or cloud-hosted devices as part of the release process.

  6. Google Play Console configured properly

    Store listing, content rating, Data safety declaration, testing tracks and staged rollout configured under your own developer account, with your team holding the owner role rather than us.

  7. Crash, ANR and vitals monitoring

    Crash reporting wired to a named recipient and the Android vitals dashboard reviewed as part of every release, so regressions surface as data rather than as one-star reviews.

  8. A version and dependency upgrade plan

    The published target API level deadlines, billing library requirements and library upgrades that will affect you, mapped to a schedule so the maintenance is planned work rather than an emergency.

How it runs

How SBPO Consulting delivers android

  1. Establish the real device landscape

    Before any architecture decisions, we look at what your users actually hold: OS version distribution, manufacturer mix, screen sizes and memory classes from your own analytics where they exist, or from your market where they do not. That data sets the minimum SDK and the test matrix, and it usually surprises people.

  2. Choose the smallest architecture that fits

    A unidirectional data flow, a view model layer, a repository boundary and dependency injection where it earns its place. Modularisation is applied when build times or team size justify it, not because a diagram looks impressive in a proposal.

  3. Build the interface in Compose against Material Design 3

    Declarative UI with theming, typography and colour roles defined once and applied everywhere, so dark mode, dynamic colour and large text are properties of the system rather than three separate pieces of retrofitting.

  4. Test on hardware, including the awkward hardware

    Unit and instrumentation tests run continuously, then physical devices covering the low end of your support matrix. A mid-range handset three years old will find problems no emulator will, particularly around memory and background process death.

  5. Release in stages through Play Console

    Internal testing, then closed and open tracks where the audience justifies them, then a staged production rollout with crash and ANR rates watched at each percentage before the next increment. A bad release caught at five per cent is an inconvenience rather than an incident.

  6. Monitor vitals and keep the app current

    After launch, Android vitals and crash reporting are reviewed on a schedule, and platform deadlines are handled ahead of time rather than when Play Console starts warning about them.

Tooling

Tools and platforms we use for android

We pick tools for the problem, not for the résumé. Where a platform is a poor fit we will say so before you have paid for it.

Language and UI

  • Kotlin
  • Jetpack Compose
  • Material Design 3
  • Kotlin Coroutines
  • Kotlin Flow

Architecture and data

  • Android Jetpack
  • Room
  • Retrofit
  • DataStore
  • Hilt
  • WorkManager

Build and tooling

  • Android Studio
  • Gradle
  • R8
  • Android App Bundle
  • Fastlane

Quality and release

  • JUnit
  • Espresso
  • Firebase Test Lab
  • Firebase Crashlytics
  • Google Play Console testing tracks

Play services

  • Google Play Billing
  • Play Integrity API
  • Firebase Cloud Messaging
  • Play Feature Delivery

Non-negotiables

The standards SBPO Consulting works to

These are checkable. Ask us to demonstrate any of them on your own project before you sign anything.

  1. Your developer account, your upload key

    The Google Play developer account is registered to your organisation with your team as owner, and the upload key is recorded and handed over. Losing control of signing material is one of the few genuinely unrecoverable situations in Android, so we do not let it depend on us.

  2. Support matrix agreed, not assumed

    Minimum SDK, target SDK and the tested device set are written into the scope. If supporting an older Android version costs meaningfully more, you get told the price before the decision, not after the estimate.

  3. Accessibility checked with TalkBack

    Content labels on every interactive element, correct heading semantics, touch targets at the 48dp minimum from Google's core app quality guidelines, and layouts that hold together at the largest system font scale.

  4. Vitals treated as a release gate

    Crash and ANR rates are reviewed against Google Play thresholds during staged rollout, and a regression stops the rollout. Store visibility depends on these numbers, so they are release criteria rather than a report.

Questions

android app development services — questions we get asked

Which Android versions should my app support?

The honest answer comes from your own data rather than from a rule of thumb. Every additional older version you support costs testing time and constrains which APIs you can use without compatibility branches, so the decision is a commercial one. Two things are not negotiable: Google Play sets a minimum target API level for apps that want to keep publishing updates, currently Android 16 (API level 36) for new apps and updates from 31 August 2026, and apps that stay on older targets stop being available to new users on newer devices. Supporting old versions at the bottom end is a choice; falling behind at the top end is a slow removal from the store.

Why do you build in Kotlin rather than Java?

Because Google does. Android has been officially Kotlin-first since 2019, which means new Jetpack libraries, samples, documentation and tooling are designed for Kotlin and Java support follows behind. Google also reports that Android apps using Kotlin are twenty per cent less likely to crash, largely because the language removes an entire category of null-related failure at compile time. Existing Java code is not a problem, since the two interoperate fully and a codebase can be migrated file by file rather than rewritten.

How do you test across so many Android devices?

With a matrix, not with hope. We take the manufacturer and OS version distribution from your analytics, pick physical devices covering the low end and the awkward middle of that range, and use a cloud device lab for breadth on top of that. Emulators are used continuously during development and trusted for logic, not for memory pressure, battery behaviour, camera stacks or manufacturer-specific background process management, which is where the real failures live. Staged rollout then acts as the final control: a problem that only shows on one manufacturer usually appears in the vitals data within the first few per cent of users.

What causes Google Play submissions to be rejected?

Policy, almost always, rather than code. The recurring causes are a Data safety declaration that does not match what the app actually collects, permissions requested without a clear in-app justification, missing account deletion where an account can be created, content or ads inconsistent with the declared rating, and metadata that overstates what the app does. Google publishes the developer programme policies in full, and reading the ones relevant to your category before the build starts is considerably cheaper than reading them after a rejection. We prepare the declarations alongside the app rather than filling them in on submission day.

Can you modernise an older Android app built in Java?

Yes, and incrementally is usually the right approach. Kotlin and Java coexist in the same module, so new work can be written in Kotlin while existing classes are converted as they are touched. Compose interoperates with the older View system in both directions, which means screens can be migrated one at a time rather than in a single risky rewrite. The first step is always an audit: whether the project builds from a clean checkout, how far behind the target API level it is, what state the dependencies are in, and whether the signing key still exists. Occasionally that audit concludes a rewrite is cheaper, and we will show you the arithmetic rather than simply assert it.

How do Android Vitals affect visibility on Google Play?

Directly. Google Play tracks a set of core vitals including the user-perceived crash rate and user-perceived ANR rate, and defines bad-behaviour thresholds at 1.09% and 0.47% respectively, assessed over the previous 28 days. Apps exceeding those thresholds can have their store visibility reduced, and Play may show a warning on the store listing. In other words stability is a discovery factor, not just an engineering quality measure. It is also why we treat a rising crash rate during staged rollout as a reason to stop rather than as something to fix in the next release.

What does ongoing Android maintenance involve?

Mostly work that produces no new features. Each year brings a new Android release with behaviour changes and deprecations, plus published deadlines you have to meet to keep publishing: target API level requirements, and current billing library versions for apps selling digital goods. Add dependency and Gradle upgrades, manufacturer-specific bugs that appear with OEM software updates, crash triage, and design changes that alter how existing screens render. A realistic arrangement assumes several small releases a year even if nothing about the product changes.

Adjacent work

iOS

Swift and SwiftUI apps for iPhone and iPad, designed to Apple conventions and checked against the review, privacy and accessibility rules long before anything is submitted.

Cross-platform

Flutter and React Native apps built from a single codebase, with the framework chosen on your constraints and the cases where cross-platform is the wrong answer named before you commit.

App store optimization

Keyword strategy, listing copy, creative testing and store analytics for the App Store and Google Play — measured on installs and retained users, not on ranking screenshots.

Part of our mobile apps practice.

Mobile

Let's talk about your android work.

Send us the problem, the constraint and the deadline. You will get a considered reply from someone who would actually do the work — not a templated proposal.