There’s some really great apps in the App Store and Google play store!

I talk to folks in business who look at today’s rideshare & online shopping apps and say: Can I get an app like that for my business?

Well, yes, of course! Anything that can be done, can be done — for a price.

I’ve seen custom photo-editing apps where you get pro-quality results right on your phone. What about fitness trackers that just seem to know exactly what you need?

What about rideshare! I heard they use GPS, calendar integration and even artificial intelligence? Oh, that’d be really great for my customers!

“Really great” just costs a bit more. But …how much more?

So there’s some “really great” app features that are the icing on the cake. Nice, but you can live without them.

But some “power app” features might be core to an app that you want built (like say Bluetooth), but are not the usual thing that comes for free with iOS or Android apps, out of the box.

Apps seem really powerful, but is it possible for my business to have a really awesome app? I love fancy animations, music, and something that works with my playlists. Is that going to cost a lot of money?

Basic apps are cheap, but by the time you add a lot of things you probably didn’t realise don’t come for free, the bill quickly adds up.

The answer to all these “Can you…” and “How much…” questions are all “Yes” and “It depends”.

Out-of-the-box apps fetch data from the web, store some local configuration such as passwords or preferences; and then display up-to-date information relevant to you. Beyond that some extra work is required, and extra code must be either written or imported from 3rd party projects (which brings its own problems).

Sometimes its a lot more because very basic apps are cheap, but a lot of things we are used to seeing in apps that are in the Apple App Store or Google Play Store do not just “come for free”. In-App Purchases or fancy cameras although we see them commonly don’t just come standard.

In this article, the sixth and last in my series on how to build an app, I will drill down into the popular add-on features that really great apps can offer. The other articles in the series are all linked from the series introduction post so jump over to that to find pre-reading if you need to.

How to Build an App so it doesn’t Break the Bank

If apps are so expensive, are they really worth it?

When your app is finally built and in the stores the final bill is likely to invoke sticker shock. Apps are expensive. Image credit: undraw.co

These questions get to the heart of how apps are different from websites. And they’re really important questions for anyone considering building an app.

In this article, the sixth and last in my series on how to build an app, I will drill down into the main features that really great apps can offer. The other articles in the series are all linked from the series introduction post so jump over to that to find pre-reading if you need to.

We will discover together how you can get a really amazing app for your business and get good value for money into the bargain.

In the previous posts we discussed how apps work, and what kinds of apps are out there. We learnt about native apps, the apps which you download from the Apple App Store and Google play store; and we learned about webapps, which are basically mobile optimised websites. And we also learnt about hybrid apps which are the halfway between apps, that offer some of the features of native whilst having the flexibility of a web app.

As we dive into this article, it’s gonna be all about that first kind of app, the native app. So let’s get started.

Native App Redux

Native apps have to be written specifically for the platform. We covered this back in the second post of this series about app types.  What this means is, if a developer is writing a native app for Apple’s iOS platforms: the iPad, iPhone or iPod touch, they will use the programming language Swift, or perhaps Objective-C.

Most iOS developers use the Xcode programming environment, and must use a Mac computer to prepare the package which will be uploaded to the App Store.

While for Android, developers must use Java or Kotlin languages, and code in one of the development environments for those languages, and build an android APK package for uploading to the Google play store.

Apple Music app for Android screenshot. App is (c) Apple
Apple Music app for Android screenshot. App is (c) Apple

Look at this store listing for the Apple Music App. This is an Android app, and it runs on Android phones. People who download it use that app to play music from Apples “Apple Music” online service.

What languages would the Apple Music App be written in?

The answer is Kotlin or Java! Even if Apple’s engineers wrote the app they need to deploy to Android so they must use Kotlin/Java to do that. They must also call into Android API’s for things like accessing the phone’s keystore.

Both platforms have their own very different, and very powerful application programming interfaces, or API’s that are used for accessing the full power of the platform.

This type of matching of language, development environment, deployment package, and API’s has been the case throughout my almost 2 decades I’m working in Mobile engineering. It’s not about to change.

