Android instant apps are a powerful new way of getting your app in front of as many users as possible.
Once you’ve added instant app support to your project, users don’t even need to have your app installed in order to access its contents and features—they’ll be able to load entire sections of your application on-demand, simply by tapping a URL.
In this three-part series, I’m covering the entire process of adding instant app support to your Android projects, so by the time you’ve finished you’ll know exactly how to create Android applications that are discoverable and accessible for any location that supports URLs.
In the first post, we looked at what instant apps are and how they work, as well as examining why this new feature is such big news for both Android developers and Android users. Previously, we took a few shortcuts and created an Android project that has instant app support built-in, but we didn’t look at how to add instant app support to an existing project—so this is what we’re going to be focusing on in this post.
I’ll also be showing you how to implement App Links, so by the end of this article you’ll have created a fully functioning instant app that you can launch and test on any compatible Android device.
Downloading the Sample Project
Adding instant app support to a project typically requires you to make some pretty drastic changes to how that project is structured.
Chances are you’re not too keen on the idea of experimenting with a new feature by completely changing the structure of one of your own Android projects, so I’ve provided a sample app that you can download from GitHub. Throughout this article, we’ll be working on updating this specific project to support the instant apps feature.
Download the MyLocation project from GitHub and open it in Android Studio. You’ll see that this is a pretty straightforward project, made up of a single app module that contains one Activity
(MapsActivity
).
Although you can install and launch this project in its current state, if MapsActivity is going to display any real content, then you’ll need to generate an API key and add it to this project:
- Open the project’s
res/values/google_maps_api.xml
file. - Generate your Google Maps API key, by following the instructions in this file.
- Copy/paste the resulting key into the
google_maps_api.xml
file:
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">your_key_goes_here</string></resources>
We’re going to update this project so that its single feature (i.e. the ability to display the user’s current location on a map) is available in instant app form. To achieve this, we’re going to complete the following steps:
- Create a base feature module containing all the code and resources that are required to deliver this single feature.
- Create an instant app module that’ll serve as the container for our instant app APK.
- Use App Links to map a specific URL to this base feature module.
Before we begin, there are also a few things you need to be aware of:
- We won’t be adding any additional feature modules to this project until the next post. However, as you’ll see when we come to test MyLocation, it’s perfectly possible to add instant app support to a project by creating a base feature module and an instant app module—additional feature modules are an optional extra.
- Since the MyLocation project consists of a single feature only, we pretty much need to include all of its code and resources in the base feature module. We can make this task much easier by turning this project’s app module into the base feature module, and then creating a new module to serve as a replacement app module. This is a handy shortcut that you may be able to use when adding instant app functionality to your own real-life Android projects. However, if this shortcut isn’t feasible for a particular project, then you’ll need to create a new module to act as your base feature module, and then spend some time moving all the relevant code and resources into this new base feature module.
Convert the App Module Into a Base Feature Module
Our first task is converting MyLocation’s app module into a base feature module.
When you’re working with multiple modules, it helps to establish a naming convention early on, so throughout this article I’m going to be appending each module’s type (-app
, -base
, -instantapp
, etc.) to the module’s name:
- Control-click the app directory and select Refactor > Rename…
- In the Rename module window, enter mylocation-base and then click OK.
- Open your newly-renamed
mylocation-base
module’s build.gradle file. The first line reveals that this module is still using the defaultcom.android.application
plugin; however, all feature modules must use thecom.android.feature
plugin, so you’ll need to change this toapply plugin: 'com.android.feature.'
. - Make it clear that this module is your project’s one and only base feature module, by adding the
baseFeature true
attribute to theandroid
block of code. - Any project that supports the instant app feature is inevitably going to consist of multiple modules, but you only need to declare the project’s
applicationID
once—and that’s in the app module. To avoid conflicts and confusion, you should remove this attribute from the rest of your project, so find theapplicationID
attribute in themylocation-base
build.gradle file, and delete it.
After completing all these steps, your mylocation-base
build.gradle file should look something like this:
apply plugin: 'com.android.feature' android { baseFeature true compileSdkVersion 25 buildToolsVersion "26.0.0" defaultConfig { minSdkVersion 24 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" }
Create Your Application Module
At this point, MyLocation is missing an application module, so let’s create a replacement:
- Select New > New module… from the Android Studio toolbar.
- In the window that appears, select Phone and Tablet, and then click Next.
- Let’s stick to the naming convention we’ve established, and call this module mylocation-app. Click Next.
- This module should contain the code and resources that you want to include in your installable application, but to help keep things as straightforward as possible, click Add No Activity, and then click Finish.
- Open your
mylocation-app
module’s Manifest file. If you think back to the project we created in the previous post, you’ll remember that the app module’s Manifest was pretty much empty, because eventually the contents of all the other Manifests scattered throughout this project would be merged with this file. This is exactly what’s going to happen with our MyLocation project, so to avoid any conflicts during the merging process, you should delete this Manifest’s entireapplication
block.
- Open the
mylocation-app
module’s build.gradle file. This module depends on ourmylocation-base
module, so remove all the code from thedependencies
block, and replace it with the following:
dependencies { implementation project(':mylocation-base') }
- Remove all unused files and directories from your application module, by switching to Android Studio’s Project view and deleting the src/androidTest directory. Then, open the main directory and delete the Java, res and test directories.
We’ve successfully moved all of MyLocation’s functionality into a shareable base feature module. Since this required us to make some pretty drastic changes to our project structure, you should check that MyLocation is still functioning as an installable app:
- Launch the AVD (Android Virtual Device) we created in part one, or connect a physical Android device that’s compatible with the instant app feature—at the time of writing, this is limited to the Nexus 5X, Nexus 6P, Pixel, Pixel XL, or a Galaxy S7 that’s running Android 6.0 or higher.
- Select Run > Run… from the Android Studio toolbar.
- Select the mylocation-app module.
- The MyLocation app will appear onscreen and, assuming that you generated a Google Maps API key for this project, it should be displaying some Google Maps content.
Creating the Instant App Module
The instant app module fulfils the simple, but essential task of acting as a container for all the Instant App APKs that are generated by your project. To create this module:
- Select File > New > New Module… from the Android Studio toolbar.
- In the subsequent window, select Instant App and then click Next.
- Give this module the name mylocation-instantapp and click Finish.
- Since this instant app module exists solely to contain our base feature module, we need to open its
build.gradle
file and declaremylocation-base
as a dependency:
apply plugin: 'com.android.instantapp' dependencies { implementation project(':mylocation-base') }
Adding App Links to Your Project
The user launches an instant app by tapping a URL that’s mapped to a base feature or feature module. This URL could be anywhere—maybe it’s a URL a friend has sent them directly via email or instant message; maybe it’s a URL they’ve spotted in a tweet, forum or in a comment thread, or a URL that’s popped up in their Google search results.
Regardless of where it appears, when the user taps this link, Google Play will recognise that it’s associated with a base feature or feature module, and retrieves all the code and resources required to run this particular module on the user’s device.
In this section, we’re going to establish this relationship between our base feature module and a URL, using App Links. The Android App Links feature was originally introduced to help users bypass Android’s app selection dialog when they were trying to access content that could be handled by an app that’s already installed on their device. For example, if you tap a link to a YouTube video, then the system may display a dialog asking whether you want to open this link in the YouTube app.
In the context of instant apps, App Links allow you to map a feature module’s entry-point Activity to a specific URL. We explored entry-point Activities in part one, but as a recap, they’re the first Activity the user sees when they launch your base feature or “regular” feature module.
When you’re adding instant app support to a real-life project, you’ll need to decide which Activity would make the most effective introduction to your instant app component, but since mylocation-base
only has a single Activity, this decision has already been made for us!
Digital Asset Links
In this section, we’re going to use Android Studio’s built-in App Links Assistant to associate MapsActivity
with the URL www.example.com/maps, but first, a disclaimer:
Uploading a Digital Asset Links file to the domain you’re working with (in this instance, www.example.com) is a crucial step in the App Links process, as it’s how the system verifies that your app has permission to act as the default handler for all the links associated with this domain.
Although I’ll be covering the process of generating and uploading a Digital Asset Links file, since we don’t own the www.example.com domain, we won’t actually be able to perform this step. However, strangely, at the time of writing it does seem possible to test an instant app component on an AVD, even if you haven’t uploaded a Digital Asset Link to the associated domain—you just need to make some tweaks to Android Studio’s runtime configuration.
If you do have easy access to a domain where you can host a Digital Asset Links file, then I’d recommend replacing the www.example.com URLs with genuine URLs and uploading the resulting Digital Asset Links file to your website. However, even if you do use the www.example.com URLs then you should still be able to test MyLocation’s instant app component, by tweaking the runtime configuration.
Create the URL Mapping
Android Studio 2.3 and higher comes with a built-in App Links Assistant that makes adding App Links to your project much more straightforward:
- Select Tools > App Links Assistant from the Android Studio toolbar. The Assistant will open as a new panel along the right side of the Android Studio window.
- Give the Open URL Mapping Editor button a click.
- In the URL-to-Activity mappings panel that appears, click the little + icon.
- In the Host field, enter the domain you want to associate with this project; I’m going to use www.example.com.
The next step is entering the specific URL you want to use in your mapping. You have a few options here, so open the Path dropdown and choose from:
- Path. You should select this option if you want to map a single URL to your entry-point Activity. Since I only want
MapsActivity
to respond to the www.example.com/maps URL, I’m going to select Path from this dropdown menu. We’ve already associated the domain www.example.com with our project, so we just need to type the final part of the URL (/maps) into the accompanying text field.
- pathPrefix. This option lets you be a bit more flexible with the URLs that trigger your entry-point Activity. For example, if you selected pathPrefix and then entered www.example.com/maps in the accompanying text box, then
MapsActivity
would respond to URLs such as www.example.com/maps/mylocation and www.example.com/maps/nearby.
- pathPattern. Similar to Path, this option lets you specify the exact URL that should launch your entry-point Activity. However, it also gives you a bit more flexibility, by allowing you to use wildcard characters in the accompanying text field.
Next, you need to select MapsActivity
as this module’s entry-point Activity:
- Open the Activity dropdown menu.
- Select .MapsActivity (mylocation-base).
- Click OK.
The App Links Assistant helpfully updates your Manifest with all the code required to turn MapsActivity
into this module’s entry-point Activity; if you take a look at your mylocation-base
module’s Manifest, then you’ll see the following code:
<activity android:name=".MapsActivity" android:label="@string/title_activity_maps"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><intent-filter><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.BROWSABLE" /><data android:scheme="http" android:host="www.example.com" android:path="/maps" /></intent-filter></activity>
Next, we need to tell MapsActivity
how to respond when it’s launched via this URL. Once again, the App Links Assistant can walk you through this process:
- Back in the App Links Assistant, give the Select Activity button a click.
- Select the Activity you want to map to your URL, which in this instance is
MapsActivity
. - Click Insert code, and the App Links Assistant will insert the following code into the
MapsActivity
:
Intent appLinkIntent = getIntent(); String appLinkAction = appLinkIntent.getAction(); Uri appLinkData = appLinkIntent.getData(); }
When you come to add instant app support to your own real-life projects, you’ll typically want to expand on this code, depending on how you want your Activity to react when it’s launched as an instant app, but for the purposes of our MyLocation project, these few lines get the job done.
Associate Your App With Your Website
In this section I’m going to show you how to generate a Digital Asset Links file, and how to upload this file to your website. If you’re using www.example.com as a stand-in for genuine URLs, then you won’t be able to complete this step, but it’s still important to understand how to generate and upload this file, ready for when you’re adding instant app support to your own Android projects.
To create this association between your domain and your application, you need to complete the following steps:
- In the App Links Assistant, click the Open the Digital Asset Links File Generator button.
- Enter the domain you want to associate with this app, such as www.example.com.
- Enter your application ID.
- Enter your app’s signing config, or select a keystore file. While it’s possible to use a debug config or keystore during testing, the generated Digital Asset Links file won’t be compatible with the release version of your app. If you do upload a Digital Asset Links file that uses a debug config or keystore, then before publishing your app you’ll need to generate and upload a new Digital Asset Links that uses your app’s release key.
- Click the Generate Digital Asset Links file button.
- Download the Digital Asset File, by clicking the Save file button. In the Canary builds of Android Studio 3.0, this button is sometimes positioned offscreen, so you may need to resize your Android Studio window in order to bring the Save file button out of hiding. Clicking this button will download an
assetlinks.json
file to your computer. - You must host the assetlinks.json file at the following address https://<yoursite>/.well-known/assetlinks.json, so upload your newly downloaded assetlinks.json file to this exact location. Also be aware that Android verifies the assetlinks.json file via an encrypted HTTPs protocol, so you’ll need to ensure this file is accessible over an HTTPS connection.
- Back in Android Studio, click the App Link Assistant’s Link and verify button. If you’re following along with this tutorial using the www.example.com stand-in links, then Android Studio should report that you’ve successfully completed every step, except uploading the Digital Asset Links file.
Testing Your Instant App
Now you’re finally ready to test MyLocation’s instant app component!
Specifically, we want to test that if a user doesn’t have MyLocation installed on their device, then tapping the www.example.com/maps link will give them access to the mylocation-base module:
- Launch your instant app-compatible AVD.
- Verify that the MyLocation app isn’t installed on your AVD by opening its launcher. If you do spot the MyLocation app, then uninstall it by dragging it to the device’s Uninstall icon.
- Next, you’ll need to make some tweaks to our project’s run configuration, especially if you’re using www.example.com/maps to trigger your mylocation-base module. Start by selecting Run > Edit configurations... from the Android Studio toolbar.
- Select mylocation-instantapp from the left-hand menu.
- Open the Launch dropdown and set it to URL.
- Delete the <> text, and replace it with the URL you want to use, such as http://www.example.com/maps. When you select this run configuration, it’ll simulate the user tapping the www.example.com/maps link.
- Click Apply, followed by OK.
- Select Run > Run… from the Android Studio toolbar.
- Choose mylocation-instantapp as the component you want to launch.
- Select your target AVD, and click OK.
- If this is the first time you’re running an instant app on this particular AVD, then the device will prompt you to opt into the instant app program. Read the disclaimer, and if you’re happy to proceed, then click Yes, I’m in.
Android Studio will now simulate you tapping the www.example.com/maps link, and the AVD should respond by loading your base feature module. At this point, the MapsActivity
will appear onscreen, and you’ll be able to interact with it exactly as though MyLocation was installed on this device.
To verify that MyLocation really isn’t present on this device, minimise the MapsActivity
and open the AVD’s launcher—the MyLocation app should be completely absent, and yet if you click the AVD’s Recents softkey, the MapsActivity
is still visible and available on this device.
You can download the MyLocation project, updated with full instant app support, from GitHub.
Troubleshooting
Instant apps is still very much a new feature, so it’s not all that unusual to encounter error messages, bugs and other strange behaviour, especially if you’re using one of the Preview or Canary builds of Android Studio 3.0.
The most common problem you’ll encounter is, when selecting Run > Run instantapp from the Android Studio toolbar, to have the AVD respond by displaying the app picker dialog or by opening the URL in its default browser. If this occurs, then it means the AVD isn’t properly recognising that your URL is mapped to an instant app module, and is handling it just like a regular URL.
Assuming that you’ve implemented instant app support correctly, there are a few possible reasons why your AVD may be refusing to cooperate:
Is Your AVD Set Up to Allow Instant Apps?
Depending on the AVD you’ve created, it’s possible that you may need to explicitly tell your AVD to support instant apps:
- Open the AVD’s Settings app.
- Select Google.
- Scroll to the Services section.
- If you spot an Instant app option, then give it a tap.
- On the subsequent screen, drag the slider into the On position.
- Repeat the process of trying to launch your instant app module on your AVD, to see whether this has fixed your problem.
Are Instant Apps Supported in Your Locale?
Instant apps aren’t supported in every locale, so check whether instant apps are currently available in your part of the world. If they aren’t, then you’ll need to use adb (Android Debug Bridge) commands to trick your AVD into thinking you’re in a different location:
- Open the Terminal (if you’re a Mac user) or Command Prompt, if you’re on Windows.
- “Change directory” so the Terminal or Command Prompt is pointing at the adb program that’s included in your Android SDK, for example:
cd /Users/jessicathornsby/Library/Android/sdk/platform-tools
- Next, enter the following command:
adb shell
- Once a
#
appears in the Terminal or Command Prompt window, enter the next command:
setprop persist.sys.locale [ISO language code, plus country/region code] ;stop;sleep 5;start
- Your AVD will now reboot, and once it's restarted it’ll be using the new locale settings. You should now be able to successfully run instant apps on this device.
If All Else Fails….
If none of the above fixes work, then you may get some positive results by triggering the instant app component from an adb command, rather than by navigating the various Android Studio menus:
- Open a Terminal or Command Prompt window.
- Use the
cd
command so that the Terminal/Command Prompt is pointing at the adb program. - Enter the following command, being sure to replace
complete-url-path
with the URL you want to use:
./adb shell am start -a android.intent.action.VIEW -d complete-url-path
Side Loading Instant App Failed
Sometimes, Android Studio may outright refuse to even load an instant app component on your AVD, as some developers have reported encountering the following error whenever they try to launch an instant app:
Side loading instant app failed: Reading bundle timed out.
If you do encounter this error message in Android Studio, then you can usually resolve it by clearing the 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 pencil icon.
- Select Clear provisioned devices cache.
- Click OK, followed by Apply, and then hit OK once more.
- Attempt to relaunch your instant app component on your AVD—the problem should now be resolved.
Conclusion
In this article, we looked at how to update an existing Android project to support instant apps, by creating a base feature module and an instant app module, implementing App Links, and then testing this project on an AVD.
At this point, you have all the information you need to add instant app functionality to your existing Android projects, but with one restriction: we’ve only created a single base feature module. This means that, currently, you’re limited to offering one instant app feature per project.
In the final post of this series, we’re going to rectify this by looking at how you’d add an extra feature module to the MyLocation project. That'll be out soon. While you're waiting, check out some of our other great posts on Android app development!
- Android SDKAndroid O: Phone Number Verification With SMS Tokens
- Android ThingsAndroid Things: Creating a Cloud-Connected Doorman
- Android SDKCreate an Intelligent App With Google Cloud Speech and Natural Language APIs