How do We Make Android Apps as Good as iOS Apps?

Funshine Weather app screenshot, showcasing some of the design considerations described below, like high contrast images, simple designs, familiar icons, and buttons within reach at the bottom of the screen.iOS apps are just better than their Android counterparts. I thought about showing a bunch of screenshots here of App Store listings vs Google Play listings for the same app, showing how the iOS apps are always rated higher, but I don’t want to call anyone out. Just take a peek at your company’s apps, maybe look at a few others, and get back to this afterwards.

Rough, right? Apps that may be 4.5 or higher on the App Store hover around the 3.5 mark on Android, especially at smaller companies and startups. Why does this happen? To be fair, part of it does come down to rating algorithms and general attitude. iOS users are more likely to pay for apps, more likely to engage with developers, and more likely to give them the benefit of the doubt, as a result. There’s a certain “sunk cost fallacy” at play there. You pay more, so you expect more, and when things go wrong, instead of being mad, you justify your purchase by assuming the issue is a fluke.

However, multiple reviewers and even a few studies have come to the conclusion that users prefer iOS versions of apps to their Android counterparts. In my personal experience, this comes down to navigation, UI consistency, “smoothness,” and a perception of quality that comes from those items. Apps across iOS all act and feel very similar, and that’s not true on Android. On top of that, devices are very different, with aspect ratio differences, feature differences, and OS differences between Android devices that just isn’t a problem on iOS. So what can an Android developer or product manager do to make sure their app is perceived as nice as iOS apps? Step one? Forget iOS.

Forget iOS

First, a harsh truth: stop thinking about iOS, they’re not thinking of you at all. iOS users don’t think about Android very much. They know it’s a platform, they just don’t think about what may be different between the platforms. Instead of trying to make the an iOS design on Android, think about how a particular feature should look when natively designed on Android.

It’s okay if the iOS and Android apps don’t look alike. A vast majority of users will never use both versions of your app. They’ll only know one experience. That experience should be the one that most matches their expectations. You don’t want to give an Android user an iOS experience because they won’t instantly know how your app should operate. You want the user experience to be intuitive. For that, use their existing expectations for what an app should look like.

In short: make an Android app, not an Android app based on an iOS app.

Tech Debt Matters!

If you work in tech and not as an engineer, you’ve likely heard your engineers complaining about tech debt at some point. Tech debt happens to all projects, even our smaller personal projects. What is tech debt? It’s when the code in a project isn’t optimized. It could be using outdated libraries, causing security problems, or simply making development more difficult than it should be. Think of your home. Now, imagine to get around you always have to play a game of “The Floor is Lava.” It could be difficult to get from your office to the living room and back to the bathroom! Maybe you could put up some rickety bridges as a quick fix, but they’ll eventually break, and you’ll be in the lava then. Instead, you should drain the lava.

That’s working on tech debt.

Now, some engineers won’t be able to stand any tech debt. We’re not always great at looking at the big picture. Product deadlines, client commitments, dependencies elsewhere in the company, all can get in the way of taking the extra time to do tech debt and often should. However, some tech debt needs to be prioritized higher. Security risks, stability issues, or outdated libraries can prevent product launches or hurt your customers. A janky interface from an old library and hacky workarounds will cause your Google Play Store rating to plummet. Plus, you have to consider how difficult the code is to maintain! I’ve worked places where we had a rule: “only hire senior engineers.” Why? Because we knew more junior engineers would struggle to make sense of the code, let alone refactor in place. This cost the company money and made growing the team more difficult.

Prioritize tech debt the same way you would any other product work, and ensure you don’t let important projects fall behind.

Test!

Engineers likely have heard about “testable code” before. Often, code will start out in a nice testable state, but tech debt and “quick fixes” will pile up. Engineers will have to add features that weren’t supposed to be there, and the architecture may fall apart. Then, it’s time for a refactor.

However, you can save yourself future trouble by making all code testable from the start. This can include ensuring that new features have unit tests before they’re merged. How can you ensure your code is testable? Start with a strong architecture, like MVVM, and stateful data, and follow-through with strong functional programming paradigms, like avoiding side effects.

If you’re working with a technology like Jetpack Compose, for example, ensure you pass only immutable state objects to your screens to prevent recomposition and make the code feel smoother. This has a secondary benefit: your view is now “dumb.” It doesn’t make decisions and always responds only to state changes. States are very easy to test. With simple functions that lack side effects, you can easily test input and expected output. You can test your repositories, data storage, mock API responses, and test all the way up to your view models without ever needing instrumentation tests. Data-based unit tests are faster and, with a good architecture, can tell you if your app will work quickly.

On top of testable code, you have to remember the look and feel of  your app is also incredibly important. You can ensure that your app looks as it should using screenshot testing. This creates a baseline of screenshots of screens, then compares them to the versions you’ve built. With this, you can make sure that the only changes that make it to the UI are the ones you’ve intended.

Finally, wrap everything up with some end-to-end automation. These tests, often written in Appium, UI Automator, or Espresso, depending on your platform and needs, act like a user. They’ll “tap” and “type” into fields, automating actions so you can assert items on the screen after mocked user input. These can be extremely helpful. A test infrastructure made to split out tests, behavior, and setup, for example, can share cross-platform tests, and even be made to do enough testing to launch an app. I’ve already worked on teams where we had such a robust test infrastructure, from unit tests, through Espresso testing, and up to Appium, that we even did a few smaller releases without any human testing. That saves you a lot of time and money.

