Overview

Android Instant Apps enables native Android applications to run in response to launching a URL without requiring installation. In this codelab, you will transform an existing Android project called "Topeka" to build an Android Instant App, in addition to an installed version.

Update Android Studio

Ensure you are using Android Studio 3.1 Preview. If you are using something older, please go here to download canary version 4 or later

Fetch Sample Project

To transform "Topeka" we will start with a base source code for this app. To get the code, clone the repo using the command below or download the zip

$ git clone https://github.com/googlecodelabs/android-topeka.git

Let's open "Topeka" using Android Studio. Run Android Studio 3 Preview and choose "Open an existing Android Studio project". Open the Topeka project you fetched in the previous step.

Now let's ensure that everything builds correctly within Android Studio. Go to Build > Build APK. The project should complete the build without any issues:

Install Instant App SDK

In order to build an Android Instant App, we need to install the SDK. Go to Tools >Android > SDK Manager. Click on the "SDK Tools" tab and install "Instant Apps Development SDK" by checking the box and hitting "Apply"

Install Android API 27 SDK and Tools

Go to Tools >Android > SDK Manager. Click on the "SDK Platforms" tab. Be sure to install the Android 8.1 system images and tools are installed by checking the following boxes under "SDK Platforms" tab and hitting "Apply" button:

Create an Emulated Device

The code lab will use an Emulator device to run Topeka. To create one, open an Android project and run AVD Manager from Android Studio (Tools > Android > AVD Manager) and create a new AVD with the following configuration:

Verify the device settings & tap "Finish" to create the emulated device.

Next, we should launch the app in the emulator and start to familiarize ourselves with it:

Running Topeka

Click ‘Run' to start the app. Select the emulator from the connected devices and check "Use same selection for future launches"

Verify the app runs and you get the following screen:

Before getting into the codelab, let's take a second to learn about a new plugin type that we will be using to create our instant app:

We will use the feature module throughout the codelab. In the first section, we will move our existing applications into the feature module and create an empty application module that depends on this base feature for its functionality. In the next section, we will create an instant app module that depends on this same feature module to produce an instant app APK. Finally, we will introduce a second feature module by moving some code out of the base feature. This will add more complex dependencies and illustrate how we express these in gradle build files.

In this step, we will convert the existing application module into a shareable feature module. We will then create a minimal application module that has a dependency on the newly formed feature. Note that this feature module will be included into the Instant App build targets later in the codelab.

At the end of this step the project should have an additional feature module that contains all of the source code files and a minimal application module that acts as a wrapper to create the APK.

Let's begin! First we switch the app module type from application to feature, which we will later use when assembling the APK.

Convert the app module into a feature module called topeka-base

We start with renaming the module from 'app' to 'topeka-base':

Next, we change the module type to Feature module by changing the plugin type from com.android.application to com.android.feature in the topeka-base/build.gradle file:

topeka-base/build.gradle

// replace
// apply plugin: 'com.android.application'
// with
apply plugin: 'com.android.feature'

Since this is no longer an application module, we need to remove applicationId from the library gradle file:

topeka-base/build.gradle

// in section defaultConfig
// remove line
applicationId "com.google.samples.apps.topeka"

And also disable proguard to decrease build times and avoid possible issues with incremental builds during refactoring (it is a good idea to disable proguard before significant refactoring anyway):

topeka-base/build.gradle

android {
    ...
    buildTypes {
        release {
            // Switch this from ‘true' to ‘false'
            minifyEnabled false
        }
    }
    ...
}

The last step here is to specify this as a base feature in the project.

topeka-base/build.gradle

android {
    ...
    baseFeature = true
    ...
}

Synchronize gradle files and re-build the project with Build->Rebuild Project.

Create topekaapk module to build APK file

Now that we have transformed our source code into a reusable library module, we can create a minimal application module that will create the APK. From File->New Module...

Select "Phone & Tablet Module", click "Next"

