5 Things to Remember Before Shipping Version 1.0 of your Mobile App
A mobile app is a great way to build a premium user experience, but it comes at a cost. One of those costs is permanence. Unlike a web app which can be updated at any time, mobile apps, once published, are out there forever. Knowing this, here are a few tips I’ve learned over my career and which I encourage you to implement as early as in your initial 1.0 release.
1. Version your API
If your app accesses a server API, its URL will be baked into your app. In order to add or update features, this API will need to change over time. Ideally, these changes should be as backwards-compatible as possible, but at some point you will want to make a breaking change. Not a problem…as long as you version your API. There are many different techniques for doing this, but the most common is to put the version number in the URL path, such as:
Now you can support older app versions concurrently with newer versions. However, there will still come a time when you won’t want to support multiple versions of your API. In that case, you need to…
2. Add a kill switch
Once a user installs your app, there is no guaranteed way for you to update it on their device. While both the Apple and Google Play stores offer auto-update by default, there is no strict timeframe for this to occur, and it can even be disabled by users. This means that, at any given time, multiple versions of your app will be in the wild. Eventually, you will want to deprecate an older version. Perhaps you’ve made a breaking change or fixed a critical bug. In that case, you need a way for the app to know it has been deprecated, and present a friendly upgrade message to the user.
A graceful way to handle this is to have your API server return a special status code, such as 301 (Moved Permanently) or 410 (Gone), for any requests made by deprecated versions of your app. When your app receives this status code, it should present a dialog reminding users to update, while entering read-only mode. Remember, you should still keep the app as usable as possible by allowing read-only access to any cached or local data stored on the device.
How does the server know which request is coming from a deprecated app version? If you use API versioning,you can simply make a particular API endpoint always return the special status code. However, a more granular approach is for your app to identify its platform, OS version, and app version in the User-Agent header of each HTTP request. It is up to you to come up with a format that contains what you need. For example:
User-Agent: MyApp/1.0.0(31) iOS/10.3
| | | | |
app name | build | os
When your server sees a request come in from a deprecated version, it should return the special status code. Even if you’re not using it on the server yet, I highly suggest to bake these host headers in as early as the initial 1.0 release of your app.
3. Log a user out remotely
There will come a time when a user’s account or permissions change, and you will need to log them out of the app remotely. You may even want to go as far as purge the data on the device if it belongs to a terminated employee, for example. In these cases, your API should return a special status code such as 401 (Unauthorized) or 403 (Forbidden) that the app interprets by doing a “soft” logout (sending them to the login screen while retaining the local data on their device) or a “hard” logout (doing the same but deleting all local data). As with anything that destroys data, be careful and test this thoroughly!
Remember, even with a hard logout, there is nothing stopping a crafty determined employee from putting their phone in airplane mode (preventing the status code from being received), and extracting the data stored in their filesystem for nefarious purposes. Don’t store more than the minimum data that your app needs to function.
4. Support impersonating users
As soon as your app ships, you will need to support it. Inevitably, a customer will contact you with an issue with their account. Your support staff will understandably ask you if they can log into the app as a particular user. That should normally be impossible because you never store unhashed user passwords anywhere, right? Right?? In that case, you need to build an impersonation mechanism into your app.
For example, you can create a secure web page where support staff can log in (this is typically your “admin portal”). On that page, support staff are able to look up a registered user and generate a short-lived token…the same token that the user normally receives when they log in (typically a JWT). Now you just need to get that token into the app. You can do that by designing the app to accept a custom URL scheme such as:
When your support staff open that link on a device, the app should bypass the login flow and automatically log them in as that user. As with any impersonation tool, be sure to consider the security implications of this technique. Keep in mind industry-specific compliance regulations such as PCI and HIPAA. Be sure to restrict this functionality to certain staff only, generate short-lived tokens if possible, and don’t copy the token around insecurely. Even if you don’t have the admin portal ready on day one, you should at least build the custom URL handler for accepting tokens in the 1.0 version of your app.
Nowadays there are additional tools that can make your support staff’s lives easier. For example, you can use Appetize.io to run a real instance of your app inside a web browser (!). It has a free tier and is very flexible and can run different builds on different OS versions and devices. You can use their API to send them a build as part of your deployment pipeline. If you really want to be fancy, you can update that impersonation page in your admin portal so that support staff can select the user, device, OS , and app version, and with a click of a button, be taken to the app, automatically logged in.
5. Install crash reporting and analytics tools
As soon as your app launches, your product manager will immediately want to know how it is doing. Relying on API server logs only tells you a tiny piece of the story. A free crash reporting tool like Crashlytics can keep track of when your app crashes, and point you to the exact line of problematic code. A free analytics tool like Google Analytics can collect valuable data on what screens users use, as well as device metadata. An APM (Application Performance Monitoring) tool like NewRelic can tell you what the network latency experience is for your users. If you want to get really fancy, a screen recording tool like AppSee can record heatmaps of your users’ interaction with your app, pointing out UX problems, and providing videos leading up to crashes. Again, the sooner you add these SDK’s to your app, the sooner you can start collecting data.
Remember, when coming from a web-centric world, mobile apps are a different beast. Once you ship your app, the proverbial cat is out of the bag. To minimize future pain and frustration, it’s best to build in these considerations into the intial 1.0 release of your app. Good luck!