And its the kind of coding that is typically used in powerful feature-rich mobile apps on the iPhone, and on the Google Play store as well. Want a powerful app? Native is the way.

Platform differences run Deep

The reason for the differences in API and language across iOS and Android, is that each platform vendor has built what they believe is the best offering, that uniquely matches the value for customers of their device.

Apple makes premium devices that are more expensive, but feature greater privacy, high-end tightly integrated hardware such as cameras, and access to curated content in the Apple ecosystem. Tightly integrated custom hardware and software often means iOS devices outperform dollar-for-dollar equivalent premium Android handsets for many common app tasks.

Amazon shopping on a Google Pixel 3a. (c) Smithsoft
Android is a good place to start when launching free apps that target large audiences of value conscious users.

Android devices can often have more CPU power and configurability at a lower price point, and thus suit enthusiasts and tech-savvy tinkerers. Android also powers a very large fleet of low price commodity phones that are used around the world, including in developing nations and often have much older versions of the android operating system installed. There’s a variety of options for apps too.

Korean manufacturer Samsung makes its own idiosyncratic configuration of Android hardware which works well as a package, and has a loyal base of fans. This is despite historic problems with upgrading Android versions on Samsung phones after a year or two of use.

Android is much more permissive regarding security and generally interoperation between apps on Android is much easier

Android is much more permissive regarding security and generally interoperation between apps and services on Android is much easier. On iOS the opposite is true, and Apple’s continuing focus on security can make background app operation, and many kinds of interoperation or hardware use difficult. A recent topical example is the Covid-19 Tracing App here in Australia which did not work on iOS due to developers not understanding Apple’s security requirements.

Android History

Android has its roots in web technologies, in that the Java Virtual Machine “Dalvik” was used to isolate the application layer from the system of the phone, following after Java Applets and the Java Midlet security model in early 2000’s.

In web-apps written in Java the manifest file, and web-requests are central concepts: in Android the manifest file also controls all entry points to the app; and the Intent replaces the web-request as the object that initiates control being passed to the app.

On iOS all code runs natively on the CPU, and web technologies are only used in applications like mobile Safari, or in hybrid apps that hand over to a web-view.

For security iOS uses a sandbox model where kernel level mechanisms secure apps from even seeing or accessing files from other apps or the OS.

All that technical history is just to say: they are very different. And its not just skin deep — it goes way back.

If you think that those differences might mean extra cost when it comes to building apps that have power features across both platforms you would be 100% right. That can be a big part of the price of power apps.

So: if you don’t like the sticker price, or the complexity; surely (you might ask) there are options?

C++ and Other Binary Formats

Another way to build apps that is worth mentioning when it comes to media, or performance apps is C++.

One interesting wrinkle for both iOS and Android is that an old-school language called C++ (which is where I started my career in 2004) is actually available to be compiled and put into an app a binary format for both platforms.

Its “native” in the sense that the CPU on the phone or tablet directly and natively runs the machine instructions in the binary package that the C++ compiles down to. This is unlike Javascript or C# which has to be interpreted by a half-way adapter software called the “virtual machine” or “run-time”.

Standby for a technical deep-dive; skim it if you want. This is how C++ is usually used:

  • On Android the NDK or Native Development Kit is used to compile C++ to a dynamic shared library that is included along with the Java/Kotlin class files that make up an Android app. That app then loads the shared library via a dlopen call.
  • On iOS the Xcode compiler toolchain can compile C++ alongside Swift and Objective-C into object format that then is compiled into a regular iOS app package. On iOS no dlopen is required.

The above may be technical detail, but what this translates to is C++ is a seperate piece on Android, but is built-in on iOS.

Once that C++ module is pushed into the app it provides powerful back-end processing for very demanding apps, especially ones with needs in:

  • scientific computing
  • game engine graphics
  • video or audio processing
  • numeric computing, and
  • artificial intelligence.

Game engines like Cocos2D-X, and Unreal Engine utilise this unique trait of C/C++ to get high-performance cross-platform graphics on both iOS and Android.

Because some apps are mostly graphical C++ and OpenGL or game engine tech can be used effectively. The code for this simple game is entirely in C++ and can be seen in my Github.