Enter application name "Topeka APK", leave suggested module name (topekaapk), click on "Edit" to the right of the suggested package name and change package name to com.google.samples.apps.topeka. Ensure that the minimum SDK is set to API 21 because that was the originally defined minimum version and the main APK should still work for that API level. Click "Next".

Select "Add No Activity" and click "Finish".

Android Studio may suggest to add some files to Git repository, click "Cancel". Android studio may ask you to install missing versions of build tools. Confirm installation to continue.

Since this project uses Data Binding, we need to ensure that topekaapk/build.gradle includes the following in the android { ... } section. This is because the data binding library requires all modules that include it to have this enabled:

topekaapk/build.gradle

android { 
    ...   
    dataBinding {
        enabled true
    }
}

Replace compile dependencies in topekaapk/build.gradle:

topekaapk/build.gradle

dependencies {
    implementation project(':topeka-base')
}

For more information on "implementation" (and "api") configurations, please see the Gradle documentation on these options

Switch to "Project" view

and remove unused files:

Switch back to "Android view" and remove the application element from topekaapk/src/main/AndroidManifest.xml. It should only contain this single manifest element.

topekaapk/src/main/AndroidManifest.xml

<manifest package="com.google.samples.app.topeka"
    xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

Finally sync Gradle files, re-build and run the project. The application should behave exactly the same despite all of our changes.

Congratulations! We have just moved the application's core functionality into a shareable feature module and we are now ready to start adding in the Instant App modules.

Android Instant Apps uses feature APKs to break up an app into smaller, feature focused modules. One way to look at Instant Apps is as a collection of these feature APKs. When the user launches a URL, Instant Apps will only deliver the necessary feature APKs to provide the functionality for that URL.

We have already created a single feature APK that encompasses the full functionality of our app. This base feature APK is the topeka-base module that we created. We will create an Instant App module that bundles our single feature APK. At the end we are going to have our single feature instant app!

Let's start by adding an Instant App module. The Instant App module is merely a wrapper for all the feature modules in your project. It should not contain any code or resources.

Create an Instant App module

Select File -> New -> New Module...

Choose "Instant App" and click "Next."

Enter name "topeka-instantapp" and click "Finish".

Android Studio adds the new instant app module for your project:

Next, we need to update the instant app gradle file to depend on the base feature module.

topeka-instantapp/build.gradle

dependencies {
    implementation project(':topeka-base')
}

Now do a clean rebuild: Build -> Rebuild project.

Defining App Links

In order to enable Instant App runtime to call your application, we must establish the relationship between your web site and the app. To associate links, we will use a new feature built into Android Studio called "App Links Assistant.". Invoke this tool through the Android Studio "Tools" menu:

From the sidebar, tap on the "Open URL Mapping Editor" button:

From the editor, tap the "+" button to add a new app link entry:

Create a new URL mapping with the following details:

Host: http://topeka.samples.androidinstantapps.com

Path: /signin (Select "pathPrefix" from dropdown)

Activity: activity.SigninActivity (topeka-base)

Repeat this dialog for https variation, as well as "/category" links:

Host: https://topeka.samples.androidinstantapps.com

Path: /signin (Select "pathPrefix" from dropdown)

Activity: activity.SigninActivity (topeka-base)

Host: http://topeka.samples.androidinstantapps.com

Path: /category (Select "pathPrefix" from dropdown)

Activity: activity.CategorySelectionActivity (topeka-base)

Host: https://topeka.samples.androidinstantapps.com

Path: /category (Select "pathPrefix" from dropdown)

Activity: activity.CategorySelectionActivity (topeka-base)

In the end, you should have 4 mappings like this:

Sync gradle files if required and rebuild the project.

The run configuration for instant app is not valid, we need to define the URL before we can launch the instant app from the IDE.

Click the Run configuration dropdown and choose "Edit Configurations..."

Select topeka-instantapp under Android App.

