Some useful insights on Instant apps

At Google IO in 2016 Google announced Instant Apps. The promise of delivering the native app experience from the web made us enthusiastic. Since the announcement it has been quiet for quite some time though. Google needed time to refine the concept. But since may 2017 instant apps are widely available. Everyone can make an instant app! So we decided to share some of our insights through this post.

What is it?

An instant app is a native app that requires no installation from the user. Instead of having a user go to the Google play store and download your app. A user who opens a link that is associated to your app can choose to open the instant app. The instant app gets downloaded too but instead of staying on your phone forever it works like how a browser behaves, it caches your app. You could call it a lightweight version of your actual app. In the near future instant apps can be added to your homescreen. The Google play store currently contains a “try now” button for apps with instant apps.

The instant app reaches out to users who haven’t installed your app but do visit your mobile site. This includes users who visit your mobile site once through shared links. Giving these users the experience of a native app is the value it provides. Instant apps are available for users on Android Lollipop (API 21) and higher. To start using them try opening a few example links on your Android phone. You should get a prompt asking whether you’d like to open an instant app. If you don’t get a prompt, try opening your Google settings and enabling instant apps explicitly. Some examples of instant apps:

NOS and our instant app concept

Before we take a deep dive, we’ll tell you something about our company and the concept we had in mind. NOS is a Dutch public broadcaster where we cover news and sports stories for the dutch audience. Everyday millions of users trust us to inform them on what’s happening in the world through our website, apps and also on social media. We’re really happy with our audience every day. We see different patterns of usage on different platforms. Obviously. What we typically see is that a user visits our website once or twice a week. A user on our app visits us every day on average. This is partly because our mobile apps perform better than the web delivering media-heavy stories. Notifications are a powerful instrument for news and sports updates. We are also aware that our app-icon on a smartphone homescreen is a very powerful thing. Once it’s there, it’s far easier to access the native app than a bookmark in a browser.

On the web we have lots of direct traffic to news and sports articles. With this insight, the idea surfaced at NOS to offer our article as an instant-app. When there’s video or other media involved, the instant app could offer a better experience than the web. At the same time it’s an opportunity for the users to get acquainted with our app. We planned to offer the instant-app users an easy way to install our main app. So, enough with the boring introduction, let’s dive in.

Recommendations before developing

We’d recommend following these steps from the Android developer site. However there are a few things we’d like to add to this:

  1. Your app needs a website and an existing app, an instant app is not a replacement for either.
  2. Reserve time for developing the instant app and stop developing features during this time. This makes refactoring and moving code a lot easier. It took us about 4–5 weeks for a first releasable version.
  3. Plan and test out the app structure, especially dependencies. This codelab has a working example.
  4. Make sure your app doesn’t have any cleartext traffic (http). We ran into a few problems but more on that in the next section.
  5. Update your dependencies beforehand. Doing this after developing your instant app can lead to surprises and complications.
  6. For defining the features, your app probably already handles a few different links to your site. Use these as your starting point.
  7. Test whether you can strip your app to less than 4 mb, Apk inspector in Android studio is your friend!

Our experience while developing

As instant apps are still new and not used often we expected to run into some issues. This section covers our experiences in no particular order.

Structure & plan

After deciding to develop an instant app we sat down and started brainstorming how to divide the modules. The goal here was to have an instant app up and running quickly. The current app mainly has one module. We changed this to a base feature and extracted all unnecessary code into another module. This is similar to what is shown as a basic instant app structure on the developer site. In hindsight it probably would’ve been faster to do this the other way around. By extracting everything you need for the instant app into the base feature. Our modules would look like this:

  • App: The base feature containing instant app code
  • App-apk: The code for the installable app
  • App-instant: A necessary wrapper only containing the instant app build.gradle

It took some time to extract code and resources out of the base feature. At the same time we were also removing unused resources and code. At some places there would be a feature that behaves differently in the instant app than the installable app. For example Google Cast did not seem to be supported, so there was no need for the added dependencies in the instant app. In short the code was extracted into a Helper class. This got implemented in the installable app but not in the instant app. The instant app only contained the interface for it.

During this whole process of extracting code the app wouldn’t always compile. We were working through different compile errors and runtime errors until we got a stable version. These issues are very project dependent. But when moving your resource to another module remember to update the import R package reference. So com.example.app.R would become com.example.app_feature.R for example. Also when running into SecurityExceptions it either is because of cleartext traffic or an Api that is not allowed on an instant app.

Play store publishing

After having a stable working instant app we started uploading builds to the instant app development release channel in the play store. After inviting testers it took a long time before they had access to the instant app. Usually a tester downloads your app or an update of it. In this case we had to test using a link the instant app supports. We found out that Google play services or chrome holds a cache of whether a domain contains an instant app and that it may take up to 24 hours before this cache expires. Clearing Google play services data seemed to help according to one of the testers. This ~24 hour delay also occurs when releasing to the production channel.