Tests ensure your standard of quality doesn’t drop. It’s as important as any other code you write.

Remember Accessibility!

Everyone is a little different. We talk about disability like people are either enabled or disabled, but it’s not that simple. Let’s say I started defining disability on whether or not  a person could ride a skateboard. Are you disabled? How about another one. Let’s say someone hears really well. This can make it hard to hear voices over background noises and music, so they watch shows with subtitles. Older people often like to use larger font sizes on their phones. Someone with motor control issues needs larger touch areas or switch control. If they have what they need to use a feature, then they’re not disabled. Your app can disable users, users aren’t disabled by their abilities, but by the lack of consideration for people with different abilities.

Everyone excels in some things and struggles with other things. A good user interface is an interface that is adaptable to the users’ needs. Accessibility can never be an afterthought, it should be a core part of the design process.

For accessibility, there’s a long list of ways to improve your interfaces. Hesitate to use custom elements and, if you do make them, ensure you have made their readouts clear and concise. Ensure TalkBack recognizes that your buttons are buttons and switches are switches by using Roles in JetPack compose. If an item is a heading, label it as a heading. If you have text that could go past the bottom of the screen, make the view scrollable so a user can pull text into view. Watch your contrast and learn how to test it. Use your app with TalkBack and other features to understand just what a person may need from it.

If you make your app so everyone can use it, everyone will like using it.

Design for All Screens

One benefit iOS has over us in Android land is the screen sizes. They always know the screen ratio and size of the device. We have to develop apps that will work on Sony’s extra long screens, or the square outer screen of a Motorola Razr+. We need to consider Samsung’s Fold and Flip, and Asus’ smaller Zenfone 10 as well as their giant ROG phones. How do you design something that looks good on everything?

S p a c e .

Focus on spacial relationships between items. Use JetPack Compose’s rows and columns more than boxes so you can make views that are simplistic, easy to navigate, and flexible, in spacing, but rigid in placement. Hard values for spaces should only be between objects, but you’re better off centering content and using dynamic sizes. You wouldn’t want someone with a tablet seeing your app scrunched up in the center of the screen. In fact, you may want to work on tablet-specific versions of your app if you could see it being something many users would want on a tablet as well as their phone.

There’s a lot of fragmentation left in this space, which can make designing for all screens difficult. But focus on accessibility features, like scrolling large text views, to accommodate smaller screens and older models, and focus on the spacing between items. You’re not defining your UI for any one display in particular, but you are designing it for all devices.

The only thing you know is consistent is what you want to put on the display, so focus on the relationships between those elements.

Remember the Device

My daily phone is still an iPhone 13 mini. Yes, I’m an iPhone user and an Android engineer, I use both a lot. It’s one of the only flagship phones to come in at a reasonable handheld size. Nearly every other device on the market needs two hands to comfortably operate, likely a case, and some kind of grip, whether it’s a ring, PopSocket, ribbon loop, or some other kind of lump on the back for grip. In short: devices are huge.

So, remembering that devices are large, and that people operate their devices with thumbs that are likely not 7 inches long, you’re going to want to ensure features are within a user’s grasp. If a user may have to press a button or menu item often, consider putting it at the bottom of the screen instead of the top. This can facilitate more comfortable one or even two handed use.

You also want to limit typing where you can. Inputting text on any device is more difficult than it is with a full-sized physical keyboard, but with the variety of keyboards on Android, you really can’t assume they’ll have good autocorrect, or a keyboard that can dynamically figure out what the user wants to type, rather than what they actually typed. So, when you can, limit typing required to use your interface. Make use of large touch targets, autocomplete (remember to debounce your searches!), drop-down menus, and other selection tools to limit typing.

Basically, remember that your users could be working with large devices, typing with only two fingers, and using their device one handed while on the go at any time.

Product Launches Matter

This is the one exception to the “forget iOS” rule. When it comes to releases, don’t make Android users wait longer than iOS users. There’s often some discrepancy between web and mobile for a variety of reasons, including web and full stack teams often having far more engineers than mobile teams. However, don’t let iOS always be weeks ahead of Android. Take time to polish iOS releases if they’re done far in advance. Android users will be disappointed from the start if you delay their release. Every time you disappoint them, starting from a delay of a new feature to issues with the app, you lose a chance to keep them a loyal and happy customer.

Imagine if, in class as a child, your teacher always let their favorite students leave for the day early. It wasn’t about those students’ performance or anything else, the teacher just liked those students more. You’d probably grow resentful of that teacher quickly, right?  What do you think you’re doing to your customers when you subject Android users to the same second-class treatment?

Time your launches so platforms, at least iOS and Android, can launch together. Treat all of your users like your most important users, and make releases exciting for everyone.

 

I’m not going to pretend this is everything you have to do to make sure your Android apps have the same quality and excitement as your iOS apps. However, by following these guidelines, you won’t just make better apps, you’ll have happier users. Happier users keep coming back. Build the brand loyalty you want to see by committing to all of your customers.

As of this writing, I’m currently looking for my next role, so, if this guide helped you and you’re looking for a talented and thoughtful engineer who’s not afraid of writing guides and documentation, look no further than my inbox! You can reach me at… well, me@daniellegolinsky.com. Thanks for stopping by!