Android
Kotlin and Jetpack Compose Android apps, built for the real spread of devices and OS versions your users carry, and kept inside Google Play policy long after launch.
SBPO Consulting · Mobile
Building the app is the cheap part. What costs money is the second year: the OS release that breaks a dependency, the store policy deadline nobody diarised, the crash that only appears on one manufacturer's software. We build mobile apps with that year already in the plan.
Where we come in
A website can be left alone for a year and still work. A mobile app cannot. Apple and Google each ship a major operating system release annually, each enforces a minimum target API level for anything you want to keep publishing, and each will quietly stop distributing a build that falls behind.
Google’s current rule shows the shape of the problem plainly. From 31 August 2026, new apps and app updates on Google Play must target Android 16 (API level 36) or higher, and apps left on older targets stop being available to new users on devices running newer Android versions. Nothing crashes. Nothing is deleted. The app simply becomes uninstallable for a growing share of the market, and the first anyone notices is a confused support email.
That is why we scope mobile app development as a multi-year commitment rather than a delivery. The interesting question is almost never whether something can be built — it usually can. It is what the thing will cost to keep alive once real people depend on it, and whether it deserves to exist in the first place.
We talk clients out of apps more often than we talk them into one, and the reason is nearly always the same: the idea does not need to be installed.
Installation is an enormous ask. Someone has to find you in a store, trust you enough to grant permissions, accept an update cadence, and keep an icon on a finite home screen. In exchange, an app must offer something a good mobile website cannot: dependable offline use, background behaviour that survives the app being closed, deep hardware access, push as a genuine part of the product rather than a marketing afterthought, or a habit frequent enough that the icon earns its space.
If your concept is essentially a catalogue, a booking flow, a set of forms or a content library, a well-built responsive site will be cheaper, instantly available, indexable by search engines, and changeable without waiting for review. Apple is unusually direct about this: its minimum functionality guideline exists precisely to reject apps that are repackaged websites with nothing added. Wrapping a site in a shell is not a cheap route to the App Store; it is a rejection with a delay attached.
Where an app is right, that same test tells you what version one should contain. The features that justify installation come first. Everything else can wait, and most of it should.
They are usually procured as though they were one thing, which is where a good deal of misalignment starts.
A consumer app competes for attention with everything else on the device. Its hardest problems are acquisition and retention, not features: the store listing has to convert, the first session has to deliver something before the user decides, and the onboarding has to ask for permissions in an order that does not feel like an interrogation. Rating prompts, push strategy and the empty state on day one matter more than the twelfth screen. Discovery is a discipline in itself, which is why we treat it separately.
A B2B or client-facing app is usually chosen by someone who will not use it. The buying decision runs on procurement criteria — security posture, single sign-on, data residency, an audit trail — while the adoption depends on people who were handed it in a meeting. Both audiences have to be designed for, and the second is the one that determines whether the contract renews. Accessibility obligations are frequently contractual here rather than optional, and enterprise device management adds constraints that are cheaper to learn about at the start.
An internal app has the smallest audience and often the clearest return, because you can measure the process it replaces. It also has the most forgiving distribution: managed deployment can sidestep public store review entirely, which changes the calculus on release cadence and on how much design polish is worth buying. The risk it carries instead is that requirements come from whoever asked loudest, so scope discipline matters more here than anywhere else.
The shape of the project — how much research, how much design, how much store work, how much integration — follows from which of these you are building. Being explicit about it in the first conversation prevents most of the arguments that happen later.
There is no universally correct answer here, only a trade you should make deliberately rather than inherit from whoever you happened to hire.
React Native and Flutter both let one team ship to both stores, and for content-led, form-led and commerce apps the results are frequently indistinguishable from native to anyone who is not looking for the seams. They work in different ways, and the difference matters. React Native renders real platform views, and its New Architecture — the Fabric renderer, TurboModules and the JavaScript Interface that replaced the old asynchronous bridge — has been the default since version 0.76. Flutter takes the opposite approach and draws everything itself through its own rendering engine, shipping its own implementations of platform controls rather than deferring to the system.
The consequence is practical. Flutter gives you an interface that is identical everywhere, which is either the point or the problem depending on your product. React Native inherits platform behaviour more naturally, and inherits platform quirks along with it.
The cost rarely priced in either case is the abstraction layer itself. You are now maintaining a framework version as well as two operating systems, and when a platform ships a new capability you either wait for framework support or write native code anyway.
Native is the right call when the app lives close to the hardware or close to the platform: sustained camera and sensor work, complex background processing, widgets, watch and car surfaces, tight integration with system features, or anything where you need a new OS capability on the day it ships. It is also the pragmatic choice when only one platform matters commercially, which is more common than agencies tend to admit. Building for both because a single-platform app feels incomplete is one of the more expensive habits in this industry.
We keep separate pages for Android app development and iOS app development because the two disciplines genuinely diverge below the surface, plus one on shared-codebase work for when that trade is worth making. The recommendation comes after the feature list exists, not before.
Most app overruns are not engineering failures. They are the accumulated cost of features that arrived without a decision, each individually reasonable and collectively fatal.
So we write the list down. Every feature gets a line, a size, and a note recording whether it is in version one and why. The deferred list is kept visible rather than deleted, because the useful artefact is not the plan — it is the record of what was consciously left out, which is what stops the same conversation happening four times.
The discipline that pays for itself most reliably is asking what happens when things go wrong. Empty states, no network, a failed payment, an expired session, a permission the user denied, a device on three per cent battery in a lift. Designing those paths early is unglamorous, and it is where apps are actually won or lost, because the happy path is the easy portion of the work and everybody remembers to build it.
Android and iOS are not two skins over the same product. They differ in navigation model, back behaviour, typography, motion, and where users expect a control to live. An app that imposes one platform’s conventions on the other feels subtly wrong in a way users rarely articulate and reliably punish in reviews.
Practically, that means designing twice at the level of interaction while designing once at the level of brand: shared visual language, platform-appropriate structure. It also means treating accessibility as a design constraint rather than a remediation phase. Android’s core app quality guidelines set a minimum touch target of 48dp and contrast ratios of 4.5:1 for small text and 3:1 for large text. Apple sets comparable expectations and adds Dynamic Type, which means your layout has to survive a user who has turned the system text size up considerably. Layouts designed at one text size that clip at another are the most common accessibility failure we find in inherited apps, and they are cheap to prevent and tedious to retrofit.
Where the interaction design is the substantial part of the project, our product design practice leads it rather than treating it as a phase inside the build.
Most apps are a client for something. The quality of that something determines more of the app’s behaviour than the app code does.
The decision carrying the most weight is how much has to work without a connection. “Works offline” ranges from caching the last screen the user saw — cheap, sensible, worth doing almost always — to full local writes with synchronisation and conflict resolution, which is one of the genuinely hard problems in software and should be scoped as such. Being clear about which one you need, early, prevents the most expensive mid-project pivot in mobile work.
Alongside that sit the parts users never see: authentication and token refresh, secure credential storage in the platform keystore rather than in preferences, certificate handling, background work scheduling, and push delivery through Apple Push Notification service and Firebase Cloud Messaging. We review these against the OWASP Mobile Application Security Verification Standard, which groups mobile security into concerns such as storage, cryptography, authentication, network and platform interaction. Using a published standard means the security discussion refers to a document you can read and audit us against, rather than to our reassurance.
Simulators are a development convenience. They are not evidence, and they will not reproduce a manufacturer’s memory management, a three-year-old mid-range chipset, or a network that drops halfway through a payment.
A serious test plan covers a device matrix drawn from your own analytics rather than from whatever the team happens to own, the oldest OS version you have committed to supporting, screen shapes from compact phones to tablets and foldables, throttled and offline networks, and interruption cases: an incoming call, a backgrounded app killed by the system, a rotation mid-form.
Beta distribution is where this becomes real. TestFlight allows up to 100 internal testers and up to 10,000 external testers, with external builds requiring Apple’s Beta App Review before they reach anyone. Google Play offers internal testing for up to 100 testers, plus closed and open tracks for progressively wider groups. Used properly these are not a formality — they are the cheapest bug reports you will ever receive, because they come from real devices in real hands before the public listing exists.
An app is not finished when it is approved. It is finished when the numbers behave, and both stores now measure you against thresholds that affect distribution.
Google Play’s Android vitals treats an app as exceeding its bad-behaviour threshold when the user-perceived crash rate rises above 1.09% or the user-perceived ANR rate above 0.47%, assessed over a rolling 28-day window. Apps beyond those thresholds can have their store visibility reduced, and may have a warning shown to users on the store listing. That is worth sitting with for a moment: stability is not only an engineering quality measure, it is a distribution input. An app that crashes for one user in fifty is not merely annoying, it is harder to find.
So crash reporting is configured before launch, not after the first incident, with alerting thresholds set and a named person receiving them. The first fortnight after release is monitored daily. Most of what you learn in that window is unglamorous — an SDK misbehaving on one OS version, a timeout that only appears on slow networks — and fixing it quickly is the difference between a stable base and a review section you spend a year recovering from.
Every year, without exception, a new iOS and a new Android version change behaviour, deprecate APIs and occasionally alter how your existing screens look. Every year, store requirements move on published dates: target API levels, billing library versions for apps selling digital goods, privacy declaration formats. None of this is optional, and none of it produces a new feature, which is exactly why it gets omitted from budgets and then discovered as an emergency.
We map those published deadlines onto a calendar at the start of an engagement, so the maintenance conversation is about a date on a schedule rather than a surprise. If you take nothing else from this page: the useful question to ask any prospective app partner is not what the build costs, but what the second year costs, and what happens if you decide to work with somebody else.
An app rarely arrives alone. The listing it launches into is its own discipline, and store listing optimisation largely decides whether anyone finds it once it is live. If the app is a client for a service that does not exist yet, the server side sits with our web application team. And where the harder problem is the interaction model rather than the engineering, design leads and the build follows.
If you are not yet sure which of those you need, that is a reasonable place to begin a conversation — and a better one than arriving with a specification you have already committed to.
Scope
Every engagement is scoped in writing before it starts. These are the artefacts that leave our hands and become yours.
The features in version one, the features explicitly deferred, and the reasoning for each. Half of what makes app projects overrun is a feature nobody agreed to and nobody can point at the moment it was added.
Every screen and state designed against the conventions of the platform it runs on, assembled into a prototype you can tap through on a real handset before a line of production code is written.
Signed, release-configured builds for Android, iOS or both, with source code in a repository you own, a README that lets a new engineer build it, and no dependency on a machine only we have.
Where the app needs a server, you get the API, the data model, the authentication layer and a web interface for the people who manage content, users or orders — not a database someone has to be trained to edit directly.
Listing copy, screenshots at the required device sizes, privacy declarations, content ratings and the submission itself, handled through App Store Connect and Google Play Console under accounts registered to your organisation.
Developer accounts, signing certificates, upload keys and service credentials belong to you and are handed over documented. An agency holding your signing key is a commercial hostage situation, and we will not create one.
Crash and error reporting wired up before launch rather than after the first incident, with alerting thresholds set and someone named as the person who receives them.
The published platform deadlines that will affect your app — target API levels, billing library versions, privacy declaration changes — mapped against a calendar so the work is planned rather than discovered.
How it runs
We start by trying to talk you out of it. If the idea works as a responsive web experience, it will be cheaper to build, cheaper to change and available without an install. An app has to earn its place through something the web genuinely cannot do well: reliable offline use, background location, deep hardware access, or a habit that needs a home screen icon.
Every feature is written on a list, sized, and challenged. The version one scope is the smallest thing that is genuinely useful to a real person, because an app nobody uses is not improved by having more in it.
Navigation, typography, motion and control behaviour follow the Apple Human Interface Guidelines and Material Design 3 respectively. An app that ignores platform convention feels subtly wrong in a way users cannot articulate but reliably punish.
Each increment is a working path through the app — screen, logic, API, storage — rather than a horizontal layer that cannot be demonstrated. You see something installable on a device early and often, which is the only reliable way to catch a misunderstanding before it is expensive.
Physical handsets across the range your analytics say your users hold, throttled and offline network conditions, and screen reader passes with VoiceOver and TalkBack. Simulators are a development convenience, not evidence.
Store submission with review notes and demo credentials prepared, followed by a monitoring window where crash-free sessions, ANR rates and store vitals are watched daily rather than checked when someone complains.
Tooling
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.
Non-negotiables
These are checkable. Ask us to demonstrate any of them on your own project before you sign anything.
Developer accounts are registered to your organisation, signing material is handed over and documented, and the repository is yours from the first commit. Nothing about the arrangement depends on us remaining friendly.
Screens are navigated with VoiceOver and TalkBack, controls carry accessible labels, touch targets meet the platform minimums, and layouts survive the largest system text size rather than clipping at it.
Credential storage, transport security, authentication and platform hardening are reviewed against the OWASP Mobile Application Security Verification Standard, so the security conversation refers to a document you can read rather than to our assurances.
Target API level requirements, billing library versions and privacy declaration changes are diarised against published dates. We will tell you what is coming before the store does.
If your idea is better served by a mobile website or an internal tool, we will say so in writing before you spend anything. It is a poor way to maximise a single invoice and a good way to still be working together in three years.
Going deeper
Where mobile apps splits into genuinely distinct disciplines, each has its own team, its own method and its own page.
Kotlin and Jetpack Compose Android apps, built for the real spread of devices and OS versions your users carry, and kept inside Google Play policy long after launch.
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.
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.
Questions
It depends on how much of your app is genuinely platform-specific. Cross-platform frameworks such as React Native and Flutter let one team ship to both stores, and for content-led, form-led and commerce apps the result is close to indistinguishable from native. Native becomes the better answer when you are deep into hardware — sustained camera or sensor work, complex background behaviour, widgets and watch surfaces, or platform features that arrive with the OS release before any framework supports them. The cost you are trading is real either way: cross-platform saves you a second codebase and adds an abstraction layer that must itself be kept current. We make the recommendation after the feature list exists, never before.
The build is usually not the constraint. What sets the calendar is how quickly scope is agreed, whether the backend already exists, how many rounds of design review your organisation needs, and whether store accounts and legal documents such as a privacy policy are in place. Store review itself is typically short compared with the project, but a rejection resets it, which is why we prepare review notes and demo credentials properly rather than submitting hopefully. The reliable accelerator is a single decision-maker and a short version one, not more developers.
Six things, roughly in order of impact: the number of distinct screens and states; whether a backend has to be built or already exists; how many platforms are in scope and whether they share a codebase; how much of the app must work offline, since synchronisation and conflict resolution are far harder than they look; whether payments, subscriptions or regulated data are involved; and how much design work is needed against how much already exists. Anyone quoting before those are known is quoting a feeling. We scope in writing against each of them, and would rather show you a wide range with reasons than a narrow one with none.
Usually, yes, because an app without a way to manage its content or its users creates a support burden that lands on you. That means the API, the data model, authentication, and a web interface for whoever runs the service day to day. If you already have a backend we will integrate with it, and we will tell you honestly if its API shape is going to make the mobile client slower or more fragile than it needs to be. See web application development for how we approach the server side.
We try to make them unlikely first. Most rejections we see are avoidable and cluster around a few guidelines: incomplete submissions with broken links or placeholder content, apps that are essentially a wrapped website, missing or inaccurate privacy declarations, account deletion not being offered where an account can be created, and payment flows that route around the store for digital goods. Apple publishes the full App Review Guidelines and they are worth reading before you commission anything. If a rejection does happen, we respond through the review dialogue with a specific technical answer rather than resubmitting the same build and hoping for a different reviewer.
Yes, and it is a large part of what we do. The first step is an audit rather than a plan: can the project be built from a clean checkout, what state are the dependencies in, who holds the signing keys and store accounts, what does the crash data actually say, and how far behind the current target API level is it. That audit sometimes concludes that a rewrite is cheaper than a rescue, and we will show you the reasoning rather than assert it. Inherited apps most often fail on the boring things — lost keys and unbuildable projects — rather than on code quality.
More than most people budget for, and almost none of it is new features. Each year brings a major iOS and Android release that changes behaviour and deprecates APIs, alongside store requirements that move on published dates: Google Play sets a minimum target API level for continued updates, and requires current billing library versions for apps selling digital goods. On top of that sit dependency and SDK maintenance, certificate and key renewals, crash triage, and OS-level design changes that alter how your screens look. A sensible maintenance arrangement assumes several small releases a year even if the feature set never changes.
Adjacent work
Research-led interface and experience design for products people use repeatedly — flows, states, accessibility and a design system engineering can actually build from.
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.
Custom web application development for SaaS products, customer portals, dashboards and internal tools — with the scope discipline that decides whether a first release ships at all.
Mobile
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.