Android Programming Sucks.

Maybe most people don’t write apps for both iOS and Android. Maybe those that do are biased by their feelings about Apple and Google. I’ve been doing both kinds of programming for almost 15 years, often writing the same app side-by-side on both platforms. And I can tell you without equivocation, Android programming sucks.

Compared to iOS apps, Android apps take longer to build. They look worse. They don’t work as well as iOS apps. They’re harder to read and harder to maintain. The APIs and services we need to build apps become obsolete and unsupported at a much faster rate, requiring a lot more time consuming rewrites. It’s just terrible all around.

Every Android project has a list of weird dependencies. Every Android function has an old version that you can still use if you install a “compatibility” package, a current version that is preferred (for now), and a shiny, new version that is useless because it only works for the 5% of users who have the latest Android release. Sure, iOS has some of these same problems, but far fewer. Most of my iOS apps have few if any external dependencies. I’ve opened iOS projects that haven’t been touched in 5 years and gotten them to run almost immediately. Try that with an Android app!

Let’s look at a specific case. I had a task to build a screen this week. I had to build it for both iOS and Android. The requirements were simple: Ask the user to walk with their phone for 90 seconds. Measure how far they walked. Every phone these days has ways to measure steps and walking distance, so how hard could it be?

In iOS, we have the CMPedometer class, part of the CoreMotion framework. You have to ask the user for permission to use it, which is pretty normal these days and not difficult to do. Once you have the permission, it’s easy to use and works really well. iOS is always measuring steps and walking distance in the background. CMPedometer is just an interface you use to get at the data. One of the nice things about it is that you can ask for data over a particular time period whether or not your app was running during that time. So if my user closes my app during their 90 second walk and opens it again later, I can easily get the data I need as long as I remember the starting time. I don’t need to have my app run in the background.

When I looked into the Android solution I found two different solutions. One is based on the SensorManager class, and the other uses the Fitness API. After reading through the docs I decided to use Fitness because SensorManager really only gives you step counts and not distance.

Fitness requires the ACTIVITY_RECOGNITION permission, which I expected. After gathering that permission, I got an instance of HistoryClient, which is similar to CMPedometer in that it lets you request historical data for past time periods. But there was a problem. HistoryClient immediately came up as a deprecated class. The whole class is deprecated, not just one function. In fact, the whole Fitness API is deprecated. I wish I’d know that before I did all this work.

I looked briefly into the supposed replacement, Health Connect. Within a few minutes I saw the documentation talking about having to install a different app from Google Play in order for it to work, which really put me off. My screen is a small part of a larger application. I don’t want to make the user install another app. I decided to stick with the deprecated stuff for now, figuring it would probably be years before it stopped working. (I was wrong about this, but didn’t notice until later).

And so I finished writing my code. I set up the correct functions, I started a timer. I stood up and walked around my office, and I got some callbacks. Good! Except, there’s no data being returned. Just an empty array. Did I do something wrong?

Cue several hours of hair-pulling research, reading documentation and Stack Overflow posts, trying anything I could think of. Eventually the problem became clear. Asking for permissions wasn’t enough. I needed access to the user’s Google account, which meant going through an authorization workflow. I was annoyed, but I went ahead and implemented it. And I ran it, and of course it didn’t work. The mysterious error message said “Developer error”.

More digging, more hours. You can’t just ask a user for their account, it turns out. You have to register your app in Google Cloud. You have to turn on the Fitness API. You have to generate an “OAuth 2.0 Client ID” and figure out where to put it. And you have to know, somehow, that the kind of OAuth key you need is the “Web” key, rather than the Android key, even though you’re using it in an Android app. Who comes up with this stuff?

Now, my app is new. I haven’t even generated signing keys or put it on Google Play yet. So, yeah, I went ahead and did all of this. I made the signing keys, I set up the Google Cloud application, I got the correct OAuth key. I ran my app and, eureka, now it pops up a new multi-screen dialog box asking me if I agree to give my app permission to my fitness data. Keep in mind that the app has already requested a permission, so to the end user, it’s going to be confusing. But it’s 5:30 and I’m frustrated and I just want to see this thing work. Now I have the account, so I’m home free. I plug it in and fire up the app and start pacing around the room again. And, you guessed it — still no data. Nothing.

What am I doing wrong? The documentation has no answers. Stack Overflow can’t help. Even ChatGPT, as useful as it is, does nothing other than produce versions of the same code I already have.

I think about it for a while and I have an idea. Maybe Android isn’t collecting data by default and I have to somehow enable it. I go to Google Play and I install the Fit app. I run it, and I configure it for pedometer functions. It works. Will doing this somehow make my app work, too? I’m not hopeful.

But it does. And there you have it. In order to do the same thing I could do in my iOS app by asking for one permission, I had to set up my app in Google Play and Google Cloud. I had to make OAuth keys and turn on APIs. I had to ask my user to log in with their Google account and put them through three screens worth of asking for permissions. I had to install and configure a completely separate app.

After all of this, I went back and took a second look at Health Connect. I rejected it originally because of the “install other app” requirement, but I had to do that anyway. It was then that I noticed the Fitness API will be discontinued at the end of 2024, just 9 months away. That’s too soon. Tomorrow, I’m going to have to tear down everything I just did and start over with Health Connect.

Android programming sucks.