The power of C++ also gets used for integrating with special scientific libraries like OpenCV, TensorFlow or FFMPEG, used for AI or Video, or Computer Vision.

Note that C++ is not native when it comes to accessing platform API’s. This is why its not a great option for generally apps.

Cross-Platform to the Rescue?

While C++ and game engines like Unity are interesting, they aren’t a general solution across the iOS and Android ecosystems.

Because of these very important differences between the platform, and the very different paths which the different platforms have followed during the development from the launch back in 2007 also, API’s and programming in general are very, very different across the two main phone platforms.

So as a result, almost as long as there has been Apple and Android, systems have been developed which try to wall-paper over those differences.

I’m talking here about cross-platform systems which have a promise of write once; deploy everywhere. Here are some of the current crop of cross-platform contenders:

React NativeJavascript
IonicJavascript (webviews)
Current options for publishing to the app store without going native

However in my experience every cross platform development system so far consistently lags well behind the functionality provided by native Apis.

As mentioned above, and on my in depth article about how apps work, native API’s provide access to these power features, like for example notifications or in-app purchases. So cross-platform systems have to do one of the following:

  • work to wrap & support the API’s on iOS and Android, OR
  • rely on community projects to provide that support, OR
  • just leave out support for that feature altogether

Cross-Platform Gotcha’s

Vendors of these systems reinterpret the meaning of “native” in some very imaginative ways, in my view.

For example the Flutter system by Google uses a C++ engine or runtime to render its Dart language components on screen; and its very highly optimised with compiler technology to get “hot-reload”. Because it’s using compiled code on the platform, and displaying graphics using a canvas view Flutter says its “native”: but it’s not using iPhone graphical UI elements on iPhone.

As I write this several respected development houses I know of are building & shipping their apps with Flutter.

React Native is also hugely popular often because many digital agencies and web-developers bill themselves as “app developers” and use their Javascript skills to create React Native apps.

AirBnb built its early versions on React Native before moving off it in favour of native.

Still, React Native apps are often a great way to quickly get a Minimal Viable Product going to prove that the app has appeal.

FlowKey GmbH, a German company building an app to learn piano have made an amazing app complete with Midi integration and in-app video all using React Native. The app is a success, earning an estimated $500k USD pa.

If you go to cross-platform to replace two languages with one, you might find now you have three languages to deal with.

Any cross platform system, sufficiently complex to capture and access native Apis inevitably winds up being more complex than the native API it seeks to replace.

If you have to write plugin code in actual native languages then you are worse off in the language proliferation stakes because now you have Kotlin on Android, Swift on iOS and whatever language your cross-platform solution is written in, say Javascript for React.

That’s three languages – so what did you save?

Cross-Platform End-of-Life

In 2015 I had been working on a new app for some time, on iOS and needed to build on to Android. It looked like I was up for a re-write.

But at that time a new cross-platform player had come along.

Appportable took Obj-C code and built for Android. It’s dead now.

Their name? Apportable. I was impressed by their technology – I found I could get my app up and running on Android even though it was written in Objective-C!

It supported many of the API’s I was using in my app.

As I got closer to shipping however I found it harder and harder to use, and the group became cagey around support requests. I later found that the company was being “restructured” and after many staff left, the remains were acquired by Google. It no longer exists.

But surely that doesn’t happen a lot, right? Someone can’t make a cross-platform system, and then just end-of-life it – can they?

Well Microsoft had a system called Xamarin, which they built a huge following around. You could write cross-platform apps in the popular language C# – and for basic apps that used simple UI’s Xamarin forms gave a fast path to market. Xamarin cloud provided Microsoft supported tooling for building your apps.

But now its gone. Microsoft just announced its end-of-life.

There may be something called Maui replacing it.

C# is a popular portable language among Microsoft developers. Xamarin made it possible to use on iOS and Android. Xamarin is dead now.

This is heartbreaking if you’ve pinned everything on that tech-stack. It’s a huge job to move all that code to something new.

List of dead cross-platform mobile development systems:

Could this happen to say… Flutter? Surely Google wouldn’t end-of-life Flutter, would they? They’ve sunk so much into it!

The Google Graveyard

Here’s a small list of million dollar projects that Google has killed:

  • Google Wave
  • Google+
  • AngularJS
  • Picasa

There’s all these as well. Arguably these projects were made redundant by something better that came along. Or were just not viable in the first place, despite having Google backing.

My point is that the only development environment that you can count on that will be around as long as the device itself; is the one that the vendors of the devices publish for that device.

Kotlin allows you to author for Android natively, is published by Google for development on Android devices. Although Java came before it Kotlin and Java code can sit in the same project, compile to the same executable package and run on the same Android Run Time.

Swift allows you to develop on iOS natively, and is published by Apple for development on Apple devices. Although Objective-C came before Swift, Obj-C and Swift files can be compiled together into the same object files, and run from the same executable.

These systems are made for purpose, and can be relied on to be there next year, when you’re shipping updates to your app.

Native is Best: Nothing you can do, that Can’t be Done 🎶

Because as a platform a phone itself is coded by Apple or Google in native languages and API’s; then if the platform can do it at all – then it can be done with native. Actual native. You have no limits on what you can achieve when you’re using native except the limits of the platform itself.

Native means there’s nothing you can do, that can’t be done (with apologies to the Beatles).

If you’re on a cross-platform product, like one of those in the previous section, you can be limited by what the vendors of that have built support for. in Android or iOS they for. When those are brand new features, it might take some time for the vendors to play catch-up.

You Still Need Native

Developers of cross-platform systems make it possible to build so called “Native Modules” or plugins, that access native platform features.

Say you have an API you want to use and React Native doesn’t support it; then Facebook wants you to write a “native module” to access it. They’ve actually just announced a re-architecture of this system called “Turbo Modules”.

It means that if you want to use that feature yourself, you have to drop-down from Javascript, C# or Dart into Swift or Kotlin (whatever the language-per-platform is) to access those power features. Or write a plugin or seperate module of native code, that is loaded by the cross-platform runtime.

So now your code looks like this:

iOS and AndroidJavascript
You wanted one code-base, but now you have three.

So now you start out with say React Native Javascript code base, but then have to special-case and fracture it for the different platforms and now you have 3 systems of code to handle.

Diagram of iOS and Android native UX. Two phone shaped rectangles, left & right. Each has the OS at the bottom and the app at the top: the app composed of the JS bundle and the react native runtime; with native modules next to it.
With cross-platform often native modules are required to access the iOS platform features. Either a community project is used, or you have to write that code.

You wanted one code-base, but now you have three.

Plugins by 3rd parties – A mixed blessing

React Native has a huge array of 3rd party code on offer from Node, React and the NPM community. Some of this code is just general utilities, and some specifically for React Native: but its a cornucopia of free functionality available ready to be downloaded!

There is a huge collection as well for native development both in iOS and Android; but in my opinion the Node/NPM/React/JS community has a bit more.

Is this all a good thing for React Native? Not necessarily.

In some cases third-parties have written the per-platform code as plugins to the relevant cross-platform eco-system. A search shows 32 plugins (at the time of writing) from 3rd parties for JS/React/Cordova plugins to do in-app purchases.

But now you’ve baked in a reliance on cross-platform OpenSource 3rd party code. That is probably fine for now. But as soon as you ship that first version of your app you already have new features you want to add: and what happens if that 3rd party code doesn’t support those new features?

That community code might have been written for a particular purpose and now they are no longer working on it.

It may not do everything you need, and as it is now unmaintained so it may require your own developers to step in to fork that project and add your requirements to it.

Security Issues

FlowKey appears to use a 3rd party React plugin for video for its iOS and Android apps. Under the hood this plugin drills down to the video API’s on the two platforms, ExoPlayer on Android and AVPlayer on iOS.

As I write this that video plugin has breaking changes in v5.0.

What happens if you need to update to v5.0 because of a security problem?

It’s common for 3rd party code to have required security updates.

