Android MVP Architecture with Instant App Support.

This architecture is highly influenced by MindorksOpenSource’s MVP architecture. So, if you are a not familiar with MVP, I would recommend going through this article and then come back here. If you are looking for adding Instant App support to an existing application you might find this article helpful. Code for this article can be found below.


Instant App links for this project:

If your mobile device supports Instant App, you can use these links to try it out. To enable Instant Apps, navigate to Settings --> Google --> InstantApps and turn it on.

https://iambedant.com/source

https://iambedant.com/newslist/bbc-news

High level Structure:

This project consists of six modules. App Module, Instant App module and four feature modules.

Module Structure

Application module: Responsible for building the Application Apk.

InstantApp Module: Responsible for building Instant App Apks.

Feature Modules:

  • Base Module: Contains all Common components like Network component, Dependency Injection Setup, Base Activities, Base Presenters, etc.
  • Feature One Module: Contains all classes for first Instant App, which displays a list of news sources in a recyclerview.
  • Feature Two Module: Contains all classes for Second Instant App, which displays a list of news stories from a selected source.
  • Other Module: Contains other files which are not part of Instant App.

AppLinks For Navigation

Project uses Applinks for navigation between modules. Currently this project uses https://iambedant.com domain for applinks. You might want to replace it with your domain.

<intent-filter
android:autoVerify="true"
android:order="1">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="https" />
<data android:scheme="http" />
<data android:host="iambedant.com" />
<data android:pathPrefix="/source" />

</intent-filter>

<meta-data
android:name="default-url"
android:value="https://iambedant.com/source" />

Also one default-url is required to allow Google Play and Android launcher to discover the app. Association of the web domain to app’s package name is also necessary. To set it up, a JSON file has to be hosted at yourdomain.com/.well-known/assetlinks.json

[
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "com.iambedant.instantappstarter.app",
"sha256_cert_fingerprints": [
"C7:A4:C4:55:EF:4B:A0:04:76:7A:13:89:29:40:49:F3:EC:F5:87:4B:11:2D:FD:DF:C7:21:FA:D1:2F:7E:0C:CC"
]
}
}
]

One thing to keep in mind, package_name here is actually your application ID. Which is shared by both Application and Instant Apps.

Build Types

This project consists of three build types:

  • debug
  • release
  • qualityassurance
buildTypes {

debug {
debuggable true
minifyEnabled false
useProguard false
}
release {
debuggable false
minifyEnabled true
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
qualityassurance {
debuggable true
minifyEnabled true
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

configuration for release and qualityassurance build types are almost same. The only difference between these two is error message for qualityassurance build type is much more descriptive, which helps QA people channelize issues to proper teams.

In the current project proguard is disabled for all build types because apparently multi feature instant apps are not working with proguard on.

Update: 9/01/18: Wojtek Kaliciński has published a blogpost here on proguarding Instant Apps.

Product Flavors

This project has two build flavors:

  • uat
  • prod
productFlavors {
uat {
it.buildConfigField 'String', 'BASE_URL', BaseUrlUat
it.buildConfigField 'String', 'PASSWORD', passwordUat
manifestPlaceholders = [
appName: "InstantStarter uat"
]
dimension "mode"
}
prod {
it.buildConfigField 'String', 'BASE_URL', BaseUrlProd
it.buildConfigField 'String', 'PASSWORD', passwordProd
manifestPlaceholders = [
appName: "InstantStarter"
]
dimension "mode"
}
}

One for testing environment (uat) and one for production environment(prod). It also modifies the appname according to buildtypes.

Apk Split:

We are spliting apk for four architectures. “x86_64”, “armeabi-v7a”, “x86” and “arm64-v8a". If you want to understand apk split better, this is a great post by Brijesh Masrani.

splits {
abi {
enable false
reset()
include "x86_64", "armeabi-v7a", "x86", "arm64-v8a"
universalApk true
}
}

Runtime validation:

Android applications consume data from external sources like Network, Disk etc. In most of the cases app developers don’t have control over these sources. As a result one unexpected null value can crash an app. So to validate data at runtime, this project uses Uber’s Runtime Annotation Validation Engine RAVE.

The Instant Apps API:

implementation “com.google.android.instantapps:instantapps:1.0.0”

Android Instant Apps API reference provides a handy collection of utilities. This can be used for:

  • Determining whether user is using instant or installed version of your app.(In this project a download icon is shown to the user in the News List page if user is using the Instant App)
  • Show Instant app user a dialog to Install your App.
If you want to improve this project, your pull requests are most welcome. Also I would love to hear your thoughts in the comment section or at Twitter. Thanks a lot !