BUILD A BROWSER BY KOTLIN COLIN LEE SEBASTIAN KASPARI @colinmlee - - PowerPoint PPT Presentation

build a browser by kotlin colin lee sebastian kaspari
SMART_READER_LITE
LIVE PREVIEW

BUILD A BROWSER BY KOTLIN COLIN LEE SEBASTIAN KASPARI @colinmlee - - PowerPoint PPT Presentation

BUILD A BROWSER BY KOTLIN COLIN LEE SEBASTIAN KASPARI @colinmlee @Anti_Hype Copenhagen Denmark Feature Session Toolbar Downloads Contextmenu Customtabs Findinpage Webnotifications Reader View Search Sync Prompts Sendtab QR ...


slide-1
SLIDE 1

Copenhagen Denmark

BUILD A BROWSER BY KOTLIN COLIN LEE SEBASTIAN KASPARI

@colinmlee @Anti_Hype

slide-2
SLIDE 2 Feature Browser Concept UI Service Support Lib Session Toolbar Downloads Contextmenu Customtabs Findinpage Webnotifications Reader View Search Sync Prompts Sendtab QR ... Toolbar Engine-System Engine-Gecko Search Tabstray Menu ... Engine Toolbar Storage Fetch Push Tabstray ... Autocomplete ... ... ... State Crash ...
slide-3
SLIDE 3

Agenda

  • Why?
  • How?
  • Live code a browser!
  • Syntactic Sugar
slide-4
SLIDE 4

Why?

slide-5
SLIDE 5

Firefox for Android

slide-6
SLIDE 6

Firefox for Android Focus for Android

slide-7
SLIDE 7

Firefox for Android Focus for Android Firefox Rocket Firefox Lite

slide-8
SLIDE 8

Firefox for Android Focus for Android Firefox Rocket Firefox for Fire TV Firefox Lite

Firefox for Echo Show

slide-9
SLIDE 9

Firefox for Android Focus for Android Firefox Rocket Firefox for Fire TV Firefox Lite

Firefox for Echo Show

? ? ?

slide-10
SLIDE 10

Firefox for Android Focus for Android Firefox Rocket Firefox for Fire TV Firefox Lite

Firefox for Echo Show

? ? ?

This does not scale!

slide-11
SLIDE 11

Goals

  • Share code between our apps
  • Reduce the maintenance overhead
  • Clear architecture boundaries
  • Make it easier and faster to build new or experimental

products.

slide-12
SLIDE 12

Solution: Build independent, reusable components to share code between existing projects and build new apps faster.

slide-13
SLIDE 13

Components?

  • Independent open-source Android libraries
  • “Android First” extensible application architecture
  • Minimal cross-component and third-party dependencies
  • Customizable and pluggable
  • Distributed as AARs via a Maven repository
slide-14
SLIDE 14

Components?

100% Kotlin

slide-15
SLIDE 15

Components?

100% Kotlin Well, and some Rust

slide-16
SLIDE 16

How?

slide-17
SLIDE 17

Browser Engine

slide-18
SLIDE 18

HTML CSS JS Browser Engine

slide-19
SLIDE 19

Browser Engine

WebView GeckoView Servo ...

slide-20
SLIDE 20

GeckoView

slide-21
SLIDE 21

GeckoView

  • App developer in control of updates.

○ Only one version needs to be supported. No surprises.

  • Multiprocess
  • Separation of session (tab) and view
  • Private mode
  • WebExtensions
  • Tracking Protection
slide-22
SLIDE 22

Engine Components

concept-engine browser-engine-system browser-engine-gecko ...

slide-23
SLIDE 23

Toolbar

slide-24
SLIDE 24
slide-25
SLIDE 25

Engine Components

concept-toolbar browser-toolbar ...

slide-26
SLIDE 26
slide-27
SLIDE 27

Done?

slide-28
SLIDE 28

What else?

slide-29
SLIDE 29
slide-30
SLIDE 30
slide-31
SLIDE 31
slide-32
SLIDE 32
slide-33
SLIDE 33
slide-34
SLIDE 34

feature-downloads feature-downloads feature-media browser-awesomebar browser-contextmenu feature-readerview

slide-35
SLIDE 35

Feature Browser Concept UI Service Support Lib

Session Toolbar Downloads Contextmenu Customtabs Findinpage Webnotifications Reader View Search Sync Prompts Sendtab QR ... Toolbar Engine-System Engine-Gecko Search Tabstray Menu ... Engine Toolbar Storage Fetch Push Tabstray ... Autocomplete ... ... ... State Crash ...