Now if developers rely on that player they must modify their code to the new v5.0 API just to get security fixes in those latest versions.

Also 3rd party code might pull in dependencies (so called “transitive dependencies”) which further complicate your job of dealing with security issues.

Importing Limitations

If you work with inexperienced developers who utilise a lot of 3rd party code you’ll need to carefully scrutinise functionality to make sure it does what you asked for. If they say what you want is “impossible” then it might be because the 3rd party plugin does not support what is needed. And remember with Native “there is nothing you can do that can’t be done”.

Notifications – A Native Case Study

Let’s have a look at one of the more powerful features of native platforms: notifications. They come in two kinds: remote and local. Remote notifications are also known as “Push Notifications”.

Notification here means a message that is delivered from a source outside of the app.

Notifications are messages that arrive from a system outside of the app. Push notifications come from a cloud system like APNS or FCM and are routed to your app by the phone’s operating system (Android or iOS).

The message is typically flagged with some kind of user experience design to bring it to the users attention. They are delivered to the app by the operating system (iOS or Android) which routes the notification to the app it is associated with.

And it produces on delivery a range of possible user-configurable advisory events:

  • a badge on the app icon,
  • a message on the lock screen;
  • a banner that appears in front of other apps
  • audible notification sounds

Then inside an app developers will write code to receive that message from the notification and process it inside the app. For example they may display a notification icon

People who buy phones often want to know straightaway when something important has happened, so they will opt in to receive notifications that benefit them. This is a great feature of our mobile devices.

Apps which abuse notifications will often be quickly uninstalled, or at least silenced by the end users in frustration.

For iOS notifications must be authorised by the user to be sent at all, and for this reason an app must include notifications in its capabilities declaration to be allowed in the App Store. Abuse of notifications, or anything Apple deems deceptive might result in rejection from the App Store.

From Android 13 Google has started doing this opt-in for notifications too. Owners of Android phones can now opt-out of notifications at app install time.

How do Notifications Work?

However when implemented correctly notifications are one of the most powerful features of mobile platforms.

Notifications (at least remote ones) on Apple are handled by the APNS system. This is a cloud based messaging system owned and administered by Apple for its phones. A certificate is generated for entities, that is a company or a person, who wants to send a notification via APNS.

Push notifications on iOS. © 2022 Sarah Smith

1) An APNS certificate is installed on a cloud based system which is then used to push messages via the Apple Push Notification Service to devices that are registered. When users agree to notifications the OS will register the app for notifications and receive a token; while in the cloud the device and its token will be added to a list.

2) Those messages are received by the iOS operating system on the phone, raising alerts and lock screen reports before being delivered to their corresponding app.

Apple push notifications can only be delivered to genuine devices. In particular they can’t be delivered to emulators, and not to web-apps, and they don’t work with browsers. This means that progressive web apps (PWA’s) do not receive notifications on iOS. This is an important security feature for the benefit of Apple users.

Notifications for Google’s android mobile operating system are handled by FCM, the Firebase Cloud Messaging system. Using a technology called service workers it is possible for properly configured progressive web-apps to receive notifications on android, but they work basically the same way notifications work in a web browser. Test, test and re-test to make sure that the user experience is what was designed.

Often a cloud based system like Urban Airship takes care of notification delivery to APNS and FCM, but you have the option of building your own web-app for this too.

So that is how notifications work. In terms of API calls this is what you have to do on iOS to set up for notifications:

  • registerForRemoteNotifications()
  • handle the callback & get token in an application handler
  • sendTokenToServer() (not a platform API)
  • requestAuthorization(options: [.alert, .sound, .badge])

In Android instead what you have to do is:

  • Sub-class the FirebaseInstanceIdService class
  • and implement onTokenRefresh()
  • In the XML manifest configure it to handle com.google.firebase.INSTANCE_ID_EVENT from FCM
  • Sub-class the FirebaseMessagingService class
  • and implement onMessageReceived()
  • In the XML manifest configure it to handle com.google.firebase.MESSAGING_EVENT from FCM

Notice how these are completely different. This is just registering.