However, before we actually got to a successful upload we ran into multiple issues with our app. Make sure your asset link file is available on your domain to verify your app belongs to your domain (See this). When uploading your instant app, Google play does some analysis on the app. It only displays one error at a time and you’ll have to upload again for the next issue. There were a few issues we ran into here.

One of the issues was that we didn’t have a default url set, this is a must. Our initial first version does not have a home screen and only contains the detailed screens for viewing content. The problem with replacing our mobile website with an instant app screen is that our website contained a bit more functionality and content the app didn’t show. Instead of setting our website homepage as a launcher we decided to use a url that redirects to the latest top articles for now.

Another issue when uploading was that the build version of the Instant app has to be lower than the installable. We’d recommend starting at 1 with your first instant app and to not follow the installable app version. The next issue was the size of the app, the development channel has a higher limit than the production/pre-release channel. After having our app in the development channel, we only found out later that our app size was over the allowed limit of 4mb. One of the initial instant app partners Realtor avoids the development channel for their quality check. Lastly we had to change the way we set up intent filters.

Oreo vs the rest

After having our instant app available to testers, there was a difference in speed when opening instant apps. Oreo opens an instant app a lot faster than previous versions. The reason behind this is because Oreo is the only Android version which supports instant apps natively. The other versions rely on Google play services to open instant apps. While Oreo opens an instant app instantly, it took about a second on other android versions. Here is a test between a Nexus 6p running Oreo and Nougat:

Left is Android Nougat and on the right Android Oreo, both are run on the Nexus 6P

Features

Apart from moving code and refactoring there were a few behavioural changes needed for the instant app. Adding an install banner to an article, getting Crashlytics to work, playing audio fragments and our analytics. Again in no particular order, starting with Crashlytics.

Getting Crashlytics to work in an instant app is little work. However during releasing we had to manually add a fabric key to our resources due to a bug. Furthermore Crashlytics supports instant apps but it doesn’t differentiate a regular app from an instant app. This can be fixed by manually adding a value to Crashlytics, to indicate it’s an instant app.

Rough translation: Always want to be up to date? With the NOS-app you’ll know what is happening.

After having a user open our app, we’d like to give the user an option to download the full app. There are some guidelines available for this. For us, we didn’t want to falsely show our users features or functionalities which are actually inaccessible within the instant app, and then show a download button. But since instant apps so far aren’t widely used or known, we chose to explain it a little and then show the user the download option, after hopefully having proven the value of our app.

To display the different elements in our articles we have quite a few types. They all still worked for our instant app except one. Audio fragments weren’t playing! This ended up being 2 separate issues; the Android media player was not working and the notifications did not show in the instant app. We replaced the MediaPlayer with ExoPlayer, since we already used this for playing videos. For the notification issue, we displayed a notification with media controls in our regular app. Instant apps doesn’t allow notifications so instead of having media play in the background we had to pause the audio after the user leaves the screen.

Lastly analytics, we need to have data on the instant app. The instant app doesn’t have a play store to leave feedback and we needed to know the usage of the app. At first this seemed like an easy task, adding a few events only for the instant app. However the library we were using had not been updated for a while. Also the current version of it contained a bug where ssl was not enabled. After updating to the latest version this bug was fixed, but the app was twice the size! Too big to be uploaded to production. After inspecting, the analytics library created .so files for different cpu architectures (More about native libraries here). Normally you could create multiple APK’s targeting different cpu architectures. Instant apps also have something similar called configuration APK’s. Configuration APK’s did create multiple APK’s but this couldn’t be uploaded to the play store. After testing a little we assumed it was because of the single apk instant app we were using. The extra APK’s generated didn’t handle any urls, this was all in the base feature apk so the play store refused the app. In the end we decided to exclude most of the .so files. The impact was not supporting about 14 devices out of 15,000+ that don’t support ARM. Thanks to the device catalogue in the play store console for providing this information.

Dependency injection with Dagger

The last topic we’d like to cover is one we’re not too happy with. For dependency injection we use Dagger. It worked well with our single module app, however splitting this in multiple modules brought up some questions for us. We couldn’t figure out how to use a single application in our base feature, since it needed to inject objects that it doesn’t know about in the other modules. Our solution ended up having a separate Component and Application for the instant app and installable app. This has 2 drawbacks, it has some duplicate/boilerplate code since the applications and components are very similar. Secondly it prevents us from injecting objects introduced in a new feature module when we start adding this. This setup is likely to improve in the future. We’d also love any feedback or suggestions on this topic.

That’s it!

Lets wrap this up. After developing our instant app we learned a few important things. It takes some time and planning to develop. The instant app has a big impact on code structurally as well as implementation wise. You might have to adjust your app behaviour for the instant app too. Getting your app smaller than 4 mb might be tricky. Also it’s still very new so you might run into issues. Despite these points developing an instant app is definitely achievable.

We hope you like our first developer story. Please let us know what you think! There are more developer stories coming.

Update:
- Reddit user/u/Dazza5000 pointed out theres a bug with databinding where it only works for the base feature module. Yigit from the Android team replied.