So I owe you a story on notifications on Android and Corona which is essentially a story on why cross-platform development is incredibly difficult.
Now if we were just a pure iOS platform, we’d be pumping out features very quickly. However, we also support Android. And actually, if we count our desktop app, Corona Simulator, we also support Mac and Windows.
The ‘I’ in API
Of all four OSs, Android really slows down our development. Internally, we have a rule of thumb that features on Android take at least 5-10 times longer. There are two main reasons:
First, there are multiple (forked) flavors of Android. In addition, to standard Android (Google Play), there’s the Kindle and NOOK, each with their own app store. Because of that, we’ve seen behavioral differences for the same “version” of Android across devices, including differences we traced down to the OpenGL device driver. There’s also things like services — maps, in-app purchase, notifications, etc — that are completely different. When it comes to these services, the different flavors might as well be completely different OSs.
Second, the Android APIs tend to be less mature. Sometimes this is because the APIs are buggy, but what I really mean is the design is less mature. I tend to think the ‘I’ in API stands for interaction instead of interface because the developer has to interact with these things. The iOS APIs were a refinement of the original MacOS APIs which came from NextStep, so those APIs have been refined for over a decade — and it shows! There’s a consistency to the naming and semantics of the APIs.
In contrast, Android is a relatively young API, and the moral of the story is that you just can’t rush out good APIs. We’ve seen a lot of Android APIs that just feel awkward or that capture the 85% case, but that last 15% just wasn’t there.
For example, when we implemented multitouch on Android, we had to jump through a lot of hoops so that we could identify individual touches uniquely. When a finger touched the screen, you wanted the events for that finger to share the same id as the finger initially touched the screen, moved around, and lifted off the screen. This was critically important when you wanted to distinguish events resulting from multiple fingers moving around the screen. This was concept was built into iOS, but in Android’s own ‘MotionEvent’, the ids that were available were not globally unique. Instead, we built our own.
Android notification infrastructure (or lack thereof)
This theme of building our own infrastructure has been a common theme when working on Android. It’s exactly what we had to do when our team built notifications on Android. We built a bunch of scaffolding to make sure that notifications behaved similarly on Android as they did on iOS.
For example, in the Corona API, we offer the capability to schedule a notification. We embraced the iOS notion that notifications should be something you could schedule. It’s a simple one-line call. Well, on Android, it wasn’t nearly as easy. There is simply no way to schedule notifications, so we had to write our own.
Now this doesn’t sound so bad at first. The hard part comes when you realize that Android requires apps to manage their own notifications. That means the app has to manage a bunch of things to make notifications work, especially when the app is backgrounded, the app is forced to exit, or the phone is rebooted. None of these come out of the box.
When your app is backgrounded (i.e. you hit the back button), you still get scheduled notifications to appear. One limitation, however, is that if you force quit the app, notifications that you’ve scheduled will not appear. This is a limitation of Android, and is a great example of missing functionality that the OS should provide.
The other thing that happens if you force quit the app or you reboot the phone is that the notifications that appear in the status bar disappear. That’s (again) because the notifications are tied to the app, and do not reside globally with the OS. What we did was make sure these notifications persist, so if you relaunch the app, those notifications reappear in the status bar. This is exactly the behavior of the “Mail” app, except we had to implement it — Android doesn’t give this to you for free.
That means when a notification is scheduled, those notifications only appear while the app is in the foreground or backgrounded (i.e. hit the back button). But if you force quit the app or reboot the phone, you don’t get the notifications.
Now the notifications on the status bar are interesting, because the application has to manage its own notifications that appear on the status bar. Because we persist the notifications just like the Mail app does, we have to make sure that when the user taps, clears or removes a notification on the status bar, the persistence data is sync’d properly.
On top of that, we added something unique to Android — adding your own custom icons to replace Corona’s default notification icon — and something familiar to those of you who have used notifications on iOS — adding custom notification sounds.
It was all quite a tricky dance, but worth it. We have a pretty solid notification system that’s supported on standard Android, Kindle, and NOOK.
It’s what we’re building upon as we work on remote push notifications on Android. Just keep in mind that Google Play’s service (Google Cloud Messaging) is only available on standard Android devices, not the other flavors — hmm, that gives me some ideas! :-)