Pro Yearly is on sale from $80 to $50! »

Introduction to Android Instant Apps

Introduction to Android Instant Apps

Android Instant Apps are the new kid in the large town of Android-city. The promise behind it is quite simple and groundbreaking at the same time: running native Android apps instantly on your device, without installation.

In this session we will first introduce this evolution in app sharing and discovery mostly from a user perspective. Secondly, we will discover how, as a developer, you can build an Android Instant Apps and deliver this new experience frictionless to all of your users.

E9bf8f6d5480ea2a2623df7dccfd1f70?s=128

Cyril Mottier

October 20, 2017
Tweet

Transcript

  1. Introduction to Android Instant Apps by Cyril Mottier

  2. None
  3. >

  4. > >

  5. > > >

  6. Find Install Start Setup Use Installing & using a mobile

    app is a long and steep path
  7. Reduce friction as much as possible

  8. Instant apps Native apps, without installation

  9. None
  10. >

  11. > >

  12. You may only need 10% of an app’s features So

    why download 100%?
  13. Application

  14. Application Feature 1 Feature 2 Feature 3 Common

  15. The build output now depends on the targeted run mode

  16. installable.apk Feature 1 Feature 2 Feature 3 Common

  17. instant_app.zip Feature 1 APK Feature 2 APK Feature 3 APK

    Base APK
  18. What about the on-device behaviour?

  19. Installable app

  20. Feature 1 Feature 2 Feature 3 Base Installable app

  21. Instant app

  22. Feature 1 Base Instant app Using feature 1

  23. Feature 2 Base Instant app Using feature 2

  24. Feature 1 Base Instant app Using feature 1 then 2

  25. Feature 1 Feature 2 Base Instant app Using feature 1

    then 2
  26. Feature 1 Feature 2 Feature 3 Base Instant app Using

    all features
  27. Lollipop+

  28. Android Studio 3.0+ with Instant Apps Development SDK

  29. Runtime permissions introduced in Android 6.0 (API level 23)

  30. App links Associate your app with your domain

  31. <intent-filter android:autoVerify="true"> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <action android:name="android.intent.action.VIEW"

    /> <data android:scheme="http" /> <data android:scheme="https" /> <data android:host="${host}" android:path="/licenses" /> </intent-filter> android:autoVerify="true"
  32. <intent-filter android:autoVerify="true"> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <action android:name="android.intent.action.VIEW"

    /> <data android:scheme="http" /> <data android:scheme="https" /> <data android:host="${host}" android:path="/licenses" /> </intent-filter> android:autoVerify="true"
  33. <intent-filter android:autoVerify="true"> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <action android:name="android.intent.action.VIEW"

    /> <data android:scheme="http" /> <data android:scheme="https" /> <data android:host="${host}" android:path="/licenses" /> </intent-filter> android:autoVerify="true"
  34. https://<host>/.well-known/assetlinks.json

  35. https://<host>/.well-known/assetlinks.json [ { "relation": [ "delegate_permission/common.handle_all_urls" ], "target": { "namespace":

    "android_app", "package_name": "com.gdgnantes.devfest.android", "sha256_cert_fingerprints": [ "1A:24:9C:B5:69:5F:B5:21:CD:80:45:7A:06:20:C5:78:DB: 07:A8:CA:A0:8F:E9:47:B9:F6:A5:60:6B:78:DB:32" ] } } ]
  36. https://<host>/.well-known/assetlinks.json [ { "relation": [ "delegate_permission/common.handle_all_urls" ], "target": { "namespace":

    "android_app", "package_name": "com.gdgnantes.devfest.android", "sha256_cert_fingerprints": [ "1A:24:9C:B5:69:5F:B5:21:CD:80:45:7A:06:20:C5:78:DB: 07:A8:CA:A0:8F:E9:47:B9:F6:A5:60:6B:78:DB:32" ] } } ] "relation": [ "delegate_permission/common.handle_all_urls" ]
  37. https://<host>/.well-known/assetlinks.json [ { "relation": [ "delegate_permission/common.handle_all_urls" ], "target": { "namespace":

    "android_app", "package_name": "com.gdgnantes.devfest.android", "sha256_cert_fingerprints": [ "1A:24:9C:B5:69:5F:B5:21:CD:80:45:7A:06:20:C5:78:DB: 07:A8:CA:A0:8F:E9:47:B9:F6:A5:60:6B:78:DB:32" ] } } ] "namespace": "android_app" "target": { }
  38. https://<host>/.well-known/assetlinks.json [ { "relation": [ "delegate_permission/common.handle_all_urls" ], "target": { "namespace":

    "android_app", "package_name": "com.gdgnantes.devfest.android", "sha256_cert_fingerprints": [ "1A:24:9C:B5:69:5F:B5:21:CD:80:45:7A:06:20:C5:78:DB: 07:A8:CA:A0:8F:E9:47:B9:F6:A5:60:6B:78:DB:32" ] } } ] "package_name": "com.gdgnantes.devfest.android" "target": { }
  39. https://<host>/.well-known/assetlinks.json [ { "relation": [ "delegate_permission/common.handle_all_urls" ], "target": { "namespace":

    "android_app", "package_name": "com.gdgnantes.devfest.android", "sha256_cert_fingerprints": [ "1A:24:9C:B5:69:5F:B5:21:CD:80:45:7A:06:20:C5:78:DB: 07:A8:CA:A0:8F:E9:47:B9:F6:A5:60:6B:78:DB:32" ] } } ] "sha256_cert_fingerprints": [ "1A:24:9C:B5:69:5F:B5:21:CD:80:45:7A:06:20:C5:78:DB: 07:A8:CA:A0:8F:E9:47:B9:F6:A5:60:6B:78:DB:32" ] "target": { }
  40. https://<host>/.well-known/assetlinks.json [ { "relation": [ "delegate_permission/common.handle_all_urls" ], "target": { "namespace":

    "android_app", "package_name": "com.gdgnantes.devfest.android", "sha256_cert_fingerprints": [ "1A:24:9C:B5:69:5F:B5:21:CD:80:45:7A:06:20:C5:78:DB: 07:A8:CA:A0:8F:E9:47:B9:F6:A5:60:6B:78:DB:32" ] } } ]
  41. Modularise your code Break the app into features

  42. Pointing out features

  43. Licenses :features:licenses module Installable app :app module About :features:about module

  44. What about the base APK? contains code/resources used in all

    modules
  45. Application icon Custom font management Common styles, dimens, colors, …

    Base Activity/Fragment implementation Utilities etc. What about the base APK? contains code/resources used in all modules
  46. Modularize action in Android Studio

  47. ./settings.gradle include ':app', ':features:about', ':features:base', ':features:licenses', ':instant'

  48. include ':app', ':features:about', ':features:base', ':features:licenses', ':instant' ./settings.gradle ':app'

  49. include ':app', ':features:about', ':features:base', ':features:licenses', ':instant' ':features:base' ./settings.gradle

  50. include ':app', ':features:about', ':features:base', ':features:licenses', ':instant' ':features:about' ./settings.gradle

  51. include ':app', ':features:about', ':features:base', ':features:licenses', ':instant' ':instant' ./settings.gradle

  52. apply plugin: 'com.android.feature' android { //... baseFeature true } dependencies

    { application project(':app') feature project(':features:about') feature project(':features:licenses') } ./features/base/build.gradle
  53. apply plugin: 'com.android.feature' android { //... baseFeature true } dependencies

    { application project(':app') feature project(':features:about') feature project(':features:licenses') } ./features/base/build.gradle apply plugin: 'com.android.feature'
  54. apply plugin: 'com.android.feature' android { //... baseFeature true } dependencies

    { application project(':app') feature project(':features:about') feature project(':features:licenses') } ./features/base/build.gradle baseFeature true
  55. apply plugin: 'com.android.feature' android { //... baseFeature true } dependencies

    { application project(':app') feature project(':features:about') feature project(':features:licenses') } ./features/base/build.gradle application project(':app') feature project(':features:about') feature project(':features:licenses')
  56. apply plugin: 'com.android.feature' android { //... baseFeature true } dependencies

    { application project(':app') feature project(':features:about') feature project(':features:licenses') } ./features/base/build.gradle
  57. apply plugin: 'com.android.feature' //... dependencies { implementation project(':features:base') } ./features/about/build.gradle

  58. apply plugin: 'com.android.application' //... dependencies { implementation project(':features:base') implementation project(':features:about')

    implementation project(':features:licenses') } ./app/build.gradle
  59. apply plugin: ‘com.android.instantapp' //... dependencies { implementation project(':features:base') implementation project(':features:about')

    implementation project(':features:licenses') } ./instant/build.gradle
  60. apply plugin: ‘com.android.instantapp' //... dependencies { implementation project(':features:base') implementation project(':features:about')

    implementation project(':features:licenses') } ./instant/build.gradle apply plugin: ‘com.android.instantapp'
  61. apply plugin: ‘com.android.instantapp' //... dependencies { implementation project(':features:base') implementation project(':features:about')

    implementation project(':features:licenses') } ./instant/build.gradle
  62. where Function returning the binary size of Total download bundle

    binary size
  63. where Function returning the binary size of Maximum download bundle

    binary size
  64. Maximum download bundle size (i.e. that weird “ ” constant)

  65. During development ∞ Maximum download bundle size (i.e. that weird

    “ ” constant)
  66. Play Store dev tracks 10MB During development ∞ Maximum download

    bundle size (i.e. that weird “ ” constant)
  67. 4MB Play Store production Play Store dev tracks 10MB During

    development ∞ Maximum download bundle size (i.e. that weird “ ” constant)
  68. The smaller, the better (not specific to Android only)

  69. Slim down your APK size

  70. Slim down your APK size Resource shrinking

  71. Slim down your APK size Code minification Resource shrinking

  72. Slim down your APK size Code minification Vector graphics Resource

    shrinking
  73. Slim down your APK size Code minification Vector graphics Resource

    shrinking
  74. Slim down your APK size Dependencies reduction Code minification Vector

    graphics Resource shrinking Downloadable fonts Resources de-duplication Remote fetching Images optimisation WebP format Granular dependencies Density bucket removal Native code architecture removal Wear 2.0 APK distribution Sparse translation elimination Version collapsing
  75. APK Analyser

  76. APK Analyser

  77. Still not enough? Configuration split to the rescue

  78. android { //... generatePureSplits true splits { abi { enable

    true } density { enable true } language { enable true include "en", "fr" } } } ./base.build.gradle
  79. Installation prompts

  80. dependencies { //... implementation 'com.google.android.instantapps:instantapps:1.1.0' } ./features/base/build.gradle

  81. if (InstantApps.isInstantApp(this)) { val postInstallIntent = MainActivity.newIntent() InstantApps.showInstallPrompt(this, postInstallIntent, INSTALL_PROMPT_REQUEST_CODE,

    "Referrer") }
  82. Keep user state after app installation

  83. Cookie API // Instant app with(packageManager) { if (cookie.size <=

    instantAppCookieMaxBytes) { updateInstantAppCookie(cookie) } }
  84. // Installable app val cookie = packageManager.instantAppCookie // ... (i.e.

    restore user data) packageManager.clearInstantAppCookie() Cookie API
  85. Instant App Data dependencies { //... implementation 'com.google.android.gms:play-services-instantapps:11.4.2' } ./features/base/build.gradle

  86. Instant App Data val client = InstantApps.getInstantAppsClient(this) val fileTask =

    client.instantAppData fileTask .addOnCompleteListener { readData(it.result) } .addOnFailureListener { handleException(it) }
  87. Instant App Data Shared Preferences getFilesDir() getDir(String, int) Databases ParcelFileDescriptor

    to the caller's Instant App's data
  88. Instant Apps in the real world aka the pros and

    cons
  89. VS Instant apps Progressive Web apps

  90. Thank you! cyrilmottier.com @cyrilmottier