In this three-part series we’ve been exploring Android instant apps, a new feature that provides an entirely new way of reaching users who don’t currently have your app installed on their device. It works by making your app discoverable and accessible from any location that supports URLs, including emails, Google search results, posts on social media platforms, YouTube comments, and forums.
In the first post, we looked at what instant apps are, how they work, and the major benefits they have to offer both Android developers and Android app users. We even got some hands-on experience with instant apps, by using Android Studio’s project creation wizard to quickly and easily generate a project that was pre-configured to support Android instant apps.
In the second post, I used the downloadable MyLocation sample app to demonstrate how you’d update an existing Android project to support the instant apps feature. If you’ve been following along since the beginning, then by this point you’ll have successfully reconfigured the MyLocation project to include a single feature module that can run on any Android Virtual Device (AVD) without you having to install the full MyLocation app.
However, MyLocation currently only consists of a single base feature module, and when it comes to real-life Android projects, you’ll often want to offer multiple features in instant app form. In this final instalment, I’m going to show you how to add multiple feature modules to your Android projects by walking you through the process of adding a second feature module to MyLocation and then mapping this module to a different URL.
Finally, to make sure you’re getting the most out of instant apps, we’ll be rounding off this series by taking a look at some instant app best practices.
Creating a Multi-Feature Instant App
If you’ve completed the second instalment, then your version of the MyLocation project should currently be divided into the following modules:
- mylocation-app. The project’s installable app module, also known as the APK module.
-
mylocation-base. The base feature module, which contains all the common code and resources that are used across all the project’s modules. This module contains a
MapsActivity
that can run independently of the installable app, and will launch on the user’s device whenever they try to access the www.example.com/maps URL. - mylocation-instantapp. The instant app module, which is responsible for transforming each of your project’s feature modules into an Instant App APK.
If this isn’t how your version of MyLocation currently looks, then you can download this version from GitHub.
Before we start the process of adding a second feature module to MyLocation, there are a few things you need to be aware of.
Firstly, at the time of writing, it was only possible to develop instant apps using the Android Studio 3.0 Preview and Canary builds. Whenever you work with early access builds, you should be prepared to encounter bugs, missing functionality, and other generally strange behaviour that will (hopefully!) be addressed way before the stable release. However, working with multiple instant app feature modules seems to be particularly temperamental in the Android Studio 3.0 Canary builds.
To reduce your risk of encountering any issues, you should double-check that you have the very latest Canary build installed before trying to add a second feature module to the MyLocation project. However, if your project does suddenly start throwing errors or refusing to compile, then towards the end of this article you’ll find a Troubleshooting section that contains workarounds and possible fixes for all the issues you’re likely to encounter when adding extra feature modules to your project.
Also note that in this tutorial we’re going to be creating an additional feature module, mapping this module to a unique URL, and then testing the module on an Android Virtual Device (AVD). This is already a lot of ground to cover, so to keep this post from getting too long, we’re going to create a module that simply displays a user interface and doesn’t contain any real functionality. However, there’s no reason why you couldn’t expand on this module with your own code and resources, if you wanted a more authentic instant apps experience.
Create Your Feature Module
The first step to turning MyLocation into a multi-feature instant app is to create our feature module:
- Open the MyLocation project in Android Studio.
- Select New > New Module… from the Android Studio toolbar.
- Select Feature Module, and click Next.
- In the Module name field, enter mylocation-directions.
- Check that the minimumSDK is the same value you’ve used elsewhere in your project, and then click Next.
We may not be implementing any real functionality in our mylocation-directions module, but we still need visual confirmation that this module has loaded correctly, so select the template of your choice (I’m opting for Basic Activity) and then click Next. I’m going to map this feature module to www.example.com/directions, so start by entering example.com in the Instant App URL Host field. Open the Instant App URL Route Type dropdown and select either Path, pathPrefix, or pathPattern. Since I want this module to respond to www.example.com/directions only, I’m going to select Path.
In the Instant App URL Route, enter /directions. This gives us our complete URL: example.com/directions. Change the Activity Name to DirectionsActivity
. Make sure the Layout Name is set to activity_directions, and then click Finish.
Declaring Your Dependencies
As you may have already noticed, a project that supports the instant apps feature is inevitably going to consist of multiple modules. If these modules are going to work together to create multiple different Instant App APKs, plus your “regular” installable APK, then they need to be aware of one another, which means you need to add the necessary dependencies to each module’s build.gradle
file.
When you create a feature module via the New > New module… menu, Android Studio actually generates a few of these dependencies for you, but it doesn’t generate them all. And, to further complicate matters, you need to use different expressions, depending on the type of module(s) you’re working with.
To give you an overview, every time you create a feature module, you need to let your project know that:
- This feature module depends on your project’s base feature module, using the
implementation project
expression. - Your project’s base feature module depends on this feature module, using the
feature project
expression. - Your project’s instant app module depends on this feature module, using the
implementation project
expression.
In this section, we’re going to look at each of these dependencies, so let’s start by running through the dependencies that Android Studio helpfully auto-generates for you.
implementation project(':mylocation-base')
Your project’s base feature module contains all the common code and resources that are used in your project, so any additional feature modules you create will all depend on this single base feature module.
If you open your feature module’s (mylocation-directions
) build.gradle
file, then you’ll see that Android Studio has already added the base feature module (mylocation-base
) as a dependency:
dependencies { ... ... ... implementation project(':mylocation-base') }
No matter how many additional feature modules you create, all of their build.gradle
files will contain this same declaration: implementation project(':mylocation-base')
.
feature project(":mylocation-directions")
Your base feature module also needs to be aware of all your additional feature modules.
If you open your mylocation-base
module’s build.gradle
file, then you’ll see that once again Android Studio has done the work for you, and declared mylocation-directions
as a dependency:
dependencies { ... ... ... feature project(":mylocation-directions")
Any additional feature modules you create will also be added to this section automatically, for example:
dependencies { ... ... ... feature project(":mylocation-directions") feature project(":mylocation-share") feature project(":mylocation-search")
What Android Studio Doesn’t Add….
There are a few dependencies that Android Studio currently doesn’t auto-generate, so you’ll need to add them manually.
implementation project(':mylocation-directions')
Instant apps are stand-alone components that can function independently of the installable app. In the context of our MyLocation app, this means that mylocation-directions
can function without mylocation-app
. However, the opposite isn’t true: mylocation-app
cannot function without mylocation-directions
.
The installable APK must contain all of your project’s modules, including all your instant app feature modules. Therefore, we need to give the APK module (mylocation-app
) a heads-up about our new feature module (mylocation-directions
).
Open the mylocation-app
build.gradle file, and point it to the mylocation-directions
module:
dependencies { implementation project(':mylocation-base') //Add the following line// implementation project(':mylocation-directions') }
You’ll need to repeat this step for every feature module you create, so if you continued to add feature modules then the mylocation-app
build.gradle
file might wind up looking something like this:
dependencies { implementation project(':mylocation-base') implementation project(':mylocation-directions') implementation project(":mylocation-share") implementation project(":mylocation-search") }
The instant app module is responsible for transforming each of your project’s feature modules into an Instant App APK, so it needs to know about every feature module you create.
Open your mylocation-instantapp
module’s build.gradle
file, and declare mylocation-base
as a dependency using the implementation project
expression:
dependencies { implementation project(':mylocation-base') implementation project(':mylocation-directions') }
And One Additional Dependency
While we’re on the subject of project dependencies, there’s one important dependency we still need to add.
A project that supports instant apps only needs to declare its applicationId
attribute once, in the APK (app) module. However, to make sure this single applicationId
attribute is properly propagated across all your feature modules, you need to add the APK module as a dependency of the base feature module.
Open your mylocation-base
module’s build.gradle
file and add mylocation-app
as a dependency, using the application project
expression:
dependencies { ... ... ... //Add the following line// application project(":mylocation-app")
Unlike all the other dependencies we’ve discussed, you only need to declare a dependency on the APK module once per project, and not every time you create a feature module.
Delete Unwanted Files and Resources
Although this step isn’t mandatory, currently our feature module does contain some unnecessary files and directories, so let’s follow best practices and streamline our mylocation-directions
module:
- Switch to Android Studio’s Project view.
- Open the
mylocation-directions
module. - Delete the
src/androidTest
directory. - Delete the
src/test
directory.
Finish Mapping Your URL
When we created this feature module, we entered some information about the URL we ultimately want to map this module to. However, currently Android Studio’s module creation wizard cannot create a complete URL mapping, so you’ll need to open the App Links Assistant and finish this process manually:
- Select Tools > App Links Assistant from the Android Studio toolbar.
- Click the Open URL Mapping Editor button.
- In the table that appears, select the DirectionsActivity row, and then click the little pencil icon.
- Select the http radio button.
- Make sure Path is selected in the dropdown menu, and then enter /directions in the accompanying text field.
- Make sure DirectionsActivity is selected in the Activity dropdown, and then click OK.
- Back in the App Links Assistant panel, click the Select Activity button.
- When prompted, select DirectionsActivity and then click Insert Code.
You now have two feature modules that are mapped to different URLs.
Test Your mylocation-directions
Module
Currently, our run configuration is set to simulate the user tapping the www.example.com/maps link, which will launch MapsActivity
, and by extension our mylocation-base
module. However, if we’re going to test our additional feature module then we’ll need to simulate the user tapping www.example.com/directions, which will launch our DirectionsActivity
. This requires us to update our runtime configuration:
- Launch the AVD you’ve been using to test your mylocation project, and make sure you’re logged in to a Google account. If you aren’t logged in to an account, then open the AVD’s launcher, select the Google app, and then enter your Gmail address and password.
- Double-check that the MyLocation app isn’t installed on this device. If it is, then uninstall it by dragging it onto the device’s Uninstall icon.
- Switch back to the main Android Studio window and select Run > Edit configurations…
- In the left-hand menu, select mylocation-instantapp.
- In the URL field, enter the URL you want to test, which in this instance is http://www.example.com/directions.
- Click Apply, followed by OK.
- In the Android Studio toolbar, click Run…
- Select mylocation-instantapp.
- Choose your target device, and then click OK.
Your DirectionsActivity
should now appear on your AVD. Congratulations, you’ve just built a multi-featured instant app!
Troubleshooting
Having to wrestle with bugs and other strange behaviour is all part of the fun of working with early access builds of Android Studio.
If your Android Studio build does go haywire, and you can’t spot anything wrong with your project, then it’s possible the error may lie with Android Studio itself.
In this section I’m going to share some workarounds for all the most common Android Studio errors and quirks you may encounter when creating a multi-feature instant app.
And, just in case you encounter a problem that isn’t listed here, I’ll also be sharing a list of general fixes that can help you smooth out whatever issues you’re currently experiencing with Android Studio.
Instant App Deployment Fails on API Levels 24 and 25
The first time you try to test your instant app on an AVD that’s running Nougat, it’s possible the app may fail to deploy. If this occurs, then:
- Select Run > Run mylocation-instantapp from the Android Studio toolbar.
- Before Android Studio has a chance to finish deploying your app, select Run > Stop.
- Select Run > Run mylocation-instantapp once again, but this time let the operation complete. Your instant app should now deploy without any problems.
Reliability Issue With Instant App Provisioning Cache
If you encounter the Reliability issue with instant app provisioning cache error message when trying to deploy your app, then this means you need to clear your cache:
- Select Run > Edit configurations… from the Android Studio toolbar.
- Select mylocation-instantapp from the left-hand menu.
- Select Instant app provision (towards the bottom of this window).
- Click the little pencil icon.
- Select Clear provisioned devices cache.
- Click OK, followed by Apply and OK once more.
AAPT2 Issues
If Android Studio complains about any AAPT2-related issues (such as displaying an AAPT2 link failed error message) then you can typically resolve these problems by disabling AAPT.
To disable AAPT, open your project’s Gradle scripts/gradle.properties
file and add the following text:
android.enableAapt2=false
Error:(85) attribute ‘android:splitName’ not found
This is easily the most frustrating, and the strangest issue you may encounter when developing instant apps.
In some builds of Android Studio 3.0, using the -
character in your module names can suddenly become an issue once you start adding more feature modules to your project. This error is particularly odd, as the -
character features in many of Google’s instant app samples, including the instant app Codelabs.
If Android Studio does start complaining about the android:splitName
attribute, then double-check that you’re running the latest release of Android Studio 3.0. You may also be able to resolve this issue by cleaning and then rebuilding your project.
If the problem persists, then as a last resort you may have to spend some time going through each of your modules and removing the -
character.
And If All Else Fails:
- Clean and rebuild your project. Select Build > Clean Project from the Android Studio toolbar, followed by Clean > Rebuild project.
- Try a different AVD. If you encounter an error whenever you try to deploy your instant app to an AVD, then you should test whether this problem persists when you’re using an AVD that has different specifications. While abandoning an AVD without at least verifying why your project is refusing to run on this device isn’t something you’ll want to carry through to your production apps, you can generally get away with bending the rules a bit when you’re experimenting with a new feature on an early access version of Android Studio. In particular, you may have more success when testing your instant app on an AVD that’s running Android O, compared with AVDs that are running an earlier version of Android.
- Check that you haven’t missed an update. At the time of writing, the Android Studio team are releasing a new Canary build on a weekly basis, so it’s always worth double-checking that you have the very latest version of Android Studio installed. In theory, each new release should fix all the issues discovered in the previous build, so if you aren’t running the latest version then it’s possible the problem you’re experiencing has already been fixed in a more recent build.
Distributing Your Instant App
Once you’ve finished testing your instant app project, the next steps are arranging some alpha and beta testing, and then you’re ready to unleash your app on the public!
You can complete all these tasks via the Google Play Console, and if you’ve ever released a “regular” installable app, then this process should feel very familiar:
- Navigate to the Play Console.
- Upload your application, if you haven’t already.
- Open the Play Console’s side-menu and select All applications.
- Select the application you want to test or publish.
- Select Android Instant Apps from the left-hand menu.
You can then choose from the following track types, depending on whether you want to test or publish your app:
- Instant app pre-release. This section contains all the settings you need to send pre-release candidates to your testers. Note that in order to use these settings, you’ll need to have created at least one list of testers; if you haven’t completed this step then you can create a list by selecting Settings > Manage testers > Create list from the Play Console’s side menu.
- Instant app development. This section allows you to deploy your application to your testers. Again, you’ll need to have created at least one list of testers in order to use the settings in this section.
- Instant app production. Once you’re happy with your app, this section contains everything you need to prepare, review and publish your application to the Google Play store.
Troubleshooting
When you try to publish a project that has instant app support, it’s possible that you may encounter the following error:
Your site ‘www.example.com” has not been linked through the Digital Assets Link protocol to your app.
If this occurs, then check that:
- Your Digital Asset Links file (
assetlinks.json
) is publicly available, and isn’t protected by any form of authentication, internal IP, or firewall. - All the URLs that are mapped to your feature modules are accessible externally. If your app uses any URLs that are only available internally, then you won’t be able to upload your app to the Google Play Console.
- The domain you’re using isn’t already associated with another application, as currently multiple instant apps cannot use the same domain.
- Your server has a valid SSL certificate from a public or trusted certificate authority.
Best Practices
Instant apps are an entirely new way of consuming Android applications, so it’s no surprise that they have their own best practices.
In this section, we’re going to ensure you’re getting the most out of this new feature, by taking a look at some instant app best practices.
Provide as Much Functionality as Possible Before Asking the User to Log In
It’s not all that unusual for installable apps to ask the user to create an account on the very first screen—after all, if the user has already committed to installing an app, then they’re unlikely to be scared off by that app asking for their email address!
However, instant apps are a completely different story, as it’s possible for a user to launch an instant app module without knowing anything about the related application. Imagine a friend has sent you a link with zero explanation, and tapping that link launches an instant app. You have no idea what this app has to offer or who created it, but it immediately asks for your email address—how likely are you to hand over this information?
If your instant app includes a login experience, then you should try to delay this login dialog for as long as possible. Giving the user more time to experience your app’s content and functionality will increase the chances of them creating an account when prompted.
Even if your installable app revolves around the user creating an account, you should still try and design your instant app modules so users can complete the task that prompted them to launch this module, before you ask them to create an account.
Consider Your Entry Points
Most installable apps only have a few entry points—typically, these are limited to the first Activity the user sees when they launch your app, and any Activities that can be started by implicit or explicit intents.
Instant apps have far more entry points, as each feature module must have at least one entry point, and can potentially have multiple entry points.
When you add instant app support to your app, one of the most important decisions you need to make is which Activity (or Activities) would serve as the best entry point for each module. You should select your entry points carefully, as ideally each entry point should:
- Allow the user to complete the task that prompted them to launch this module in the first place.
- Make the best possible first impression on users who may be experiencing your app for the first time.
- Provide all the context the user needs to understand what your app has to offer, just in case someone launches this module with zero background information about your app.
Provide a Seamless Experience for Users Who Migrate From Instant to Installable
Your app’s user interface, navigation, functionality, and overall look and feel should be constant across all your instant app modules and your installable APK. If you handed someone a device with your application already running, they should be unable to tell whether they’re looking at your app’s instant or its installable form.
In addition, any instant app user who takes the plunge and installs your app should be able to pick up exactly where they left off. For example, you could transfer the stored app state from your instant app to your installable app using either cookies or local storage.
Create Small, Lightweight Modules
Since instant apps are loaded on demand, the size of the instant app binary has a huge impact on how easily users can access your app.
The Android team have imposed a 4 MB limit on each instant app component (that’s the size of the feature module plus your project’s base feature module), but you should aim to make your modules even more lightweight if possible.
If you’re struggling to streamline a particular module, then take a critical look at what you’ve included in that module, as it may be possible to rework a single module into several smaller, self-contained modules.
Never Use Instant Apps as an Advert for Your Installable App
Although you should never design an instant app solely to drive traffic to your installable app, there are two kinds of installation prompts that you can use in your instant apps:
- implicit installation prompts
- explicit installation prompts
Implicit installation prompts are UI elements that the user interacts with expecting to trigger a certain feature, only to encounter an installation prompt instead.
This approach is reminiscent of Android’s runtime permissions model, as it allows you to issue installation prompts in context. Get the context right, and you should never have to explain why you’re displaying a particular installation prompt. For example, if the user encounters an installation prompt after tapping a Share this route with others button, then the message is clear: if you want to access this functionality, then you need to install the app.
Just don’t get carried away, to the point where your instant app starts to feel like an advert for your installable app. Your users will quickly get frustrated if your app is constantly teasing them with functionality that they can’t access, so limit yourself to a maximum of three implicit installation prompts per instant app module. You should also carefully consider where you place these installation prompts, to avoid the user encountering multiple prompts in quick succession.
Explicit installation prompts are UI elements that are clearly going to display an installation dialog when the user interacts with them, for example a button with “Install app” emblazoned across the front.
All explicit installation prompts should use the Material Design “get app” icon, and if you include any supporting text then choose your words carefully to avoid creating the impression that your instant app is in any way an incomplete or lesser version of your “real” app—so avoid saying things like upgrade now or install the full application!
Consider the Metrics You Want to Track
Traditionally, looking at the total number of installs has been one of the most effective ways of gauging an app’s success. However, when you add instant app support to a project, you remove the need for users to install that app, which requires you to rethink how you measure this app’s performance.
Instead of counting installations, you may want to measure metrics that relate to levels of user engagement, such as how much time users are investing in your app, the total number of tasks they complete, or how many users pay repeat visits to your instant app modules.
It’s also important to remember that even though instant app APKs and installable APKs are built from the same project, they represent two entirely different ways of consuming your application. To get the most accurate insight into your app’s performance, you’ll need a way of differentiating between the metrics gathered from your instant app component(s) and the metrics gathered from your installable app.
Conclusion
In this three-part series, we looked at how to add instant app support to your Android applications. If you’ve been following along from the beginning, then you’ll have successfully created a project consisting of two instant apps, which are triggered by different URLs.
If you want to get more experience with instant apps, then you could continue adding features modules to this project, or work on expanding the mylocation-directions
module so that it offers some real functionality.
In the meantime, check out some of our other posts on Android app development!
-
Android SDKIntroduction to Android Architecture Components
-
Machine LearningCreate Chatbots on Android With IBM Watson
-
Android SDKJava vs. Kotlin: Should You Be Using Kotlin for Android Development?
-
KotlinKotlin From Scratch: Variables, Basic Types, and Arrays
-
Android SDKQuick Tip: Write Cleaner Code With Kotlin SAM Conversions
-
Android SDKAndroid O: Phone Number Verification With SMS Tokens