slide-36
SLIDE 36

LIVE CODING

slide-37
SLIDE 37

Syntactic Sugar

Mozilla ❤ Kotlin

slide-38
SLIDE 38

null, null?, null!!

Explicit nullability

slide-39
SLIDE 39

Handling state

slide-40
SLIDE 40

lib-state

Store State

Store & State

slide-41
SLIDE 41

data classes

data class BrowserState( val tabs: List<TabSessionState> = emptyList(), val selectedTabId: String? = null, val customTabs: List<..> = emptyList(), val extensions: Map<..> = emptyMap() ) : State

Modeling State

slide-42
SLIDE 42

lib-state

Store State Component / App

  • bserves

State

Observing state

slide-43
SLIDE 43

lib-state

@CheckResult(suggest = "observe") @Synchronized fun observeManually(

  • bserver: Observer<S>

): Subscription<S, A> { // .. } Observing state

slide-44
SLIDE 44

lib-state

Observing state

val subscription = store.observeManually { state -> // .. } subscription.unsubscribe()

slide-45
SLIDE 45

Extension functions

@MainThread fun <..> Store<S, A>.observe(

  • wner: LifecycleOwner,
  • bserver: Observer<S>

) { // .. } Iterating on API

slide-46
SLIDE 46

Extension functions

@MainThread fun <..> Store<S, A>.observe( view: View,

  • bserver: Observer<S>

) { // .. } Iterating on API

slide-47
SLIDE 47

lib-state

Store State Component / App

  • bserves

State dispatches Action

Dispatching actions

slide-48
SLIDE 48

Sealed classes

sealed class TabListAction : BrowserAction() { data class AddTabAction( val tab: TabSessionState, val select: Boolean = false ) : TabListAction() data class SelectTabAction( val tabId: String ) : TabListAction() // .. }

Modeling Actions

slide-49
SLIDE 49

lib-state

Store Reducer State Action

Inside the store

State

slide-50
SLIDE 50

Functions & Sealed classes

Reducing state

fun reduce( state: BrowserState, action: TabListAction ): BrowserState { return when (action) { is TabListAction.AddTabAction -> { .. } is TabListAction.SelectTabAction -> { .. } // .. } }

slide-51
SLIDE 51

data classes

Creating a new state val newState = state.copy( selectedTabId = "some-other-tab" )

slide-52
SLIDE 52

Type aliases

Observing state typealias Observer<S> = (S) -> Unit typealias Reducer<S, A> = (S, A) -> S

slide-53
SLIDE 53

Channels & Flow

slide-54
SLIDE 54

Channel

@ExperimentalCoroutinesApi @MainThread fun <..> Store<S, A>.channel(

  • wner: LifecycleOwner = ProcessLifecycleOwner.get()

): ReceiveChannel<S> { // .. }

Observing state sequentially

slide-55
SLIDE 55

Flow

@ExperimentalCoroutinesApi @MainThread fun <..> Store<S, A>.flow(

  • wner: LifecycleOwner? = null

): Flow<S> { // .. } Observing state

slide-56
SLIDE 56

“Scoped flow”

@ExperimentalCoroutinesApi @MainThread fun <..> Store<S, A>.flowScoped(

  • wner: LifecycleOwner? = null,

block: suspend (Flow<S>) -> Unit ): CoroutineScope { // .. } Observing state

slide-57
SLIDE 57

Operators for dealing with state updates

slide-58
SLIDE 58

Flow operators

fun <T> Flow<T>.ifChanged(): Flow<T> Only update UI if the state has changed

store .flow() .map { state -> state.selectedTab.title } .ifChanged() .collect { title -> // .. }

slide-59
SLIDE 59

Flow operators

fun <T, R> Flow<T>.ifChanged( transform: (T) -> R ): Flow<T> Only update UI if state changed partially

store .flow() .ifChanged { state -> state.selectedTab.title } .collect { state -> // .. }

slide-60
SLIDE 60

Flow operators

fun <T, R> Flow<List<T>>.filterChanged( transform: (T) -> R ): Flow<T> store .flow() .map { state -> state.tabs } .filterChanged { tab -> tab.title } .collect { tab -> // .. }

slide-61
SLIDE 61

https://mozac.org https://mozilla.github.io/geckoview https://mozilla.github.io/application-services/ https://github.com/mozilla-mobile/

slide-62
SLIDE 62

#KotlinConf

THANK YOU AND REMEMBER TO VOTE

Colin Lee @colinmlee Sebastian Kaspari @Anti_Hype