There is a lot more complexity than this, as on later Android systems you also have to ask for authorisation (which you have to do in iOS, but don’t have to do for Android earlier than v13). So there could be a version check, and an authorisation call.

Then you have to display or action the notification.

Also the two systems handle background processing of notifications differently as well.

Takeaway: the API’s are wildly different. Completely un-alike.

Cross-Platform Notifications

General rule: you cannot get notifications in a web-app.

Exception to that rule – you can (sort of) get notifications on PWA’s on Android phones. But not on iOS.

I’ve seen mixed reports of whether notifications are reliably received by PWA’s or by Ionic/Phonegap/Cordova (web based) apps that are backgrounded on Android. One developer writes about having an app rejected by both Apple and by Google as a result of notifications setup on JS based apps.

But: if you build with a cross-platform system, the allows your app to be authored in some single-code-base and published to the Google Play Store and Apple App Store, you can get notifications in your app. There are some traps though.

Cross platform development systems like Flutter, Cordova and ReactNative can produce native apps that run similarly on both platforms, and can receive notifications.

This is done simply enough by calling into plugins or in the case of Flutter or Xamarin, into their own API’s that then proxy through to the runtime to call the native API under the hood.

Cross-platform systems usually provide support for notifications via plugins or third party community supported projects.

React Native used to have its own support, but this is now provided by community projects.

Why? Perhaps because implementing truly cross-platform support for notifications is hard because the two platforms are very different, and both vendors (Apple and Google) often change how notifications work.

In Flutter there is basic support for notifications handling in iOS and Android built in, especially on the delivery side. Community projects are available for handling them in the app.

Cloud Vendor SDK’s for Notifications

Additionally if you use a cloud notification system, they will likely have SDK’s to integrate that will handle notifications end-to-end. Note that such SDK’s do limit you if you need to manage notifications outside of that cloud provider.

For example let’s say you have a shopping app. You set up Urban Airship to send notifications to your fleet of deployed apps for marketing new items in your catalog. So you can integrate their SDK:

  • If native you can use Urban Airships iOS SDK or Android SDK.
  • If React Native you can use Urban Airships RN SDK.

Later you decide to use a customer loyalty product in the backend. However it requires to send notifications seperate to Urban Airship.

Now because of the tight binding to Urban Airship via its SDK, if you need to send notifications from that other system you may have issues with receiving them in the app.

Features Needing Native

That was a deep dive into notifications. That is only one native feature that requires a different API’s on each platform – and now you know just how different.

The following are all features that are powerful and natural for mobile devices (like notifications), but which require native API’s to access:

  • In-App Purchases
  • Cameras
  • Photos
  • Games
  • Bluetooth
  • Data integration (Calendar, Photos, Address book)

On cross-platform systems these can be supported by the system itself, or via community plugins.

But in general the same types of issues as mentioned in our Notifications case study above apply.


How do I harness the power of apps? Basically, use native!

Basic apps are cheap, but by the time you add a lot of things you probably didn’t realise don’t come for free, the bill quickly adds up.

Native apps redux: Both platforms have their own very different, and very powerful application programming interfaces, or API’s that are used for accessing the full power of the platform.

Platform differences run deep – apple is premium, android is commodity

C++ and some game engines can be used for special purpose apps:

  • scientific computing
  • game engine graphics
  • video or audio processing

Cross-platform – a promise of write once; deploy everywhere

Gotchas – replace two languages with one, you might find now you have three languages to deal with.

Any cross platform system always winds up being more complex than the native API it seeks to replace.

End of life – will the system you choose join xamarin & cordova in the graveyard of x-platform projects dumped by big tech companies?

Native is still best in class – you still need it as x-platform vendors tell you to use plugins or native modules to solve support issues

Or: you rely on community projects and the dependency issues they bring – security, functionality limitations

They don’t work with PWA’s – they can’t be received on emulators for iOS, and they require use permissions

There’s cloud infrastructure to make them work, requiring certificates from both Google and Apple and work in a complex way

Cross-platform systems can do notifications but usually require plugins or 3rd party modules

SDK’s from Notification system providers further complicate & constrain implementations