Mobile Development

iOS and Android app development: what to decide and why

Building for iOS and Android means deciding how much code the two apps share and how much each platform keeps for itself. Most business apps can share most of their code and still feel at home on each phone, while apps built around the camera, sensors, graphics or a new system feature often justify two native codebases. This page sets out the decisions in the order that matters, and when Swift and Kotlin are the right call.

Start a project

The first decision: native, shared or a mix

A native app is written separately for each platform, in Swift for iOS and Kotlin for Android. A cross-platform app shares most of its code. A middle route writes the business rules once and the screens natively. The right choice follows from the product, not from fashion.

ApproachWhat it meansUsually fits
Two native appsTwo codebases, one in Swift and one in KotlinApps built around device features, graphics or a platform's newest capabilities
One shared codebaseA framework such as Flutter or React Native, with native code where neededMost business apps: accounts, forms, lists, maps, payments and content
Shared logic, native screensRules and data code written once, interfaces written per platformTeams with strong native skills who want one set of business rules

Choosing between frameworks has its own pages, Flutter and React Native, so we do not repeat that comparison here. The article on native or cross-platform covers the wider question.

When native Swift and Kotlin is the right call

Native code earns its cost when the platform itself is the product. Choose it when:

  • The app depends on a deep device feature, such as a custom camera pipeline, augmented reality, background Bluetooth or health sensors.
  • It needs widgets, watch apps, car integrations or other system surfaces that frameworks reach late.
  • Smooth, graphics-heavy interaction is the main experience, as in a drawing tool or real-time video.
  • You need a new operating system feature the week it ships.

The cost is real: two codebases mean two sets of skills and bugs, and constant effort to keep features in step. Limit it by sharing the design system, the API contract and one backlog. Modern native screens use SwiftUI on iOS and Jetpack Compose on Android, both declarative, so the two codebases often mirror each other's structure.

Device features and how they differ

List the device features the product needs before choosing a technology, then check how each behaves on both platforms. The same feature is rarely the same on iOS and Android.

  • Notifications. Delivery, channels and user controls differ. Never build a flow that depends on a notification arriving at an exact moment.
  • Background work. Both systems limit what an app can do off screen, and some Android manufacturers add battery restrictions of their own. Design sync that resumes, not constant running.
  • Location. Precise and approximate location, and foreground and background access, are separate choices for the user. Background access needs a clear reason.
  • Biometrics. Face and fingerprint unlock run through system prompts, and your app never sees the biometric data.

Ask only for the permissions a feature needs, at the moment of use, and say why. Both stores ask you to declare how the app uses data, so every permission you add is also a line in your privacy answers.

Store review and release planning

Open a developer account for the organisation on each store early, because verification takes time. Both stores review apps against written policies that change, so read the current ones before you design a feature, not in launch week.

  • Privacy declarations. Apple's privacy details and Google Play's data safety section must match what the app and its third-party SDKs really collect.
  • Accounts. If people can create an account in the app, both stores expect them to be able to delete it. Check the current rules.
  • Payments. Digital goods and subscriptions generally go through each store's billing, and the rules vary by store and region. Settle this before you design a paywall.
  • Listings. Prepare screenshots, descriptions and keywords in English and Arabic.
  • Rollout. Use TestFlight and Google Play's testing tracks for beta builds, then a staged rollout, so a faulty release reaches few people first.

Review times vary and rejections happen, so leave a buffer around any fixed launch date.

Secure storage and authentication

Every project starts with a threat review of the core flows. For a mobile app the questions are what is stored on the phone, what travels over the network and who can sign in. The usual answers:

  • Secure storage. Keep tokens and keys in the iOS Keychain and the Android Keystore, never in plain preferences or files, and store as little as you can on the device.
  • Sign-in. Use the system browser or the platform's authentication session for single sign-on, not a web view inside the app. Offer passkeys or biometric unlock for returning users, and multi-factor authentication where the data justifies it.
  • Sessions. Issue short-lived access tokens, rotate refresh tokens and let the server revoke a lost device.
  • The server decides. Anything inside an app can be read or altered, so check permissions, prices and limits on the server and keep real secrets there.