Replace the text ‘<< ERROR - NO URL SET>>' with https://topeka.samples.androidinstantapps.com/signin

To run your Instant App, select topeka-instantapp from the Run configuration dropdown and click Run:

To verify the running app is, in fact, an Instant App, check the drop down notification menu:

You should see "Instant Apps - Topkea" with the lightning bolt icon.

Congratulations!

You have now created and deployed an Android Instant App. You took an existing Android application and restructured it to build both a full installed APK and an Instant APK that will be loaded when the user taps on the associated URLs.

In the next part of the code lab you will learn how to refactor the sample app into multiple features, while keeping common code in the base feature. We would love for you to continue, but if you end this lab now, feel proud that you built your first Android Instant App!

If you check the size of the Instant App zip file, you will find that it is close to 4 MB, which is the limit for an Instant App split APK. What do we need to do if our application code is larger than 4 MB? We need to use multi feature application!

You may need to separate the code in multiple features for various reasons, the most obvious one is feature separation, to let users download only the relevant portions of the app. Let's introduce multi feature structure to our Instant App!

We will create another feature module and move all UI code there (activities and related fragments). It will let us create two features (topeka-base and topekaui) later.

Let's start by creating a new module topekaui using File -> New -> New Module. Choose "Feature Module" and click "Next."

Set package name as com.google.samples.apps.topeka.ui , application name as Topeka UI and module name as topekaui. Click ‘Next' .

In the final wizard screen, choose "Add no activity" and click Finish.

topekaui/build.gradle

Make sure you have data binding enabled:

// add to the the android section
    dataBinding {
        enabled true
    }

topekaui/build.gradle

Replace all pre-generated dependencies with the following dependency:

dependencies {
    api project(':topeka-base')
}

Now add dependencies to the newly created feature module in both topekaapk and topeka-instantapp

topeka-instantapp/build.gradle

Add the dependency to our new feature module topekaui

dependencies {
   implementation project(":topeka-base")
   implementation project(":topekaui")
}

topekaapk/build.gradle

Add the dependency to our new feature module topekaui

dependencies {
   implementation project(":topeka-base")
   implementation project(":topekaui")
}

topeka-base/build.gradle

dependencies {
   application project(":topekaapk")
   feature project(":topekaui")
   ...
}

topekaui/src/main/AndroidManifest.xml

Cut the application tag from topeka-base/src/main/AndroidManifest.xml over to topekaui replacing the generated tag. Make sure to also include the tools namespace to the root element.

<!-- make sure the package name is set to com.google.samples.apps.topeka.ui -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   package="com.google.samples.apps.topeka.ui">
   <application android:allowBackup="false"
       android:fullBackupContent="false"
       android:hardwareAccelerated="true"
       android:icon="@mipmap/ic_launcher"
       android:label="@string/app_name"
       android:supportsRtl="false"
       android:theme="@style/Topeka"
       tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
   </application>
</manifest>


Switch to "Project" view and delete the test sources in topekaui

Sync gradle files and make sure you can re-build the project (Build -> Rebuild project). Although we didn't add any code to the UI module, you should be able to run the multi-split instant app.

Move classes from topeka-base module to topekaui module

Make sure you are using "Android" view. Create new packages called "fragment" and "activity" relative to "com.google.samples.apps.topeka.ui":

Your Android view tree should look like this for topekaui:

Select the CategorySelectionFragment, QuizFragment and SignInFragment classes from topeka-base:

"Cut" them (Ctrl/Cmd+X).

Select your new "fragment" package in "topekaui" module and paste (Ctrl/Cmd+V):

A dialog will pop up warning about conflicts. Press Continue. If asked, also press "Do Refactor"

Repeat this the CategorySelectionActivity, QuizActivity and SignInActivity classes, pasting into the "activity" package in the same "topekaui" module.

You should end up with the following structure:

