IntroduceInstantApps(DroidKaigi2018)

Daec7e5cd5fae384eda88037d937343b?s=47 AAkira
February 07, 2018

 IntroduceInstantApps(DroidKaigi2018)

Introduce Instant Apps in your existing project.
This is talked in https://droidkaigi.jp/2018/

Sample project on github : https://github.com/AAkira/DaggerInstantApps

Daec7e5cd5fae384eda88037d937343b?s=128

AAkira

February 07, 2018
Tweet

Transcript

  1. 既存アプリへの
 Instant Apps導入 荒谷 光 あらたに あきら @_a_akira - Introduce Instant Apps

    -
  2. About me @_a_akira AAkira CyberAgent, Inc. Akira Aratani

  3. • 生放送配信プラットフォーム • ライブファンディング • 4K配信対応, 低遅延配信 • M11の頃からFull Kotlinで開発


    サーバサイドも1年前からKotlinを使用 About 3
  4. Agenda • About Instant Apps • Develop Instant Apps •

    Tools • Modularize • Modularize by Dagger Injection • Summary 4
  5. About Instant Apps

  6. https://youtu.be/862r3XS2YB0?t=5993 Google I/O 2016 (1:39:50頃) 6

  7. About Instant Apps • Google I/O 2016で発表 • Google I/O

    2017の当日から使用可能に • Android 6.0+
 (将来的には5.0+) 7
  8. 8

  9. Purpose • URLベースでアクセス可能なので、
 最初のキッカケを与えられる • ネイティブアプリと同じ経験を 9

  10. Use case • 将来的には、
 位置情報, QRCode, ビーコン、NFC
 をキッカケにすることも考えている • Text

    baseのurlで起動出来るので、
 広告での使用も可能 10
  11. Use case • 検索結果から
 InstantAppsを直接起動
 11 © RED BULL

  12. Use case • Slack等の
 メッセージアプリからも
 InstantAppsを直接起動 12 © Vimeo, Inc.

  13. Use case Web Pageでの表示 Storeでの表示 13 sharethemeal.org © RED BULL

  14. Use case • Instant Appsは
 端末にDLされる 14

  15. Use case • Instant Appsは
 端末にDLされる 15

  16. APIs • Smart Lock
 → ログインがスムーズに • Google Payment API


    → 購入がスムーズに 16 Wish © ContextLogic, Inc.
  17. APIs • Play Install API
 → インストールまでが
   スムーズに 17

    © Vimeo, Inc.
  18. About Instant Apps • ユーザへの障壁を出来るだけ減らす • UXを上げる各種APIが揃っている 18

  19. About Instant Apps • ユーザへの障壁を出来るだけ減らす • UXを上げる各種APIが揃っている Googleの目指している未来 19

  20. Develop
 Instant Apps

  21. Development tools Android Studio 3.0+ Emulator Support App Links include

    SDK 21
  22. App links • Marshmallow(6.0)から導入 • Manifestに<intent-filter>を追加 • サーバにjsonファイルを配置すれば
 リンクをクリックした時にアプリを起動可能
 AndroidManifestに


    android:autoVerify=“true”を指定する 22
  23. App links assistant • Tools > App links assistant 23

  24. Develop instant apps 1つのコードベースで
 instant apps, installed appの開発が可能 24

  25. Develop instant apps 1つのコードベースで
 instant apps, installed appの開発が可能 25

  26. Modularization Feature three Feature one Feature two Source code Installed

    app 26
  27. Modularization Feature three Feature one Feature two Source code 4MB

    Installed app 27
  28. Source code Modularization Base module Feature one module Feature two

    module Instant apps Installed app 28
  29. Source code Modularization Base module Feature one module Feature two

    module Instant apps Installed app 4MB 29
  30. Source code Modularization Base module Feature one module Feature two

    module Installed app Instant apps 30
  31. Reduce app size 4MB 制限が一番大変 31

  32. Reduce app size • webP • Vector drawable 32

  33. Reduce app size android { ... buildTypes { release {

    minifyEnabled true
 shrinkResources true proguardFiles getDefaultProguardFile( 
 'proguard-android.txt'), 'proguard-rules.pro' } } } 33
  34. Reduce app size android { ... buildTypes { release {

    minifyEnabled true
 shrinkResources true
 useProguard false proguardFiles getDefaultProguardFile( 
 'proguard-android.txt'), 'proguard-rules.pro' } } } 34
  35. Modularize

  36. Modularization • リポジトリの一覧リスト • リポジトリ詳細 • プルリクエスト一覧 • Issue一覧 GitHubクライアント

    36
  37. Modularization • リポジトリの一覧リスト ← Installed • リポジトリ詳細 ← Instant, Installed

    • プルリクエスト一覧 ← Installed • Issue一覧 ← Installed • 通信等の共通部分 ← Base, Instant, Installed GitHubクライアント 37
  38. Structure Base module Feature one module Feature two module Instant

    Installed 38
  39. Structure Base module Feature one module Feature two module Instant

    Installed API通信等の
 共通処理 39
  40. Structure Base module Feature one module Feature two module Instant

    Installed リポジトリ詳細 API通信等の
 共通処理 40
  41. Structure Base module Feature one module Feature two module Instant

    Installed リポジトリ詳細 PR
 Issue
 リポジトリ一覧 API通信等の
 共通処理 41
  42. Step by Step -Gradle -

  43. Package structure • installed → app • instant → instantapp

    43
  44. 1. Apply plugin • Installed module apply plugin: 'com.android.application' apply

    plugin: 'com.android.instantapp' apply plugin: 'com.android.feature' • Instant module • Base, Feature module 44
  45. 2. Specify baseFeature • Base module android { ... buildToolsVersion

    "26.0.1" ... defaultConfig { ... } Base module Feature one Feature two Instant Installed 45
  46. 2. Specify baseFeature • Base module android { ... buildToolsVersion

    "26.0.1" baseFeature true ... defaultConfig { ...
 } Base module Feature one Feature two Instant Installed 46
  47. 3. Dependencies • Installed module dependencies { implementation project(":base") implementation

    project(":featureone") implementation project(":featuretwo") } Base module Feature one Feature two Instant Installed 47
  48. 3. Dependencies • Instant module dependencies { implementation project(":base") implementation

    project(":featureone") } Base module Feature one Feature two Instant Installed 48
  49. 3. Dependencies • Feature one module dependencies { implementation project(":base")

    } Base module Feature one Feature two Instant Installed 49
  50. 3. Dependencies • Feature two module dependencies { implementation project(":base")

    } Base module Feature one Feature two Instant Installed 50
  51. 3. Dependencies • Base module dependencies { application project(":app") feature

    project(":featureone") feature project(":featuretwo") } Base module Feature one Feature two Instant Installed 51
  52. Installed module.gradle apply plugin: 'com.android.application' android { ... } dependencies

    { implementation project(':base') implementation project(':featureone') implementation project(':featuretwo') } 52 Base module Feature one Feature two Instant Installed
  53. Instant module.gradle apply plugin: 'com.android.instantapp' android { ... } dependencies

    { implementation project(':base') implementation project(':featureone') } 53 Base module Feature one Feature two Instant Installed
  54. Feature module.gradle apply plugin: 'com.android.feature' ... android { ... }

    dependencies { implementation project(':base') } 54 Base module Feature one Feature two Instant Installed
  55. Base module.gradle apply plugin: 'com.android.feature' ... android { ... baseFeature

    true ... } dependencies { application project(':app') feature project(':featureone') feature project(':featuretwo') } 55 Base module Feature one Feature two Instant Installed
  56. Step by Step -App links -

  57. App links Base module Feature one module Feature two module

    Instant Installed 57
  58. App links module間の参照は? 58

  59. App links 通常:各Activityにstaticなメソッド companion object { private const val KEY_HOGE

    = "hoge" fun createIntent(context: Context, hoge: Int): Intent = Intent(context, MainActivity::class.java).apply { putExtra(KEY_HOGE, hoge) } } 59
  60. App links Feature one module Feature two module リポジトリ詳細 リポジトリ一覧

    60
  61. App links Feature one module Feature two module リポジトリ詳細 リポジトリ一覧

    61 参照不可 ɹ
  62. App links Feature one module Feature two module リポジトリ詳細 リポジトリ一覧

    https://hoge.com/repository/hoge App links 62
  63. App links • AndroidManifestにintent filterを追加 <activity android:name=".ui.repo.RepoActivity"> <intent-filter android:priority="1"> <action

    android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:host="aakira.github.com" android:pathPattern="/.*" android:scheme="https" /> </intent-filter> </activity> 63
  64. App links • data属性にhost, path, schemeを指定 <activity android:name=".ui.repo.RepoActivity"> <intent-filter android:priority="1">

    <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:host="aakira.github.com" android:pathPattern="/.*" android:scheme="https" /> </intent-filter> </activity> 64
  65. App links • priorityは大きいほど優先 <activity android:name=".ui.repo.RepoActivity"> <intent-filter android:priority="1"> <action android:name="android.intent.action.VIEW"

    /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:host="aakira.github.com" android:pathPattern="/.*" android:scheme="https" /> </intent-filter> </activity> 65
  66. App links • base module/Navigator.kt const val KEY_REPO_GITHUB_REPO = "key_repo_github_repo"

    fun Activity.startRepoActivity(githubRepo: GithubRepo) { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(
 "https://github.com/aakira/DaggerInstantApps")).apply { `package` = packageName addCategory(Intent.CATEGORY_BROWSABLE) putExtra(KEY_REPO_GITHUB_REPO, githubRepo) }) } 66
  67. App links Feature one module Feature two module リポジトリ詳細 Search

    Intent リポジトリ一覧 Google検索 自他アプリから 67
  68. Step by Step -Dagger -

  69. Sample Project 69 AAkira/DaggerInstantApps https://goo.gl/7xqb5M @_a_akira

  70. Gradle • Dagger android support(2.10.0+)
 今回は2.14.1を使う implementation dagger "com.google.dagger:dagger:2.14.1" implementation

    daggerAndroid "com.google.dagger:dagger-android:2.14.1" implementation daggerAndroidSupport "com.google.dagger:dagger-android-support:2.14.1" implementation daggerCompiler "com.google.dagger:dagger-compiler:2.14.1" implementation daggerAndroidProcessor "com.google.dagger:dagger-android-processor:2.14.1" 70
  71. App structure • リポジトリの一覧リスト (RepoList) • リポジトリ詳細 (Repo) • プルリクエスト一覧

    (PullRequestList) • Issue一覧 (IssueList) GitHubクライアント 71
  72. App structure • Scope 72 Repo PR Issue Base module

    (App Scope) Repo
 List
  73. App structure • Scope 73 Repo PR Issue Repo
 List

    Base module (App Scope) App Scope PerUi Scope PerUi Scope PerUi Scope PerUi Scope
  74. App structure Base module Feature one module Feature two module

    Instant Installed 74
  75. App structure Base module Feature one module Feature two module

    Instant Installed 75 Base moduleから Feature moduleへの参照は出来ない
  76. App structure • Scope 76 Repo PR Issue Module One

    Base module (App Scope) Repo
 List Module Two App Scope PerModule Scope PerModule Scope PerUi Scope PerUi Scope PerUi Scope PerUi Scope
  77. Base/AppComponent 77 @Singleton @Component(modules = [ AndroidSupportInjectionModule::class, AppModule::class, ActivityBuilder::class ])

    interface AppComponent : AndroidInjector<App>, AppComponentProviders { override fun inject(instance: App) @Component.Builder interface Builder { @BindsInstance fun application(application: Application): Builder fun build(): AppComponent } }
  78. Base/AppComponent 78 @Singleton @Component(modules = [ AndroidSupportInjectionModule::class, AppModule::class, ActivityBuilder::class ])

    interface AppComponent : AndroidInjector<App>, AppComponentProviders { override fun inject(instance: App) @Component.Builder interface Builder { @BindsInstance fun application(application: Application): Builder fun build(): AppComponent } }
  79. Base/Application 79 class App : DaggerApplication() { companion object {

    fun appComponent(context: Context) = 
 (context.applicationContext as App).appComponent } private val appComponent = DaggerAppComponent.builder()
 .application(this)
 .build() override fun applicationInjector(): AndroidInjector<out DaggerApplication> = appComponent.apply { inject(this@App) } }
  80. Base/Application 80 class App : DaggerApplication() { companion object {

    fun appComponent(context: Context) = 
 (context.applicationContext as App).appComponent } private val appComponent = DaggerAppComponent.builder()
 .application(this)
 .build() override fun applicationInjector(): AndroidInjector<out DaggerApplication> = appComponent.apply { inject(this@App) } }
  81. Base/Application 81 class App : DaggerApplication() { companion object {

    fun appComponent(context: Context) = 
 (context.applicationContext as App).appComponent } private val appComponent = DaggerAppComponent.builder()
 .application(this)
 .build() override fun applicationInjector(): AndroidInjector<out DaggerApplication> = appComponent.apply { inject(this@App) } }
  82. Feature/Component 82 @PerModuleScope @Component( dependencies = [AppComponent::class], modules = [

    AndroidSupportInjectionModule::class, FeatureOneUiBuilder::class, FeatureOneModule::class ] ) interface FeatureOneComponent : AndroidInjector<FeatureOneModuleInjector>
  83. Feature/Component 83 @PerModuleScope @Component( dependencies = [AppComponent::class], modules = [

    AndroidSupportInjectionModule::class, FeatureOneUiBuilder::class, FeatureOneModule::class ] ) interface FeatureOneComponent : AndroidInjector<FeatureOneModuleInjector>
  84. Feature/Component 84 @PerModuleScope @Component( dependencies = [AppComponent::class], modules = [

    AndroidSupportInjectionModule::class, FeatureOneUiBuilder::class, FeatureOneModule::class ] ) interface FeatureOneComponent : AndroidInjector<FeatureOneModuleInjector>
  85. Feature/FeatureModuleInjector 85 object FeatureOneModuleInjector : BaseModuleInjector() { override fun moduleInjector(appComponent:

    AppComponent): AndroidInjector<out BaseModuleInjector> { return DaggerFeatureOneComponent.builder() .appComponent(appComponent) .build() } }
  86. Feature/FeatureModuleInjector 86 object FeatureOneModuleInjector : BaseModuleInjector() { override fun moduleInjector(appComponent:

    AppComponent): AndroidInjector<out BaseModuleInjector> { return DaggerFeatureOneComponent.builder() .appComponent(appComponent) .build() } }
  87. Feature/FeatureModuleInjector 87 object FeatureOneModuleInjector : BaseModuleInjector() { override fun moduleInjector(appComponent:

    AppComponent): AndroidInjector<out BaseModuleInjector> { return DaggerFeatureOneComponent.builder() .appComponent(appComponent) .build() } }
  88. Base/BaseModuleInjector 88 abstract class BaseModuleInjector : HasActivityInjector, HasFragmentInjector,
 HasSupportFragmentInjector, HasServiceInjector,


    HasBroadcastReceiverInjector, HasContentProviderInjector { @Inject lateinit var activityInjector: DispatchingAndroidInjector<Activity> ... private var needToInject = true abstract fun moduleInjector(appComponent: AppComponent):
 AndroidInjector<out BaseModuleInjector> fun inject(dependerContext: Context) { injectIfNecessary(App.appComponent(dependerContext)) ... } private fun injectIfNecessary(appComponent: AppComponent) { ...
 } ... override fun activityInjector(): DispatchingAndroidInjector<Activity> = activityInjector ... }
  89. Base/BaseModuleInjector 89 abstract class BaseModuleInjector : HasActivityInjector, HasFragmentInjector,
 HasSupportFragmentInjector, HasServiceInjector,


    HasBroadcastReceiverInjector, HasContentProviderInjector { @Inject lateinit var activityInjector: DispatchingAndroidInjector<Activity> ... private var needToInject = true abstract fun moduleInjector(appComponent: AppComponent):
 AndroidInjector<out BaseModuleInjector> fun inject(dependerContext: Context) { injectIfNecessary(App.appComponent(dependerContext)) ... } private fun injectIfNecessary(appComponent: AppComponent) { ...
 } ... override fun activityInjector(): DispatchingAndroidInjector<Activity> = activityInjector ... }
  90. Feature/UiBuilder 90 @Module abstract class FeatureOneUiBuilder { @PerUiScope @ContributesAndroidInjector(modules =

    [RepoModule::class]) internal abstract fun bindRepoActivity(): RepoActivity }
  91. Feature/Activity 91 class RepoActivity : AbstractActivity() { @Inject lateinit var

    repoAction: RepoAction @Inject lateinit var repoStore: RepoStore
 ... override fun onCreate(savedInstanceState: Bundle?) { FeatureOneModuleInjector.inject(this) super.onCreate(savedInstanceState) setContentView(R.layout.activity_repo) } }
  92. Feature/Activity 92 class RepoActivity : AbstractActivity() { @Inject lateinit var

    repoAction: RepoAction @Inject lateinit var repoStore: RepoStore
 ... override fun onCreate(savedInstanceState: Bundle?) { FeatureOneModuleInjector.inject(this) super.onCreate(savedInstanceState) setContentView(R.layout.activity_repo) } }
  93. App structure 93 Repo PR Issue Module One Base module

    (App Scope) Repo
 List Module Two App Scope PerModule Scope PerModule Scope PerUi Scope PerUi Scope PerUi Scope PerUi Scope
  94. App structure 94 Repo PR Issue Module One Repo
 List

    Module Two App Scope PerModule Scope PerModule Scope PerUi Scope PerUi Scope PerUi Scope PerUi Scope Base module (App Scope) App Component
  95. App structure 95 PR Issue Repo
 List Module Two App

    Scope PerModule Scope PerModule Scope PerUi Scope PerUi Scope PerUi Scope PerUi Scope Base module (App Scope) App Component Repo Module One ModuleOne
 Component
 * Repo
  96. App structure 96 App Scope PerModule Scope PerModule Scope PerUi

    Scope PerUi Scope PerUi Scope PerUi Scope Base module (App Scope) App Component Repo Module One ModuleOne
 Component
 * Repo PR Issue Repo
 List Module Two ModuleTwo 
 Component
 * PR
 * Issue
 * RepoList
  97. Summary

  98. Summary • Instant Appsは
 Googleの目指すモバイルの未来 • 対応はそこまで難しくは無いが、
 4MB制限が一番大変 • Module分けしても今まで通りDaggerを


    用いてDIする事が可能 98
  99. @_a_akira AAkira Thanks