A security review before launch gives a prioritised fix list, and our cybersecurity service includes testing mobile apps. The guide to secure app development goes deeper.

Updates and compatibility

People do not update at the same time, so several versions of your app will talk to your servers at once. Plan for that from the first release:

  • Minimum OS version. Choose it from your audience's real devices, not the newest phones. Each extra old version costs testing time.
  • New system releases. Each platform ships a major version about once a year. Test against the beta builds when they appear, so the app works the day the release reaches users.
  • Store requirements. Both stores raise their minimum build requirements over time, so keep dependencies current rather than upgrading in a rush.
  • Old app versions. Version your API, keep older versions working for a stated period, and build a way to ask users on an unsupported version to update.
  • Local data and switches. Write migrations so an update never loses data stored on the device, and use feature flags to turn off a faulty feature without waiting for store review.

Testing on devices

Simulators and emulators are fast and useful every day, but they do not reproduce real cameras, Bluetooth, push delivery, biometrics, battery behaviour or the speed of a weak phone. Pick a small device set from your audience: an older, low-memory Android phone, a recent flagship, a small-screen iPhone, and the minimum supported and latest OS version on each platform.

Then script the cases that cause the most failures:

  • Interruptions: an incoming call, switching apps, low battery, a permission revoked in settings.
  • Poor networks: airplane mode mid-task, a slow connection, a drop during a payment.
  • Accessibility settings and Arabic right-to-left, with large text, a screen reader and long mixed-direction strings.

Automate what repeats with unit tests, UI tests (XCUITest on iOS, Espresso on Android) and a pipeline that builds every change.

Monitoring after launch

A release is the start of the work. Before launch, set up:

  • Crash reporting, with the symbol files kept for each build so reports stay readable.
  • Performance signals: start-up time, slow or frozen frames and network failures, watched per release and per device group, alongside each store's own quality reports such as Android vitals.
  • Alerts that reach a person when a new version raises the crash rate, and a rule for when to halt a staged rollout.
  • Privacy by design: keep personal data out of logs and analytics events.

Read reviews and support messages as a signal too, and fold what you learn into the weekly plan.

How we plan a build for both platforms

We settle the native-or-shared question in scoping, with the feature and device list in front of us. A discovery sprint produces a clickable prototype, a technical approach and a threat model of the core flows, so the choice rests on evidence. After that you see working builds on real devices at the weekly demo, and a security review comes before launch. The work belongs to our mobile development service.

Questions we get asked

  • It depends on the features. If the app is mostly screens, forms, lists, maps and payments, one shared codebase usually serves both platforms well. If it depends on deep device features, heavy graphics or new system capabilities, native Swift and Kotlin are often worth the extra cost. We decide by listing the features before choosing a technology.

  • It varies by store, by app and over time, and a rejection restarts the process. We cannot promise a number, so we leave a buffer around any fixed launch date, submit early to catch policy problems, and use TestFlight and Google Play's testing tracks before the public release.

  • Do not store passwords on the device at all. Keep short-lived tokens in the iOS Keychain and the Android Keystore, never in plain preferences or files, and let the server revoke them when a device is lost. Keep real secrets and critical checks on the server, because anything inside an app can be read.

  • Choose from your audience's real devices rather than the newest phones. Each older version you support adds testing time and limits the system features you can use. Set a minimum for each platform, review it every year, and show users on unsupported versions a clear message asking them to update.

Keep exploring

Ready to build something secure?

Tell us about your product. We will reply with a clear plan.

Start a project

We would like to use Microsoft Clarity to see how visitors use the site, so we can improve it. It sets cookies and is off unless you accept. Cookie policy