Now, let's also move "CategorySelectionActivity", "QuizActivity" and "SignInActivity" declarations from the application manifest in topeka-base over to the topekaui module:

topeka-base/src/main/AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:tools="http://schemas.android.com/tools"
         package="com.google.samples.apps.topeka">
</manifest>

Clean and re-build the project (Build -> Rebuild Project). There will now be some build errors that result from splitting the code into 2 separate modules. We will resolve these issues in the following section.

Decouple Activities from widgets

Add the following interface definition to AbsQuizView. Press Ctrl+N/Cmd+O, type "AbsQuizView" and add the following:

   // near the end of the class (line 361) add:
   public interface NextStepHandler {
       void proceed();
   }

Ensure QuizActivity implements these interfaces (the actuals methods are already there). Press Ctrl+N/Cmd+O and modify the class declaration:

replace

public class QuizActivity extends AppCompatActivity {

with

public class QuizActivity extends AppCompatActivity implements AbsQuizView.NextStepHandler {

Modify AbsQuizView to use this interface instead of directly calling activity methods (in method moveViewOffScreen(boolean)):

@@ -347,8 +349,8 @@ public abstract class AbsQuizView<Q extends Quiz> extends FrameLayout {
             @Override
             public void run() {
                 mCategory.setScore(getQuiz(), answerCorrect);
-                if (getContext() instanceof QuizActivity) {
-                    ((QuizActivity) getContext()).proceed();
+                if (getContext() instanceof NextStepHandler) {
+                    ((NextStepHandler) getContext()).proceed();
                 }
             }
         };

Make sure the resulting code looks like

private void moveViewOffScreen(final boolean answerCorrect) {
   // Move the current view off the screen.
   mMoveOffScreenRunnable = new Runnable() {
       @Override
       public void run() {
           mCategory.setScore(getQuiz(), answerCorrect);
           if (getContext() instanceof NextStepHandler) {
               ((NextStepHandler) getContext()).proceed();
           }
       }
   };
   mHandler.postDelayed(mMoveOffScreenRunnable,
           FOREGROUND_COLOR_CHANGE_DELAY * 2);
}

And remove the invocation of lockIdlingResource() method:

@@ -280,7 +280,6 @@ public abstract class AbsQuizView<Q extends Quiz> extends FrameLayout {
      * @param answerCorrect <code>true</code> if the answer was correct, else <code>false</code>.
      */
     private void performScoreAnimation(final boolean answerCorrect) {
-        ((QuizActivity) getContext()).lockIdlingResource();
         // Decide which background color to use.
         final int backgroundColor = ContextCompat.getColor(getContext(),
                 answerCorrect ? R.color.green : R.color.red);
         ....

The resulting code should look like

private void performScoreAnimation(final boolean answerCorrect) {
   // Decide which background color to use.
   final int backgroundColor = ContextCompat.getColor(getContext(),
           answerCorrect ? R.color.green : R.color.red);

  ....

At this stage the code no longer needs the .contrib.CountingIdlingResource class, so let's remove the entire package (make sure you do this from ‘Android' view, otherwise you will need to manually remove import for CountingIdlingResource from QuizActivity):

Press Ctrl+Alt+O to remove unused imports for AbsQuizView. Make sure the AbsQuizView no longer mentions QuizActivity.

Make sure you can re-build the project (Build -> Rebuild Project).

Sync and rebuild the project. You may have to clean up some imports and remove unused references around QuizActivity and CountingIdlingResource. You should also rename activity and fragment imports to include ".ui" in their import path.

Assuming you have a valid run configuration, you should be able to deploy and run the Instant App using Android Studio's "Run" button.

You've successfully taken a real world Android applications and have gone through the process of preparing it for an Android Instant App user experience. If this were your own app, the final step would be to publish on the Play Store. If you have time, glance through this guide to get an idea of the final steps!

If you want to go deeper on Android Instant Apps, here are some links to get you started:

Main Docs

Code Samples

UX Guidelines

FAQ