SlideShare a Scribd company logo
DEVELOPMENT
1
Kotlin Multiplatform in Action
Alexandr Pogrebnyak
Droidcon Tel Aviv
19.12.19.
DEVELOPMENT
โ— About us
โ— What is Kotlin Multiplatform?
โ— Our experience in Kotlin Multiplatform
โ— moko.icerock.dev โ€“ a set of multiplatform libraries
โ— moko-widgets
2
DEVELOPMENT
โ— 5 years in mobile development
โ— 80+ mobile projects (iOS & Android)
โ— 40+ developers in 2 offices
3
DEVELOPMENT
Focus on:
4
Avoid logic reduplication and
keep UI native
DEVELOPMENT
5
Code Sharing in IceRock
Flutter
React Native
J2ObjC
New programming language
Integration with OS via middle layer
Non-native UI
Legacy tech stacks
Asynchronous work with OS
Need to adopt Java-code to ObjC
Native UI
Hot reload
DEVELOPMENT
6
Kotlin Multiplatform
+
Kotlin/Native
Code Sharing at IceRock
Kotlin looks like Swift
Inner libraries already in Kotlin
Shift to native env at any moment
Familiar programming language
Native UI
Full access to Android OS and iOS features
and SDKs
There are some limitations in Kotlin > Swift direction
Devs worry about integration
DEVELOPMENT
7
Kotlin Multiplatform at IceRock
Kotlin MPP and Kotlin/Native since July 2018
1 year achievement
Reduce time and cost for both platforms by 1.5x
1.5x speed
50% of shared code on average
50:50
Easy learning curve for Android and iOS developers
Easy to learn, hard to master
DEVELOPMENT
8
Kotlin Multiplatform
Android Windows macOS Linux Java Java Script WebAssemblyiOS
DEVELOPMENT
9
expect class Logger(tag: String) {
fun log(string: String)
}
fun main() {
val logger = Logger("MPP")
logger.log("hello world!")
}
commonMain
DEVELOPMENT
10
iosMain
import platform.Foundation.NSLog
actual class Logger actual constructor(private val
tag: String) {
actual fun log(string: String) {
NSLog("[$tag] $string")
}
}
import android.util.Log
actual class Logger actual constructor(private val
tag: String) {
actual fun log(string: String) {
Log.v(tag, string)
}
}
androidMain
DEVELOPMENT
11
androidMain
โ””โ”€โ”€ kotlin
โ””โ”€โ”€ com.icerockdev.library
โ””โ”€โ”€ Logger.kt
commonMain
โ””โ”€โ”€ kotlin
โ””โ”€โ”€ com.icerockdev.library
โ””โ”€โ”€ Logger.kt
iosMain
โ””โ”€โ”€ kotlin
โ””โ”€โ”€ com.icerockdev.library
โ””โ”€โ”€ Logger.kt
Kotlin Multiplatform
DEVELOPMENT
12
Kotlin Multiplatform - past
View
AuthActivity AuthViewController Pro๏ฌleViewController Pro๏ฌleActivity
Presentation
AuthViewModel Pro๏ฌleViewModel PostsViewModel AddPostViewModel
Domain
UserInteractor PostsInteractor Validator Payment
Data
User Post UserRepository PostRepository
RestUser RestPost UserApi PostApi
DEVELOPMENT
13
Kotlin Multiplatform - now
View
AuthScreen Pro๏ฌleScreen
Presentation
AuthViewModel Pro๏ฌleViewModel PostsViewModel
Domain
UserInteractor PostsInteractor Validator
Data
User Post UserRepository
RestUser RestPost UserApi
powered by
DEVELOPMENT
14
Shared Code in a Typical Project - past
Shared code
62%
Android-speci๏ฌc
16%
iOS-speci๏ฌc
22%
DEVELOPMENT
15
Shared Code in a Typical Project - now
Android-speci๏ฌc
3%
iOS-speci๏ฌc
2%
Shared code
95%
powered by
DEVELOPMENT
16
moko.icerock.dev
Community
DEVELOPMENT
17moko.icerock.dev
DEVELOPMENT
18moko.icerock.dev
DEVELOPMENT
19
Fast start
github.com/icerockdev/moko-template
codelabs.kmp.icerock.dev
DEVELOPMENT
20
Result
DEVELOPMENT
21
A moko-template (sample project)
https://github.com/icerockdev/moko-template.git
Features:
Install:
git clone Done!
app_name
app_icon
applicationId
โ— Shared business logic
โ— Kotlin Gradle DSL
โ— Modular-based architecture
โ— Independent feature and domain modules
โ— ViewModels, LiveData, Resource management, Runtime permissions access,
Media access, UI from shared code, Network layer generation from OpenAPIโ€ฆ
DEVELOPMENT
22
github.com/icerockdev/moko-template
widgets branch
DEVELOPMENT
Goal #1
1 Kotlin developer => 2 native mobile apps
23
goals
DEVELOPMENT
Goal #2
Fast start = the codebase should grow without
rewrites
24
goals
DEVELOPMENT
The basic architecture concepts:
1. compliance with platform rules
2. declare structure, not rendering
3. compile-time safety
4. reactive data handling
25
concepts
DEVELOPMENT
26
code
class App : BaseApplication() {
override fun setup() {
val theme = Theme()
registerScreenFactory(MainScreen::class) { MainScreen(theme) }
}
override fun getRootScreen(): KClass<out Screen<Args.Empty>> {
return MainScreen::class
}
}
common
DEVELOPMENT
27
code
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
mppApplication = App().apply {
setup()
}
}
companion object {
lateinit var mppApplication: App
}
}
class MainActivity : HostActivity() {
override val application: BaseApplication
get() = MainApplication.mppApplication
}
android
DEVELOPMENT
28
code
@UIApplicationMain
class AppDelegate: NSObject, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: ..., didFinishLaunchingWithOptions ...) -> Bool {
let app = App()
app.setup()
let screen = app.createRootScreen()
let rootViewController = screen.createViewController()
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = rootViewController
window?.makeKeyAndVisible()
return true
}
}
ios
DEVELOPMENT
29
code
class MainScreen(
private val theme: Theme
) : WidgetScreen<Args.Empty>() {
override fun createContentWidget() = with(theme) {
container(size = WidgetSize.AsParent) {
center {
text(
size = WidgetSize.WrapContent,
text = const(MR.strings.hello_world.desc())
)
}
}
}
}
common
DEVELOPMENT
30
code
class MainScreen(
private val theme: Theme
) : WidgetScreen<Args.Empty>() {
override fun createContentWidget() = with(theme) {
container(size = WidgetSize.AsParent) {
center {
text(
size = WidgetSize.WrapContent,
text = const(MR.strings.hello_world.desc())
)
}
}
}
}
common
DEVELOPMENT
31
code
class MainScreen(
private val theme: Theme
) : WidgetScreen<Args.Empty>() {
override fun createContentWidget() = with(theme) {
container(size = WidgetSize.AsParent) {
center {
text(
size = WidgetSize.WrapContent,
text = const(MR.strings.hello_world.desc())
)
}
}
}
}
common
DEVELOPMENT
32
code
class MainScreen(
private val theme: Theme
) : WidgetScreen<Args.Empty>() {
override fun createContentWidget() = with(theme) {
container(size = WidgetSize.AsParent) {
center {
text(
size = WidgetSize.WrapContent,
text = const(MR.strings.hello_world.desc())
)
}
}
}
}
common
DEVELOPMENT
33
code
class MainScreen(
private val theme: Theme
) : WidgetScreen<Args.Empty>() {
override fun createContentWidget() = with(theme) {
container(size = WidgetSize.AsParent) {
center {
text(
size = WidgetSize.WrapContent,
text = const(MR.strings.hello_world.desc())
)
}
}
}
}
common
DEVELOPMENT
34
code
class MainScreen(
private val theme: Theme
) : WidgetScreen<Args.Empty>() {
override fun createContentWidget() = with(theme) {
container(size = WidgetSize.AsParent) {
center {
text(
size = WidgetSize.WrapContent,
text = const(MR.strings.hello_world.desc())
)
}
}
}
}
common
DEVELOPMENT
35
code
DEVELOPMENT
36
code
class App : BaseApplication() {
override fun setup() {
val theme = Theme {
// custom styles here
}
registerScreenFactory(MainScreen::class) { MainScreen(theme) }
}
override fun getRootScreen(): KClass<out Screen<Args.Empty>> {
return MainScreen::class
}
}
common
DEVELOPMENT
37
code
val theme = Theme {
textFactory = DefaultTextWidgetViewFactory(
DefaultTextWidgetViewFactoryBase.Style(
textStyle = TextStyle(
size = 24,
color = Colors.black
),
padding = PaddingValues(padding = 16f)
)
)
}
common
DEVELOPMENT
38
code
val theme = Theme {
textFactory = DefaultTextWidgetViewFactory(
DefaultTextWidgetViewFactoryBase.Style(
textStyle = TextStyle(
size = 24,
color = Colors.black
),
padding = PaddingValues(padding = 16f)
)
)
}
common
DEVELOPMENT
39
code
val theme = Theme {
textFactory = DefaultTextWidgetViewFactory(
DefaultTextWidgetViewFactoryBase.Style(
textStyle = TextStyle(
size = 24,
color = Colors.black
),
padding = PaddingValues(padding = 16f)
)
)
}
common
DEVELOPMENT
40
code
DEVELOPMENT
Simple is simple.
How about some complexity?
41
code
DEVELOPMENT
42
code
DEVELOPMENT
43
code
image center
between
2 ๏ฌelds and a button
in the center
DEVELOPMENT
44
code
class LoginScreen(
private val theme: Theme
) : WidgetScreen<Args.Empty>() {
override fun createContentWidget() = with(theme) {
constraint(size = WidgetSize.AsParent) {
// ...
}
}
}
common
DEVELOPMENT
45
code
override fun createContentWidget() = with(theme) {
constraint(size = WidgetSize.AsParent) {
val logoImage = +image(
size = WidgetSize.Const(SizeSpec.WrapContent, SizeSpec.WrapContent),
image = const(Image.resource(MR.images.logo))
)
}
}
common
DEVELOPMENT
46
code
constraint(size = WidgetSize.AsParent) {
val logoImage = +image(...)
val emailInput = +input(
size = WidgetSize.WidthAsParentHeightWrapContent,
id = Id.EmailInputId,
label = const("Email".desc() as StringDesc),
field = viewModel.emailField
)
val passwordInput = +input(
size = WidgetSize.WidthAsParentHeightWrapContent,
id = Id.PasswordInputId,
label = const("Password".desc() as StringDesc),
field = viewModel.passwordField
)
}
common
DEVELOPMENT
47
code
constraint(size = WidgetSize.AsParent) {
val logoImage = +image(...)
val emailInput = +input(...)
val passwordInput = +input(...)
val loginButton = +button(
size = WidgetSize.Const(SizeSpec.AsParent, SizeSpec.Exact(50f)),
text = const("Login".desc() as StringDesc),
onTap = viewModel::onLoginPressed
)
}
common
DEVELOPMENT
48
code
constraint(size = WidgetSize.AsParent) {
val logoImage = +image(...)
val emailInput = +input(...)
val passwordInput = +input(...)
val loginButton = +button(...)
constraints {
passwordInput centerYToCenterY root
passwordInput leftRightToLeftRight root
emailInput bottomToTop passwordInput
emailInput leftRightToLeftRight root
loginButton topToBottom passwordInput
loginButton leftRightToLeftRight root
logoImage centerXToCenterX root
logoImage.verticalCenterBetween(
top = root.top,
bottom = emailInput.top
)
}
common
DEVELOPMENT
49
code
constraint(size = WidgetSize.AsParent) {
val logoImage = +image(...)
val emailInput = +input(...)
val passwordInput = +input(...)
val loginButton = +button(...)
constraints {
passwordInput centerYToCenterY root
passwordInput leftRightToLeftRight root
emailInput bottomToTop passwordInput
emailInput leftRightToLeftRight root
loginButton topToBottom passwordInput
loginButton leftRightToLeftRight root
logoImage centerXToCenterX root
logoImage.verticalCenterBetween(
top = root.top,
bottom = emailInput.top
)
}
common
DEVELOPMENT
50
code
constraint(size = WidgetSize.AsParent) {
val logoImage = +image(...)
val emailInput = +input(...)
val passwordInput = +input(...)
val loginButton = +button(...)
constraints {
passwordInput centerYToCenterY root
passwordInput leftRightToLeftRight root
emailInput bottomToTop passwordInput
emailInput leftRightToLeftRight root
loginButton topToBottom passwordInput
loginButton leftRightToLeftRight root
logoImage centerXToCenterX root
logoImage.verticalCenterBetween(
top = root.top,
bottom = emailInput.top
)
}
common
DEVELOPMENT
51
code
constraint(size = WidgetSize.AsParent) {
val logoImage = +image(...)
val emailInput = +input(...)
val passwordInput = +input(...)
val loginButton = +button(...)
constraints {
passwordInput centerYToCenterY root
passwordInput leftRightToLeftRight root
emailInput bottomToTop passwordInput
emailInput leftRightToLeftRight root
loginButton topToBottom passwordInput
loginButton leftRightToLeftRight root
logoImage centerXToCenterX root
logoImage.verticalCenterBetween(
top = root.top,
bottom = emailInput.top
)
}
common
DEVELOPMENT
52
code
DEVELOPMENT
53
code
DEVELOPMENT
54
code
val loginTheme = Theme(theme) {
constraintFactory = DefaultConstraintWidgetViewFactory(
DefaultConstraintWidgetViewFactoryBase.Style(
padding = PaddingValues(16f),
background = Background(
fill = Fill.Solid(Colors.white)
)
)
)
}
common
DEVELOPMENT
55
code
val loginTheme = Theme(theme) {
constraintFactory = DefaultConstraintWidgetViewFactory(...)
imageFactory = DefaultImageWidgetViewFactory(
DefaultImageWidgetViewFactoryBase.Style(
scaleType = DefaultImageWidgetViewFactoryBase.ScaleType.FIT
)
)
}
common
DEVELOPMENT
56
code
val loginTheme = Theme(theme) {
constraintFactory = DefaultConstraintWidgetViewFactory(...)
imageFactory = DefaultImageWidgetViewFactory(...)
val corners = platformSpecific(android = 8f, ios = 25f)
inputFactory = DefaultInputWidgetViewFactory(
DefaultInputWidgetViewFactoryBase.Style(
margins = MarginValues(bottom = 8f),
underLineColor = Color(0xe5e6eeFF),
labelTextStyle = TextStyle(
color = Color(0x777889FF)
)
)
)
}
common
DEVELOPMENT
57
code
val loginTheme = Theme(theme) {
constraintFactory = DefaultConstraintWidgetViewFactory(...)
imageFactory = DefaultImageWidgetViewFactory(...)
val corners = platformSpecific(android = 16f, ios = 25f)
inputFactory = DefaultInputWidgetViewFactory(
DefaultInputWidgetViewFactoryBase.Style(
margins = MarginValues(bottom = 8f),
underLineColor = Color(0xe5e6eeFF),
labelTextStyle = TextStyle(
color = Color(0x777889FF)
)
)
)
}
common
DEVELOPMENT
58
code
val loginTheme = Theme(theme) {
constraintFactory = DefaultConstraintWidgetViewFactory(...)
imageFactory = DefaultImageWidgetViewFactory(...)
val corners = ...
inputFactory = DefaultInputWidgetViewFactory(...)
buttonFactory = DefaultButtonWidgetViewFactory(
DefaultButtonWidgetViewFactoryBase.Style(
margins = MarginValues(top = 32f),
background = StateBackground(
normal = Background(
fill = Fill.Solid(Color(0x6770e0FF)),
shape = Shape.Rectangle(cornerRadius = corners)
),
pressed = Background(...),
disabled = Background(...)
),
textStyle = TextStyle(color = Colors.white)
)
)
}
common
DEVELOPMENT
59
code
DEVELOPMENT
60
code
how add different
button?
DEVELOPMENT
61
code
constraint(size = WidgetSize.AsParent) {
val logoImage = +image(...)
val emailInput = +input(...)
val passwordInput = +input(...)
val loginButton = +button(...)
val registerButton = +button(
id = Id.RegistrationButtonId,
size = WidgetSize.Const(SizeSpec.WrapContent, SizeSpec.Exact(40f)),
text = const("Registration".desc() as StringDesc),
onTap = viewModel::onRegistrationPressed
)
constraints {
// ...
registerButton topToBottom loginButton
registerButton rightToRight root
}
}
DEVELOPMENT
62
code
constraint(size = WidgetSize.AsParent) {
val logoImage = +image(...)
val emailInput = +input(...)
val passwordInput = +input(...)
val loginButton = +button(...)
val registerButton = +button(
id = Id.RegistrationButtonId,
size = WidgetSize.Const(SizeSpec.WrapContent, SizeSpec.Exact(40f)),
text = const("Registration".desc() as StringDesc),
onTap = viewModel::onRegistrationPressed
)
constraints {
// ...
registerButton topToBottom loginButton
registerButton rightToRight root
}
}
DEVELOPMENT
63
code
class LoginScreen(...) : WidgetScreen<Args.Empty>() {
override fun createContentWidget() = ...
object Id {
...
object RegisterButtonId : ButtonWidget.Id
}
}
DEVELOPMENT
64
code
val loginTheme = Theme(theme) {
// โ€ฆ
setButtonFactory(
DefaultButtonWidgetViewFactory(
DefaultButtonWidgetViewFactoryBase.Style(
// ...
)
),
LoginScreen.Id.RegistrationButtonId
)
}
common
DEVELOPMENT
65
code
DefaultButtonWidgetViewFactoryBase.Style(
margins = MarginValues(top = 16f),
padding = platformSpecific(
ios = PaddingValues(start = 16f, end = 16f),
android = null
),
background = StateBackground(
normal = Background(
fill = Fill.Solid(Colors.white),
border = Border(
color = Color(0xF2F2F8FF),
width = 2f
),
shape = Shape.Rectangle(cornerRadius = corners)
),
pressed = Background(...),
disabled = Background(...)
),
textStyle = TextStyle(color = Color(0x777889FF))
)
common
DEVELOPMENT
66
code
DefaultButtonWidgetViewFactoryBase.Style(
margins = MarginValues(top = 16f),
padding = platformSpecific(
ios = PaddingValues(start = 16f, end = 16f),
android = null
),
background = StateBackground(
normal = Background(
fill = Fill.Solid(Colors.white),
border = Border(
color = Color(0xF2F2F8FF),
width = 2f
),
shape = Shape.Rectangle(cornerRadius = corners)
),
pressed = Background(...),
disabled = Background(...)
),
textStyle = TextStyle(color = Color(0x777889FF))
)
common
DEVELOPMENT
67
code
DefaultButtonWidgetViewFactoryBase.Style(
margins = MarginValues(top = 16f),
padding = platformSpecific(
ios = PaddingValues(start = 16f, end = 16f),
android = null
),
background = StateBackground(
normal = Background(
fill = Fill.Solid(Colors.white),
border = Border(
color = Color(0xF2F2F8FF),
width = 2f
),
shape = Shape.Rectangle(cornerRadius = corners)
),
pressed = Background(...),
disabled = Background(...)
),
textStyle = TextStyle(color = Color(0x777889FF))
)
common
DEVELOPMENT
68
code
DefaultButtonWidgetViewFactoryBase.Style(
margins = MarginValues(top = 16f),
padding = platformSpecific(
ios = PaddingValues(start = 16f, end = 16f),
android = null
),
background = StateBackground(
normal = Background(
fill = Fill.Solid(Colors.white),
border = Border(
color = Color(0xF2F2F8FF),
width = 2f
),
shape = Shape.Rectangle(cornerRadius = corners)
),
pressed = Background(...),
disabled = Background(...)
),
textStyle = TextStyle(color = Color(0x777889FF))
)
common
DEVELOPMENT
69
code
DEVELOPMENT
Multiple screens?
70
code
DEVELOPMENT
71
results
DEVELOPMENT
72
results
DEVELOPMENT
73
results
DEVELOPMENT
Lists?
74
code
DEVELOPMENT
75
results
DEVELOPMENT
The basic architecture concepts:
1. compliance with platform rules
2. declare structure, not rendering
3. compile-time safety
4. reactive data handling
76
concepts
DEVELOPMENT
77
concepts
Compliance with platform rules:
1. Activity recreation on Android
2. Save instance state on Android
3. All elements are native (UI/UX)
DEVELOPMENT
78
concepts
Declare structure, not rendering
DEVELOPMENT
Compile-time safety:
1. Type match of WidgetFactory and Widget
2. Child Widgets sizes compile-time checks
3. Widgets Id match to Widget type
4. Arguments in Screens
79
concepts
DEVELOPMENT
80
concepts
Type match of WidgetFactory and Widget
val theme = Theme {
textFactory = DefaultTextWidgetViewFactory()
}
val theme = Theme {
textFactory = DefaultContainerWidgetViewFactory()
}
DEVELOPMENT
81
concepts
Child Widgets sizes compile-time checks
override fun createContentWidget() = with(theme) {
container(size = WidgetSize.AsParent) {
}
}
override fun createContentWidget() = with(theme) {
container(size = WidgetSize.WrapContent) {
}
}
DEVELOPMENT
82
concepts
Child Widgets sizes compile-time checks
fun createContentWidget(): Widget<WidgetSize.Const<SizeSpec.AsParent,
SizeSpec.AsParent>>
DEVELOPMENT
83
concepts
Widgets Id match to Widget type
setContainerFactory(
DefaultContainerWidgetViewFactory(),
RootContainerId
)
setTextFactory(
DefaultTextWidgetViewFactory(),
RootContainerId
)
object RootContainerId: ContainerWidget.Id
DEVELOPMENT
84
concepts
Arguments in Screens
routeToScreen(NoArgsScreen::class)
class NoArgsScreen : WidgetScreen<Args.Empty>()
DEVELOPMENT
85
concepts
Arguments in Screens
routeToScreen(ArgsScreen::class, ArgsScreen.Arg(10))
routeToScreen(ArgsScreen::class)
class ArgsScreen : WidgetScreen<Args.Parcel<ArgsScreen.Arg>>()
DEVELOPMENT
Reactive data handling:
1. One-way binding via LiveData
2. Two-way binding via MutableLiveData
86
concepts
DEVELOPMENT
87
concepts
One-way binding via LiveData
class TimerViewModel : ViewModel() {
val text: LiveData<StringDesc>
}
val viewModel = getViewModel { TimerViewModel() }
container(size = WidgetSize.AsParent) {
center {
text(size = WidgetSize.WrapContent, text = viewModel.text)
}
}
DEVELOPMENT
88
concepts
Two-way binding via MutableLiveData
class InputViewModel : ViewModel() {
val nameField: FormField<String, StringDesc> = FormField("")
}
val viewModel = getViewModel { InputViewModel() }
input(
size = WidgetSize.WidthAsParentHeightWrapContent,
id = Id.NameInput,
label = const(MR.strings.name_label.desc()),
field = viewModel.nameField
)
DEVELOPMENT
89
concepts
Two-way binding via MutableLiveData
class FormField<D, E> {
val data: MutableLiveData<D>
val error: LiveData<E?>
val isValid: LiveData<Boolean>
}
DEVELOPMENT
90
current list of widgets
with(theme) {
constraint(...)
container(...)
linear(...)
scroll(...)
stateful(...)
tabs(...)
clickable(...)
image(...)
text(...)
input(...)
button(...)
list(...)
collection(...)
flatAlert(...)
progressBar(...)
singleChoice(...)
switch(...)
}
DEVELOPMENT
91
current list of widgets
public abstract class Widget<WS : WidgetSize> public constructor() {
public abstract val size: WS
public abstract fun buildView(viewFactoryContext: ViewFactoryContext): ViewBundle<WS>
}
public interface ViewFactory<W : Widget<out WidgetSize>> {
public abstract fun <WS : WidgetSize> build(widget: W, size: WS,
viewFactoryContext: ViewFactoryContext): ViewBundle<WS>
}
DEVELOPMENT
โ— Widgets declare screens and structure of screens,
but rendering is native
โ— Jetpack Compose & SwiftUI can be used to render
widgets
92
references
DEVELOPMENT
โ— 1 kotlin developer can create for both platforms
โ— natively for developer and customer
โ— no limits with any modi๏ฌcations (feature, screen, โ€ฆ)
โ— MVP quickly โ‰  must redo natively in the future
93
bene๏ฌts
DEVELOPMENT
Whatโ€™s available today (December, 19):
โ— Base widgets set
โ— Base navigation patterns
โ— Base styles for default widget-views
โ— A set of samples
โ— Actual version โ€“ 0.1.0-dev-5
94
roadmap
DEVELOPMENT
95
December-January:
โ— Implement in production project
โ— Check ๏ฌ‚exibility of API to detect and ๏ฌx limits โ€“ you
can help with it.
Just try self and send feedback to github issues
โ— Screens actions API design (show toast, alert, route)
โ— More documentation and samples
roadmap
DEVELOPMENT
February-March:
โ— Release 0.1.0 (with ๏ฌ‚exible API for customization)
โ— Codelabs and Medium posts with details of new
version
96
roadmap
DEVELOPMENT
2020 Q2-Q3:
โ— New widgets
โ— More variations of widgets renders
โ— More styles
โ— Production usage
97
roadmap
DEVELOPMENT
98
ap@icerock.dev
Try MOKO widgets today =>
@kotlinmpp github/icerockdev
Ad

More Related Content

What's hot (20)

Webkit/chromium contribution process
Webkit/chromium contribution processWebkit/chromium contribution process
Webkit/chromium contribution process
NAVER LABS
ย 
Dependencies Managers in C/C++. Using stdcpp 2014
Dependencies Managers in C/C++. Using stdcpp 2014Dependencies Managers in C/C++. Using stdcpp 2014
Dependencies Managers in C/C++. Using stdcpp 2014
biicode
ย 
Build a lego app with CocoaPods
Build a lego app with CocoaPodsBuild a lego app with CocoaPods
Build a lego app with CocoaPods
CocoaHeads France
ย 
Deployment Automation with Docker
Deployment Automation with DockerDeployment Automation with Docker
Deployment Automation with Docker
Egor Pushkin
ย 
Operator Framework Overview
Operator Framework OverviewOperator Framework Overview
Operator Framework Overview
Rob Szumski
ย 
SPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo Omura
SPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo OmuraSPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo Omura
SPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo Omura
Preferred Networks
ย 
Kubernetes - from sketch to production
Kubernetes - from sketch to productionKubernetes - from sketch to production
Kubernetes - from sketch to production
Sergio Shevchenko
ย 
Console Apps: php artisan forthe:win
Console Apps: php artisan forthe:winConsole Apps: php artisan forthe:win
Console Apps: php artisan forthe:win
Joe Ferguson
ย 
React Ecosystem
React EcosystemReact Ecosystem
React Ecosystem
Craig Jolicoeur
ย 
Concourse CI Meetup Demo
Concourse CI Meetup DemoConcourse CI Meetup Demo
Concourse CI Meetup Demo
Toshiaki Maki
ย 
Google io extended '17 ์ธ์ฒœ
Google io extended '17 ์ธ์ฒœGoogle io extended '17 ์ธ์ฒœ
Google io extended '17 ์ธ์ฒœ
Pluu love
ย 
Kubernetes Operators: Rob Szumski
Kubernetes Operators: Rob SzumskiKubernetes Operators: Rob Szumski
Kubernetes Operators: Rob Szumski
Redis Labs
ย 
Griffon: Re-imaging Desktop Java Technology
Griffon: Re-imaging Desktop Java TechnologyGriffon: Re-imaging Desktop Java Technology
Griffon: Re-imaging Desktop Java Technology
James Williams
ย 
Php Dependency Management with Composer ZendCon 2016
Php Dependency Management with Composer ZendCon 2016Php Dependency Management with Composer ZendCon 2016
Php Dependency Management with Composer ZendCon 2016
Clark Everetts
ย 
Dockerfiles building docker images automatically v (workdir, env, add, and ...
Dockerfiles   building docker images automatically v (workdir, env, add, and ...Dockerfiles   building docker images automatically v (workdir, env, add, and ...
Dockerfiles building docker images automatically v (workdir, env, add, and ...
ansonjonel
ย 
Composer
ComposerComposer
Composer
Federico Damiรกn Lozada Mosto
ย 
Introduction to Flutter - truly crossplatform, amazingly fast
Introduction to Flutter - truly crossplatform, amazingly fastIntroduction to Flutter - truly crossplatform, amazingly fast
Introduction to Flutter - truly crossplatform, amazingly fast
Bartosz Kosarzycki
ย 
Cross-Platform App Development with Flutter, Xamarin, React Native
Cross-Platform App Development with Flutter, Xamarin, React NativeCross-Platform App Development with Flutter, Xamarin, React Native
Cross-Platform App Development with Flutter, Xamarin, React Native
Korhan Bircan
ย 
Automating stateful applications with kubernetes operators - Openstack Summit...
Automating stateful applications with kubernetes operators - Openstack Summit...Automating stateful applications with kubernetes operators - Openstack Summit...
Automating stateful applications with kubernetes operators - Openstack Summit...
Jorge Morales
ย 
Pc54
Pc54Pc54
Pc54
guestd9aa5
ย 
Webkit/chromium contribution process
Webkit/chromium contribution processWebkit/chromium contribution process
Webkit/chromium contribution process
NAVER LABS
ย 
Dependencies Managers in C/C++. Using stdcpp 2014
Dependencies Managers in C/C++. Using stdcpp 2014Dependencies Managers in C/C++. Using stdcpp 2014
Dependencies Managers in C/C++. Using stdcpp 2014
biicode
ย 
Build a lego app with CocoaPods
Build a lego app with CocoaPodsBuild a lego app with CocoaPods
Build a lego app with CocoaPods
CocoaHeads France
ย 
Deployment Automation with Docker
Deployment Automation with DockerDeployment Automation with Docker
Deployment Automation with Docker
Egor Pushkin
ย 
Operator Framework Overview
Operator Framework OverviewOperator Framework Overview
Operator Framework Overview
Rob Szumski
ย 
SPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo Omura
SPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo OmuraSPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo Omura
SPIFFE Meetup Tokyo #2 - Attestation Internals in SPIRE - Shingo Omura
Preferred Networks
ย 
Kubernetes - from sketch to production
Kubernetes - from sketch to productionKubernetes - from sketch to production
Kubernetes - from sketch to production
Sergio Shevchenko
ย 
Console Apps: php artisan forthe:win
Console Apps: php artisan forthe:winConsole Apps: php artisan forthe:win
Console Apps: php artisan forthe:win
Joe Ferguson
ย 
React Ecosystem
React EcosystemReact Ecosystem
React Ecosystem
Craig Jolicoeur
ย 
Concourse CI Meetup Demo
Concourse CI Meetup DemoConcourse CI Meetup Demo
Concourse CI Meetup Demo
Toshiaki Maki
ย 
Google io extended '17 ์ธ์ฒœ
Google io extended '17 ์ธ์ฒœGoogle io extended '17 ์ธ์ฒœ
Google io extended '17 ์ธ์ฒœ
Pluu love
ย 
Kubernetes Operators: Rob Szumski
Kubernetes Operators: Rob SzumskiKubernetes Operators: Rob Szumski
Kubernetes Operators: Rob Szumski
Redis Labs
ย 
Griffon: Re-imaging Desktop Java Technology
Griffon: Re-imaging Desktop Java TechnologyGriffon: Re-imaging Desktop Java Technology
Griffon: Re-imaging Desktop Java Technology
James Williams
ย 
Php Dependency Management with Composer ZendCon 2016
Php Dependency Management with Composer ZendCon 2016Php Dependency Management with Composer ZendCon 2016
Php Dependency Management with Composer ZendCon 2016
Clark Everetts
ย 
Dockerfiles building docker images automatically v (workdir, env, add, and ...
Dockerfiles   building docker images automatically v (workdir, env, add, and ...Dockerfiles   building docker images automatically v (workdir, env, add, and ...
Dockerfiles building docker images automatically v (workdir, env, add, and ...
ansonjonel
ย 
Introduction to Flutter - truly crossplatform, amazingly fast
Introduction to Flutter - truly crossplatform, amazingly fastIntroduction to Flutter - truly crossplatform, amazingly fast
Introduction to Flutter - truly crossplatform, amazingly fast
Bartosz Kosarzycki
ย 
Cross-Platform App Development with Flutter, Xamarin, React Native
Cross-Platform App Development with Flutter, Xamarin, React NativeCross-Platform App Development with Flutter, Xamarin, React Native
Cross-Platform App Development with Flutter, Xamarin, React Native
Korhan Bircan
ย 
Automating stateful applications with kubernetes operators - Openstack Summit...
Automating stateful applications with kubernetes operators - Openstack Summit...Automating stateful applications with kubernetes operators - Openstack Summit...
Automating stateful applications with kubernetes operators - Openstack Summit...
Jorge Morales
ย 

Similar to Kotlin Multiplatform in Action - Alexandr Pogrebnyak - IceRockDev (20)

Intro to Eclipse Che, by Tyler Jewell
Intro to Eclipse Che, by Tyler JewellIntro to Eclipse Che, by Tyler Jewell
Intro to Eclipse Che, by Tyler Jewell
jwi11iams
ย 
FooConf23_Bringing the cloud back down to earth.pptx
FooConf23_Bringing the cloud back down to earth.pptxFooConf23_Bringing the cloud back down to earth.pptx
FooConf23_Bringing the cloud back down to earth.pptx
Grace Jansen
ย 
Mobile Web Apps and the Intelยฎ XDK
Mobile Web Apps and the Intelยฎ XDKMobile Web Apps and the Intelยฎ XDK
Mobile Web Apps and the Intelยฎ XDK
Intelยฎ Software
ย 
Comment dรฉvelopper une application mobile en 8 semaines - Meetup PAUG 24-01-2023
Comment dรฉvelopper une application mobile en 8 semaines - Meetup PAUG 24-01-2023Comment dรฉvelopper une application mobile en 8 semaines - Meetup PAUG 24-01-2023
Comment dรฉvelopper une application mobile en 8 semaines - Meetup PAUG 24-01-2023
Nicolas HAAN
ย 
Jfokus_Bringing the cloud back down to earth.pptx
Jfokus_Bringing the cloud back down to earth.pptxJfokus_Bringing the cloud back down to earth.pptx
Jfokus_Bringing the cloud back down to earth.pptx
Grace Jansen
ย 
SwissJUG_Bringing the cloud back down to earth.pptx
SwissJUG_Bringing the cloud back down to earth.pptxSwissJUG_Bringing the cloud back down to earth.pptx
SwissJUG_Bringing the cloud back down to earth.pptx
Grace Jansen
ย 
Why I โค๏ธ Kotlin Multiplatform (and want YOU to also โค๏ธ Kotlin Multiplatform)
Why I โค๏ธ Kotlin Multiplatform (and want YOU to also โค๏ธ Kotlin Multiplatform)Why I โค๏ธ Kotlin Multiplatform (and want YOU to also โค๏ธ Kotlin Multiplatform)
Why I โค๏ธ Kotlin Multiplatform (and want YOU to also โค๏ธ Kotlin Multiplatform)
Derek Lee
ย 
Tell Me Quando - Implementing Feature Flags
Tell Me Quando - Implementing Feature FlagsTell Me Quando - Implementing Feature Flags
Tell Me Quando - Implementing Feature Flags
Jorge Ortiz
ย 
Rapid and Reliable Developing with HTML5 & GWT
Rapid and Reliable Developing with HTML5 & GWTRapid and Reliable Developing with HTML5 & GWT
Rapid and Reliable Developing with HTML5 & GWT
Manuel Carrasco Moรฑino
ย 
Developing for BlackBerry 10 โ€“ Tools and SDKs by Luca Filigheddu
 Developing for BlackBerry 10 โ€“ Tools and SDKs by Luca Filigheddu Developing for BlackBerry 10 โ€“ Tools and SDKs by Luca Filigheddu
Developing for BlackBerry 10 โ€“ Tools and SDKs by Luca Filigheddu
Codemotion
ย 
Visage Android Hands-on Lab
Visage Android Hands-on LabVisage Android Hands-on Lab
Visage Android Hands-on Lab
Stephen Chin
ย 
TK2323 Lecture 1 - Introduction to Mobile Application.pdf
TK2323 Lecture 1 - Introduction to Mobile Application.pdfTK2323 Lecture 1 - Introduction to Mobile Application.pdf
TK2323 Lecture 1 - Introduction to Mobile Application.pdf
Lam Chun
ย 
whats-new-netbeans-ide-7x.pptx
whats-new-netbeans-ide-7x.pptxwhats-new-netbeans-ide-7x.pptx
whats-new-netbeans-ide-7x.pptx
GabrielSoche
ย 
005528214.pdf
005528214.pdf005528214.pdf
005528214.pdf
EidTahir
ย 
[20200720]cloud native develoment - Nelson Lin
[20200720]cloud native develoment - Nelson Lin[20200720]cloud native develoment - Nelson Lin
[20200720]cloud native develoment - Nelson Lin
HanLing Shen
ย 
PittsburgJUG_Cloud-Native Dev Tools: Bringing the cloud back to earth
PittsburgJUG_Cloud-Native Dev Tools: Bringing the cloud back to earthPittsburgJUG_Cloud-Native Dev Tools: Bringing the cloud back to earth
PittsburgJUG_Cloud-Native Dev Tools: Bringing the cloud back to earth
Grace Jansen
ย 
gopaddle-meetup
gopaddle-meetupgopaddle-meetup
gopaddle-meetup
Sujai Sivasamy
ย 
iOS Development Survival Guide for the .NET Guy
iOS Development Survival Guide for the .NET GuyiOS Development Survival Guide for the .NET Guy
iOS Development Survival Guide for the .NET Guy
Nick Landry
ย 
Getting started with the NDK
Getting started with the NDKGetting started with the NDK
Getting started with the NDK
Kirill Kounik
ย 
Kotlin native for iOS and Android
Kotlin native for iOS and AndroidKotlin native for iOS and Android
Kotlin native for iOS and Android
Shady Selim
ย 
Intro to Eclipse Che, by Tyler Jewell
Intro to Eclipse Che, by Tyler JewellIntro to Eclipse Che, by Tyler Jewell
Intro to Eclipse Che, by Tyler Jewell
jwi11iams
ย 
FooConf23_Bringing the cloud back down to earth.pptx
FooConf23_Bringing the cloud back down to earth.pptxFooConf23_Bringing the cloud back down to earth.pptx
FooConf23_Bringing the cloud back down to earth.pptx
Grace Jansen
ย 
Mobile Web Apps and the Intelยฎ XDK
Mobile Web Apps and the Intelยฎ XDKMobile Web Apps and the Intelยฎ XDK
Mobile Web Apps and the Intelยฎ XDK
Intelยฎ Software
ย 
Comment dรฉvelopper une application mobile en 8 semaines - Meetup PAUG 24-01-2023
Comment dรฉvelopper une application mobile en 8 semaines - Meetup PAUG 24-01-2023Comment dรฉvelopper une application mobile en 8 semaines - Meetup PAUG 24-01-2023
Comment dรฉvelopper une application mobile en 8 semaines - Meetup PAUG 24-01-2023
Nicolas HAAN
ย 
Jfokus_Bringing the cloud back down to earth.pptx
Jfokus_Bringing the cloud back down to earth.pptxJfokus_Bringing the cloud back down to earth.pptx
Jfokus_Bringing the cloud back down to earth.pptx
Grace Jansen
ย 
SwissJUG_Bringing the cloud back down to earth.pptx
SwissJUG_Bringing the cloud back down to earth.pptxSwissJUG_Bringing the cloud back down to earth.pptx
SwissJUG_Bringing the cloud back down to earth.pptx
Grace Jansen
ย 
Why I โค๏ธ Kotlin Multiplatform (and want YOU to also โค๏ธ Kotlin Multiplatform)
Why I โค๏ธ Kotlin Multiplatform (and want YOU to also โค๏ธ Kotlin Multiplatform)Why I โค๏ธ Kotlin Multiplatform (and want YOU to also โค๏ธ Kotlin Multiplatform)
Why I โค๏ธ Kotlin Multiplatform (and want YOU to also โค๏ธ Kotlin Multiplatform)
Derek Lee
ย 
Tell Me Quando - Implementing Feature Flags
Tell Me Quando - Implementing Feature FlagsTell Me Quando - Implementing Feature Flags
Tell Me Quando - Implementing Feature Flags
Jorge Ortiz
ย 
Rapid and Reliable Developing with HTML5 & GWT
Rapid and Reliable Developing with HTML5 & GWTRapid and Reliable Developing with HTML5 & GWT
Rapid and Reliable Developing with HTML5 & GWT
Manuel Carrasco Moรฑino
ย 
Developing for BlackBerry 10 โ€“ Tools and SDKs by Luca Filigheddu
 Developing for BlackBerry 10 โ€“ Tools and SDKs by Luca Filigheddu Developing for BlackBerry 10 โ€“ Tools and SDKs by Luca Filigheddu
Developing for BlackBerry 10 โ€“ Tools and SDKs by Luca Filigheddu
Codemotion
ย 
Visage Android Hands-on Lab
Visage Android Hands-on LabVisage Android Hands-on Lab
Visage Android Hands-on Lab
Stephen Chin
ย 
TK2323 Lecture 1 - Introduction to Mobile Application.pdf
TK2323 Lecture 1 - Introduction to Mobile Application.pdfTK2323 Lecture 1 - Introduction to Mobile Application.pdf
TK2323 Lecture 1 - Introduction to Mobile Application.pdf
Lam Chun
ย 
whats-new-netbeans-ide-7x.pptx
whats-new-netbeans-ide-7x.pptxwhats-new-netbeans-ide-7x.pptx
whats-new-netbeans-ide-7x.pptx
GabrielSoche
ย 
005528214.pdf
005528214.pdf005528214.pdf
005528214.pdf
EidTahir
ย 
[20200720]cloud native develoment - Nelson Lin
[20200720]cloud native develoment - Nelson Lin[20200720]cloud native develoment - Nelson Lin
[20200720]cloud native develoment - Nelson Lin
HanLing Shen
ย 
PittsburgJUG_Cloud-Native Dev Tools: Bringing the cloud back to earth
PittsburgJUG_Cloud-Native Dev Tools: Bringing the cloud back to earthPittsburgJUG_Cloud-Native Dev Tools: Bringing the cloud back to earth
PittsburgJUG_Cloud-Native Dev Tools: Bringing the cloud back to earth
Grace Jansen
ย 
gopaddle-meetup
gopaddle-meetupgopaddle-meetup
gopaddle-meetup
Sujai Sivasamy
ย 
iOS Development Survival Guide for the .NET Guy
iOS Development Survival Guide for the .NET GuyiOS Development Survival Guide for the .NET Guy
iOS Development Survival Guide for the .NET Guy
Nick Landry
ย 
Getting started with the NDK
Getting started with the NDKGetting started with the NDK
Getting started with the NDK
Kirill Kounik
ย 
Kotlin native for iOS and Android
Kotlin native for iOS and AndroidKotlin native for iOS and Android
Kotlin native for iOS and Android
Shady Selim
ย 
Ad

More from DroidConTLV (20)

Mobile Development in the Information Age - Yossi Elkrief, Nike
Mobile Development in the Information Age - Yossi Elkrief, NikeMobile Development in the Information Age - Yossi Elkrief, Nike
Mobile Development in the Information Age - Yossi Elkrief, Nike
DroidConTLV
ย 
Doing work in the background - Darryn Campbell, Zebra Technologies
Doing work in the background - Darryn Campbell, Zebra TechnologiesDoing work in the background - Darryn Campbell, Zebra Technologies
Doing work in the background - Darryn Campbell, Zebra Technologies
DroidConTLV
ย 
No more video loss - Alex Rivkin, Motorola Solutions
No more video loss - Alex Rivkin, Motorola SolutionsNo more video loss - Alex Rivkin, Motorola Solutions
No more video loss - Alex Rivkin, Motorola Solutions
DroidConTLV
ย 
Mobile at Scale: from startup to a big company - Dor Samet, Booking.com
Mobile at Scale: from startup to a big company - Dor Samet, Booking.comMobile at Scale: from startup to a big company - Dor Samet, Booking.com
Mobile at Scale: from startup to a big company - Dor Samet, Booking.com
DroidConTLV
ย 
LiveData on Steroids - Giora Shevach + Shahar Ben Moshe, Climacell
LiveData on Steroids - Giora Shevach + Shahar Ben Moshe, ClimacellLiveData on Steroids - Giora Shevach + Shahar Ben Moshe, Climacell
LiveData on Steroids - Giora Shevach + Shahar Ben Moshe, Climacell
DroidConTLV
ย 
MVVM In real life - Lea Cohen Tannoudji, Lightricks
MVVM In real life - Lea Cohen Tannoudji, LightricksMVVM In real life - Lea Cohen Tannoudji, Lightricks
MVVM In real life - Lea Cohen Tannoudji, Lightricks
DroidConTLV
ย 
Best Practices for Using Mobile SDKs - Lilach Wagner, SafeDK (AppLovin)
Best Practices for Using Mobile SDKs - Lilach Wagner, SafeDK (AppLovin)Best Practices for Using Mobile SDKs - Lilach Wagner, SafeDK (AppLovin)
Best Practices for Using Mobile SDKs - Lilach Wagner, SafeDK (AppLovin)
DroidConTLV
ย 
Building Apps with Flutter - Hillel Coren, Invoice Ninja
Building Apps with Flutter - Hillel Coren, Invoice NinjaBuilding Apps with Flutter - Hillel Coren, Invoice Ninja
Building Apps with Flutter - Hillel Coren, Invoice Ninja
DroidConTLV
ย 
New Android Project: The Most Important Decisions - Vasiliy Zukanov
New Android Project: The Most Important Decisions - Vasiliy ZukanovNew Android Project: The Most Important Decisions - Vasiliy Zukanov
New Android Project: The Most Important Decisions - Vasiliy Zukanov
DroidConTLV
ย 
Designing a Design System - Shai Mishali, Gett
Designing a Design System - Shai Mishali, GettDesigning a Design System - Shai Mishali, Gett
Designing a Design System - Shai Mishali, Gett
DroidConTLV
ย 
The Mighty Power of the Accessibility Service - Guy Griv, Pepper
The Mighty Power of the Accessibility Service - Guy Griv, PepperThe Mighty Power of the Accessibility Service - Guy Griv, Pepper
The Mighty Power of the Accessibility Service - Guy Griv, Pepper
DroidConTLV
ย 
Flutter State Management - Moti Bartov, Tikal
Flutter State Management - Moti Bartov, TikalFlutter State Management - Moti Bartov, Tikal
Flutter State Management - Moti Bartov, Tikal
DroidConTLV
ย 
Reactive UI in android - Gil Goldzweig Goldbaum, 10bis
Reactive UI in android - Gil Goldzweig Goldbaum, 10bisReactive UI in android - Gil Goldzweig Goldbaum, 10bis
Reactive UI in android - Gil Goldzweig Goldbaum, 10bis
DroidConTLV
ย 
Fun with flutter animations - Divyanshu Bhargava, GoHighLevel
Fun with flutter animations - Divyanshu Bhargava, GoHighLevelFun with flutter animations - Divyanshu Bhargava, GoHighLevel
Fun with flutter animations - Divyanshu Bhargava, GoHighLevel
DroidConTLV
ย 
DroidconTLV 2019
DroidconTLV 2019DroidconTLV 2019
DroidconTLV 2019
DroidConTLV
ย 
Ok google, it's time to bot! - Hadar Franco, Albert + Stav Levi, Monday
Ok google, it's time to bot! - Hadar Franco, Albert + Stav Levi, MondayOk google, it's time to bot! - Hadar Franco, Albert + Stav Levi, Monday
Ok google, it's time to bot! - Hadar Franco, Albert + Stav Levi, Monday
DroidConTLV
ย 
Introduction to React Native - Lev Vidrak, Wix
Introduction to React Native - Lev Vidrak, WixIntroduction to React Native - Lev Vidrak, Wix
Introduction to React Native - Lev Vidrak, Wix
DroidConTLV
ย 
Bang-Bang, you have been hacked - Yonatan Levin, KolGene
Bang-Bang, you have been hacked - Yonatan Levin, KolGeneBang-Bang, you have been hacked - Yonatan Levin, KolGene
Bang-Bang, you have been hacked - Yonatan Levin, KolGene
DroidConTLV
ย 
Educating your app โ€“ adding ML edge to your apps - Maoz Tamir
Educating your app โ€“ adding ML edge to your apps - Maoz TamirEducating your app โ€“ adding ML edge to your apps - Maoz Tamir
Educating your app โ€“ adding ML edge to your apps - Maoz Tamir
DroidConTLV
ย 
Constraint-ly motion - making your app dance - John Hoford, Google
Constraint-ly motion - making your app dance - John Hoford, GoogleConstraint-ly motion - making your app dance - John Hoford, Google
Constraint-ly motion - making your app dance - John Hoford, Google
DroidConTLV
ย 
Mobile Development in the Information Age - Yossi Elkrief, Nike
Mobile Development in the Information Age - Yossi Elkrief, NikeMobile Development in the Information Age - Yossi Elkrief, Nike
Mobile Development in the Information Age - Yossi Elkrief, Nike
DroidConTLV
ย 
Doing work in the background - Darryn Campbell, Zebra Technologies
Doing work in the background - Darryn Campbell, Zebra TechnologiesDoing work in the background - Darryn Campbell, Zebra Technologies
Doing work in the background - Darryn Campbell, Zebra Technologies
DroidConTLV
ย 
No more video loss - Alex Rivkin, Motorola Solutions
No more video loss - Alex Rivkin, Motorola SolutionsNo more video loss - Alex Rivkin, Motorola Solutions
No more video loss - Alex Rivkin, Motorola Solutions
DroidConTLV
ย 
Mobile at Scale: from startup to a big company - Dor Samet, Booking.com
Mobile at Scale: from startup to a big company - Dor Samet, Booking.comMobile at Scale: from startup to a big company - Dor Samet, Booking.com
Mobile at Scale: from startup to a big company - Dor Samet, Booking.com
DroidConTLV
ย 
LiveData on Steroids - Giora Shevach + Shahar Ben Moshe, Climacell
LiveData on Steroids - Giora Shevach + Shahar Ben Moshe, ClimacellLiveData on Steroids - Giora Shevach + Shahar Ben Moshe, Climacell
LiveData on Steroids - Giora Shevach + Shahar Ben Moshe, Climacell
DroidConTLV
ย 
MVVM In real life - Lea Cohen Tannoudji, Lightricks
MVVM In real life - Lea Cohen Tannoudji, LightricksMVVM In real life - Lea Cohen Tannoudji, Lightricks
MVVM In real life - Lea Cohen Tannoudji, Lightricks
DroidConTLV
ย 
Best Practices for Using Mobile SDKs - Lilach Wagner, SafeDK (AppLovin)
Best Practices for Using Mobile SDKs - Lilach Wagner, SafeDK (AppLovin)Best Practices for Using Mobile SDKs - Lilach Wagner, SafeDK (AppLovin)
Best Practices for Using Mobile SDKs - Lilach Wagner, SafeDK (AppLovin)
DroidConTLV
ย 
Building Apps with Flutter - Hillel Coren, Invoice Ninja
Building Apps with Flutter - Hillel Coren, Invoice NinjaBuilding Apps with Flutter - Hillel Coren, Invoice Ninja
Building Apps with Flutter - Hillel Coren, Invoice Ninja
DroidConTLV
ย 
New Android Project: The Most Important Decisions - Vasiliy Zukanov
New Android Project: The Most Important Decisions - Vasiliy ZukanovNew Android Project: The Most Important Decisions - Vasiliy Zukanov
New Android Project: The Most Important Decisions - Vasiliy Zukanov
DroidConTLV
ย 
Designing a Design System - Shai Mishali, Gett
Designing a Design System - Shai Mishali, GettDesigning a Design System - Shai Mishali, Gett
Designing a Design System - Shai Mishali, Gett
DroidConTLV
ย 
The Mighty Power of the Accessibility Service - Guy Griv, Pepper
The Mighty Power of the Accessibility Service - Guy Griv, PepperThe Mighty Power of the Accessibility Service - Guy Griv, Pepper
The Mighty Power of the Accessibility Service - Guy Griv, Pepper
DroidConTLV
ย 
Flutter State Management - Moti Bartov, Tikal
Flutter State Management - Moti Bartov, TikalFlutter State Management - Moti Bartov, Tikal
Flutter State Management - Moti Bartov, Tikal
DroidConTLV
ย 
Reactive UI in android - Gil Goldzweig Goldbaum, 10bis
Reactive UI in android - Gil Goldzweig Goldbaum, 10bisReactive UI in android - Gil Goldzweig Goldbaum, 10bis
Reactive UI in android - Gil Goldzweig Goldbaum, 10bis
DroidConTLV
ย 
Fun with flutter animations - Divyanshu Bhargava, GoHighLevel
Fun with flutter animations - Divyanshu Bhargava, GoHighLevelFun with flutter animations - Divyanshu Bhargava, GoHighLevel
Fun with flutter animations - Divyanshu Bhargava, GoHighLevel
DroidConTLV
ย 
DroidconTLV 2019
DroidconTLV 2019DroidconTLV 2019
DroidconTLV 2019
DroidConTLV
ย 
Ok google, it's time to bot! - Hadar Franco, Albert + Stav Levi, Monday
Ok google, it's time to bot! - Hadar Franco, Albert + Stav Levi, MondayOk google, it's time to bot! - Hadar Franco, Albert + Stav Levi, Monday
Ok google, it's time to bot! - Hadar Franco, Albert + Stav Levi, Monday
DroidConTLV
ย 
Introduction to React Native - Lev Vidrak, Wix
Introduction to React Native - Lev Vidrak, WixIntroduction to React Native - Lev Vidrak, Wix
Introduction to React Native - Lev Vidrak, Wix
DroidConTLV
ย 
Bang-Bang, you have been hacked - Yonatan Levin, KolGene
Bang-Bang, you have been hacked - Yonatan Levin, KolGeneBang-Bang, you have been hacked - Yonatan Levin, KolGene
Bang-Bang, you have been hacked - Yonatan Levin, KolGene
DroidConTLV
ย 
Educating your app โ€“ adding ML edge to your apps - Maoz Tamir
Educating your app โ€“ adding ML edge to your apps - Maoz TamirEducating your app โ€“ adding ML edge to your apps - Maoz Tamir
Educating your app โ€“ adding ML edge to your apps - Maoz Tamir
DroidConTLV
ย 
Constraint-ly motion - making your app dance - John Hoford, Google
Constraint-ly motion - making your app dance - John Hoford, GoogleConstraint-ly motion - making your app dance - John Hoford, Google
Constraint-ly motion - making your app dance - John Hoford, Google
DroidConTLV
ย 
Ad

Recently uploaded (20)

Technology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data AnalyticsTechnology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data Analytics
InData Labs
ย 
Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025
Splunk
ย 
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In FranceManifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
chb3
ย 
Greenhouse_Monitoring_Presentation.pptx.
Greenhouse_Monitoring_Presentation.pptx.Greenhouse_Monitoring_Presentation.pptx.
Greenhouse_Monitoring_Presentation.pptx.
hpbmnnxrvb
ย 
Rusty Waters: Elevating Lakehouses Beyond Spark
Rusty Waters: Elevating Lakehouses Beyond SparkRusty Waters: Elevating Lakehouses Beyond Spark
Rusty Waters: Elevating Lakehouses Beyond Spark
carlyakerly1
ย 
Special Meetup Edition - TDX Bengaluru Meetup #52.pptx
Special Meetup Edition - TDX Bengaluru Meetup #52.pptxSpecial Meetup Edition - TDX Bengaluru Meetup #52.pptx
Special Meetup Edition - TDX Bengaluru Meetup #52.pptx
shyamraj55
ย 
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
organizerofv
ย 
How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?
Daniel Lehner
ย 
UiPath Community Berlin: Orchestrator API, Swagger, and Test Manager API
UiPath Community Berlin: Orchestrator API, Swagger, and Test Manager APIUiPath Community Berlin: Orchestrator API, Swagger, and Test Manager API
UiPath Community Berlin: Orchestrator API, Swagger, and Test Manager API
UiPathCommunity
ย 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
ย 
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
SOFTTECHHUB
ย 
Big Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur MorganBig Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur Morgan
Arthur Morgan
ย 
Electronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploitElectronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploit
niftliyevhuseyn
ย 
Procurement Insights Cost To Value Guide.pptx
Procurement Insights Cost To Value Guide.pptxProcurement Insights Cost To Value Guide.pptx
Procurement Insights Cost To Value Guide.pptx
Jon Hansen
ย 
Linux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdfLinux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdf
RHCSA Guru
ย 
Cyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of securityCyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of security
riccardosl1
ย 
AI Changes Everything โ€“ Talk at Cardiff Metropolitan University, 29th April 2...
AI Changes Everything โ€“ Talk at Cardiff Metropolitan University, 29th April 2...AI Changes Everything โ€“ Talk at Cardiff Metropolitan University, 29th April 2...
AI Changes Everything โ€“ Talk at Cardiff Metropolitan University, 29th April 2...
Alan Dix
ย 
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdfThe Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
Abi john
ย 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
ย 
TrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business ConsultingTrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business Consulting
Trs Labs
ย 
Technology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data AnalyticsTechnology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data Analytics
InData Labs
ย 
Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025
Splunk
ย 
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In FranceManifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
chb3
ย 
Greenhouse_Monitoring_Presentation.pptx.
Greenhouse_Monitoring_Presentation.pptx.Greenhouse_Monitoring_Presentation.pptx.
Greenhouse_Monitoring_Presentation.pptx.
hpbmnnxrvb
ย 
Rusty Waters: Elevating Lakehouses Beyond Spark
Rusty Waters: Elevating Lakehouses Beyond SparkRusty Waters: Elevating Lakehouses Beyond Spark
Rusty Waters: Elevating Lakehouses Beyond Spark
carlyakerly1
ย 
Special Meetup Edition - TDX Bengaluru Meetup #52.pptx
Special Meetup Edition - TDX Bengaluru Meetup #52.pptxSpecial Meetup Edition - TDX Bengaluru Meetup #52.pptx
Special Meetup Edition - TDX Bengaluru Meetup #52.pptx
shyamraj55
ย 
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
IEDM 2024 Tutorial2_Advances in CMOS Technologies and Future Directions for C...
organizerofv
ย 
How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?
Daniel Lehner
ย 
UiPath Community Berlin: Orchestrator API, Swagger, and Test Manager API
UiPath Community Berlin: Orchestrator API, Swagger, and Test Manager APIUiPath Community Berlin: Orchestrator API, Swagger, and Test Manager API
UiPath Community Berlin: Orchestrator API, Swagger, and Test Manager API
UiPathCommunity
ย 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
ย 
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
SOFTTECHHUB
ย 
Big Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur MorganBig Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur Morgan
Arthur Morgan
ย 
Electronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploitElectronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploit
niftliyevhuseyn
ย 
Procurement Insights Cost To Value Guide.pptx
Procurement Insights Cost To Value Guide.pptxProcurement Insights Cost To Value Guide.pptx
Procurement Insights Cost To Value Guide.pptx
Jon Hansen
ย 
Linux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdfLinux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdf
RHCSA Guru
ย 
Cyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of securityCyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of security
riccardosl1
ย 
AI Changes Everything โ€“ Talk at Cardiff Metropolitan University, 29th April 2...
AI Changes Everything โ€“ Talk at Cardiff Metropolitan University, 29th April 2...AI Changes Everything โ€“ Talk at Cardiff Metropolitan University, 29th April 2...
AI Changes Everything โ€“ Talk at Cardiff Metropolitan University, 29th April 2...
Alan Dix
ย 
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdfThe Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
Abi john
ย 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
ย 
TrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business ConsultingTrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business Consulting
Trs Labs
ย 

Kotlin Multiplatform in Action - Alexandr Pogrebnyak - IceRockDev

  • 1. DEVELOPMENT 1 Kotlin Multiplatform in Action Alexandr Pogrebnyak Droidcon Tel Aviv 19.12.19.
  • 2. DEVELOPMENT โ— About us โ— What is Kotlin Multiplatform? โ— Our experience in Kotlin Multiplatform โ— moko.icerock.dev โ€“ a set of multiplatform libraries โ— moko-widgets 2
  • 3. DEVELOPMENT โ— 5 years in mobile development โ— 80+ mobile projects (iOS & Android) โ— 40+ developers in 2 offices 3
  • 4. DEVELOPMENT Focus on: 4 Avoid logic reduplication and keep UI native
  • 5. DEVELOPMENT 5 Code Sharing in IceRock Flutter React Native J2ObjC New programming language Integration with OS via middle layer Non-native UI Legacy tech stacks Asynchronous work with OS Need to adopt Java-code to ObjC Native UI Hot reload
  • 6. DEVELOPMENT 6 Kotlin Multiplatform + Kotlin/Native Code Sharing at IceRock Kotlin looks like Swift Inner libraries already in Kotlin Shift to native env at any moment Familiar programming language Native UI Full access to Android OS and iOS features and SDKs There are some limitations in Kotlin > Swift direction Devs worry about integration
  • 7. DEVELOPMENT 7 Kotlin Multiplatform at IceRock Kotlin MPP and Kotlin/Native since July 2018 1 year achievement Reduce time and cost for both platforms by 1.5x 1.5x speed 50% of shared code on average 50:50 Easy learning curve for Android and iOS developers Easy to learn, hard to master
  • 8. DEVELOPMENT 8 Kotlin Multiplatform Android Windows macOS Linux Java Java Script WebAssemblyiOS
  • 9. DEVELOPMENT 9 expect class Logger(tag: String) { fun log(string: String) } fun main() { val logger = Logger("MPP") logger.log("hello world!") } commonMain
  • 10. DEVELOPMENT 10 iosMain import platform.Foundation.NSLog actual class Logger actual constructor(private val tag: String) { actual fun log(string: String) { NSLog("[$tag] $string") } } import android.util.Log actual class Logger actual constructor(private val tag: String) { actual fun log(string: String) { Log.v(tag, string) } } androidMain
  • 11. DEVELOPMENT 11 androidMain โ””โ”€โ”€ kotlin โ””โ”€โ”€ com.icerockdev.library โ””โ”€โ”€ Logger.kt commonMain โ””โ”€โ”€ kotlin โ””โ”€โ”€ com.icerockdev.library โ””โ”€โ”€ Logger.kt iosMain โ””โ”€โ”€ kotlin โ””โ”€โ”€ com.icerockdev.library โ””โ”€โ”€ Logger.kt Kotlin Multiplatform
  • 12. DEVELOPMENT 12 Kotlin Multiplatform - past View AuthActivity AuthViewController Pro๏ฌleViewController Pro๏ฌleActivity Presentation AuthViewModel Pro๏ฌleViewModel PostsViewModel AddPostViewModel Domain UserInteractor PostsInteractor Validator Payment Data User Post UserRepository PostRepository RestUser RestPost UserApi PostApi
  • 13. DEVELOPMENT 13 Kotlin Multiplatform - now View AuthScreen Pro๏ฌleScreen Presentation AuthViewModel Pro๏ฌleViewModel PostsViewModel Domain UserInteractor PostsInteractor Validator Data User Post UserRepository RestUser RestPost UserApi powered by
  • 14. DEVELOPMENT 14 Shared Code in a Typical Project - past Shared code 62% Android-speci๏ฌc 16% iOS-speci๏ฌc 22%
  • 15. DEVELOPMENT 15 Shared Code in a Typical Project - now Android-speci๏ฌc 3% iOS-speci๏ฌc 2% Shared code 95% powered by
  • 21. DEVELOPMENT 21 A moko-template (sample project) https://github.com/icerockdev/moko-template.git Features: Install: git clone Done! app_name app_icon applicationId โ— Shared business logic โ— Kotlin Gradle DSL โ— Modular-based architecture โ— Independent feature and domain modules โ— ViewModels, LiveData, Resource management, Runtime permissions access, Media access, UI from shared code, Network layer generation from OpenAPIโ€ฆ
  • 23. DEVELOPMENT Goal #1 1 Kotlin developer => 2 native mobile apps 23 goals
  • 24. DEVELOPMENT Goal #2 Fast start = the codebase should grow without rewrites 24 goals
  • 25. DEVELOPMENT The basic architecture concepts: 1. compliance with platform rules 2. declare structure, not rendering 3. compile-time safety 4. reactive data handling 25 concepts
  • 26. DEVELOPMENT 26 code class App : BaseApplication() { override fun setup() { val theme = Theme() registerScreenFactory(MainScreen::class) { MainScreen(theme) } } override fun getRootScreen(): KClass<out Screen<Args.Empty>> { return MainScreen::class } } common
  • 27. DEVELOPMENT 27 code class MainApplication : Application() { override fun onCreate() { super.onCreate() mppApplication = App().apply { setup() } } companion object { lateinit var mppApplication: App } } class MainActivity : HostActivity() { override val application: BaseApplication get() = MainApplication.mppApplication } android
  • 28. DEVELOPMENT 28 code @UIApplicationMain class AppDelegate: NSObject, UIApplicationDelegate { var window: UIWindow? func application(_ application: ..., didFinishLaunchingWithOptions ...) -> Bool { let app = App() app.setup() let screen = app.createRootScreen() let rootViewController = screen.createViewController() window = UIWindow(frame: UIScreen.main.bounds) window?.rootViewController = rootViewController window?.makeKeyAndVisible() return true } } ios
  • 29. DEVELOPMENT 29 code class MainScreen( private val theme: Theme ) : WidgetScreen<Args.Empty>() { override fun createContentWidget() = with(theme) { container(size = WidgetSize.AsParent) { center { text( size = WidgetSize.WrapContent, text = const(MR.strings.hello_world.desc()) ) } } } } common
  • 30. DEVELOPMENT 30 code class MainScreen( private val theme: Theme ) : WidgetScreen<Args.Empty>() { override fun createContentWidget() = with(theme) { container(size = WidgetSize.AsParent) { center { text( size = WidgetSize.WrapContent, text = const(MR.strings.hello_world.desc()) ) } } } } common
  • 31. DEVELOPMENT 31 code class MainScreen( private val theme: Theme ) : WidgetScreen<Args.Empty>() { override fun createContentWidget() = with(theme) { container(size = WidgetSize.AsParent) { center { text( size = WidgetSize.WrapContent, text = const(MR.strings.hello_world.desc()) ) } } } } common
  • 32. DEVELOPMENT 32 code class MainScreen( private val theme: Theme ) : WidgetScreen<Args.Empty>() { override fun createContentWidget() = with(theme) { container(size = WidgetSize.AsParent) { center { text( size = WidgetSize.WrapContent, text = const(MR.strings.hello_world.desc()) ) } } } } common
  • 33. DEVELOPMENT 33 code class MainScreen( private val theme: Theme ) : WidgetScreen<Args.Empty>() { override fun createContentWidget() = with(theme) { container(size = WidgetSize.AsParent) { center { text( size = WidgetSize.WrapContent, text = const(MR.strings.hello_world.desc()) ) } } } } common
  • 34. DEVELOPMENT 34 code class MainScreen( private val theme: Theme ) : WidgetScreen<Args.Empty>() { override fun createContentWidget() = with(theme) { container(size = WidgetSize.AsParent) { center { text( size = WidgetSize.WrapContent, text = const(MR.strings.hello_world.desc()) ) } } } } common
  • 36. DEVELOPMENT 36 code class App : BaseApplication() { override fun setup() { val theme = Theme { // custom styles here } registerScreenFactory(MainScreen::class) { MainScreen(theme) } } override fun getRootScreen(): KClass<out Screen<Args.Empty>> { return MainScreen::class } } common
  • 37. DEVELOPMENT 37 code val theme = Theme { textFactory = DefaultTextWidgetViewFactory( DefaultTextWidgetViewFactoryBase.Style( textStyle = TextStyle( size = 24, color = Colors.black ), padding = PaddingValues(padding = 16f) ) ) } common
  • 38. DEVELOPMENT 38 code val theme = Theme { textFactory = DefaultTextWidgetViewFactory( DefaultTextWidgetViewFactoryBase.Style( textStyle = TextStyle( size = 24, color = Colors.black ), padding = PaddingValues(padding = 16f) ) ) } common
  • 39. DEVELOPMENT 39 code val theme = Theme { textFactory = DefaultTextWidgetViewFactory( DefaultTextWidgetViewFactoryBase.Style( textStyle = TextStyle( size = 24, color = Colors.black ), padding = PaddingValues(padding = 16f) ) ) } common
  • 41. DEVELOPMENT Simple is simple. How about some complexity? 41 code
  • 44. DEVELOPMENT 44 code class LoginScreen( private val theme: Theme ) : WidgetScreen<Args.Empty>() { override fun createContentWidget() = with(theme) { constraint(size = WidgetSize.AsParent) { // ... } } } common
  • 45. DEVELOPMENT 45 code override fun createContentWidget() = with(theme) { constraint(size = WidgetSize.AsParent) { val logoImage = +image( size = WidgetSize.Const(SizeSpec.WrapContent, SizeSpec.WrapContent), image = const(Image.resource(MR.images.logo)) ) } } common
  • 46. DEVELOPMENT 46 code constraint(size = WidgetSize.AsParent) { val logoImage = +image(...) val emailInput = +input( size = WidgetSize.WidthAsParentHeightWrapContent, id = Id.EmailInputId, label = const("Email".desc() as StringDesc), field = viewModel.emailField ) val passwordInput = +input( size = WidgetSize.WidthAsParentHeightWrapContent, id = Id.PasswordInputId, label = const("Password".desc() as StringDesc), field = viewModel.passwordField ) } common
  • 47. DEVELOPMENT 47 code constraint(size = WidgetSize.AsParent) { val logoImage = +image(...) val emailInput = +input(...) val passwordInput = +input(...) val loginButton = +button( size = WidgetSize.Const(SizeSpec.AsParent, SizeSpec.Exact(50f)), text = const("Login".desc() as StringDesc), onTap = viewModel::onLoginPressed ) } common
  • 48. DEVELOPMENT 48 code constraint(size = WidgetSize.AsParent) { val logoImage = +image(...) val emailInput = +input(...) val passwordInput = +input(...) val loginButton = +button(...) constraints { passwordInput centerYToCenterY root passwordInput leftRightToLeftRight root emailInput bottomToTop passwordInput emailInput leftRightToLeftRight root loginButton topToBottom passwordInput loginButton leftRightToLeftRight root logoImage centerXToCenterX root logoImage.verticalCenterBetween( top = root.top, bottom = emailInput.top ) } common
  • 49. DEVELOPMENT 49 code constraint(size = WidgetSize.AsParent) { val logoImage = +image(...) val emailInput = +input(...) val passwordInput = +input(...) val loginButton = +button(...) constraints { passwordInput centerYToCenterY root passwordInput leftRightToLeftRight root emailInput bottomToTop passwordInput emailInput leftRightToLeftRight root loginButton topToBottom passwordInput loginButton leftRightToLeftRight root logoImage centerXToCenterX root logoImage.verticalCenterBetween( top = root.top, bottom = emailInput.top ) } common
  • 50. DEVELOPMENT 50 code constraint(size = WidgetSize.AsParent) { val logoImage = +image(...) val emailInput = +input(...) val passwordInput = +input(...) val loginButton = +button(...) constraints { passwordInput centerYToCenterY root passwordInput leftRightToLeftRight root emailInput bottomToTop passwordInput emailInput leftRightToLeftRight root loginButton topToBottom passwordInput loginButton leftRightToLeftRight root logoImage centerXToCenterX root logoImage.verticalCenterBetween( top = root.top, bottom = emailInput.top ) } common
  • 51. DEVELOPMENT 51 code constraint(size = WidgetSize.AsParent) { val logoImage = +image(...) val emailInput = +input(...) val passwordInput = +input(...) val loginButton = +button(...) constraints { passwordInput centerYToCenterY root passwordInput leftRightToLeftRight root emailInput bottomToTop passwordInput emailInput leftRightToLeftRight root loginButton topToBottom passwordInput loginButton leftRightToLeftRight root logoImage centerXToCenterX root logoImage.verticalCenterBetween( top = root.top, bottom = emailInput.top ) } common
  • 54. DEVELOPMENT 54 code val loginTheme = Theme(theme) { constraintFactory = DefaultConstraintWidgetViewFactory( DefaultConstraintWidgetViewFactoryBase.Style( padding = PaddingValues(16f), background = Background( fill = Fill.Solid(Colors.white) ) ) ) } common
  • 55. DEVELOPMENT 55 code val loginTheme = Theme(theme) { constraintFactory = DefaultConstraintWidgetViewFactory(...) imageFactory = DefaultImageWidgetViewFactory( DefaultImageWidgetViewFactoryBase.Style( scaleType = DefaultImageWidgetViewFactoryBase.ScaleType.FIT ) ) } common
  • 56. DEVELOPMENT 56 code val loginTheme = Theme(theme) { constraintFactory = DefaultConstraintWidgetViewFactory(...) imageFactory = DefaultImageWidgetViewFactory(...) val corners = platformSpecific(android = 8f, ios = 25f) inputFactory = DefaultInputWidgetViewFactory( DefaultInputWidgetViewFactoryBase.Style( margins = MarginValues(bottom = 8f), underLineColor = Color(0xe5e6eeFF), labelTextStyle = TextStyle( color = Color(0x777889FF) ) ) ) } common
  • 57. DEVELOPMENT 57 code val loginTheme = Theme(theme) { constraintFactory = DefaultConstraintWidgetViewFactory(...) imageFactory = DefaultImageWidgetViewFactory(...) val corners = platformSpecific(android = 16f, ios = 25f) inputFactory = DefaultInputWidgetViewFactory( DefaultInputWidgetViewFactoryBase.Style( margins = MarginValues(bottom = 8f), underLineColor = Color(0xe5e6eeFF), labelTextStyle = TextStyle( color = Color(0x777889FF) ) ) ) } common
  • 58. DEVELOPMENT 58 code val loginTheme = Theme(theme) { constraintFactory = DefaultConstraintWidgetViewFactory(...) imageFactory = DefaultImageWidgetViewFactory(...) val corners = ... inputFactory = DefaultInputWidgetViewFactory(...) buttonFactory = DefaultButtonWidgetViewFactory( DefaultButtonWidgetViewFactoryBase.Style( margins = MarginValues(top = 32f), background = StateBackground( normal = Background( fill = Fill.Solid(Color(0x6770e0FF)), shape = Shape.Rectangle(cornerRadius = corners) ), pressed = Background(...), disabled = Background(...) ), textStyle = TextStyle(color = Colors.white) ) ) } common
  • 61. DEVELOPMENT 61 code constraint(size = WidgetSize.AsParent) { val logoImage = +image(...) val emailInput = +input(...) val passwordInput = +input(...) val loginButton = +button(...) val registerButton = +button( id = Id.RegistrationButtonId, size = WidgetSize.Const(SizeSpec.WrapContent, SizeSpec.Exact(40f)), text = const("Registration".desc() as StringDesc), onTap = viewModel::onRegistrationPressed ) constraints { // ... registerButton topToBottom loginButton registerButton rightToRight root } }
  • 62. DEVELOPMENT 62 code constraint(size = WidgetSize.AsParent) { val logoImage = +image(...) val emailInput = +input(...) val passwordInput = +input(...) val loginButton = +button(...) val registerButton = +button( id = Id.RegistrationButtonId, size = WidgetSize.Const(SizeSpec.WrapContent, SizeSpec.Exact(40f)), text = const("Registration".desc() as StringDesc), onTap = viewModel::onRegistrationPressed ) constraints { // ... registerButton topToBottom loginButton registerButton rightToRight root } }
  • 63. DEVELOPMENT 63 code class LoginScreen(...) : WidgetScreen<Args.Empty>() { override fun createContentWidget() = ... object Id { ... object RegisterButtonId : ButtonWidget.Id } }
  • 64. DEVELOPMENT 64 code val loginTheme = Theme(theme) { // โ€ฆ setButtonFactory( DefaultButtonWidgetViewFactory( DefaultButtonWidgetViewFactoryBase.Style( // ... ) ), LoginScreen.Id.RegistrationButtonId ) } common
  • 65. DEVELOPMENT 65 code DefaultButtonWidgetViewFactoryBase.Style( margins = MarginValues(top = 16f), padding = platformSpecific( ios = PaddingValues(start = 16f, end = 16f), android = null ), background = StateBackground( normal = Background( fill = Fill.Solid(Colors.white), border = Border( color = Color(0xF2F2F8FF), width = 2f ), shape = Shape.Rectangle(cornerRadius = corners) ), pressed = Background(...), disabled = Background(...) ), textStyle = TextStyle(color = Color(0x777889FF)) ) common
  • 66. DEVELOPMENT 66 code DefaultButtonWidgetViewFactoryBase.Style( margins = MarginValues(top = 16f), padding = platformSpecific( ios = PaddingValues(start = 16f, end = 16f), android = null ), background = StateBackground( normal = Background( fill = Fill.Solid(Colors.white), border = Border( color = Color(0xF2F2F8FF), width = 2f ), shape = Shape.Rectangle(cornerRadius = corners) ), pressed = Background(...), disabled = Background(...) ), textStyle = TextStyle(color = Color(0x777889FF)) ) common
  • 67. DEVELOPMENT 67 code DefaultButtonWidgetViewFactoryBase.Style( margins = MarginValues(top = 16f), padding = platformSpecific( ios = PaddingValues(start = 16f, end = 16f), android = null ), background = StateBackground( normal = Background( fill = Fill.Solid(Colors.white), border = Border( color = Color(0xF2F2F8FF), width = 2f ), shape = Shape.Rectangle(cornerRadius = corners) ), pressed = Background(...), disabled = Background(...) ), textStyle = TextStyle(color = Color(0x777889FF)) ) common
  • 68. DEVELOPMENT 68 code DefaultButtonWidgetViewFactoryBase.Style( margins = MarginValues(top = 16f), padding = platformSpecific( ios = PaddingValues(start = 16f, end = 16f), android = null ), background = StateBackground( normal = Background( fill = Fill.Solid(Colors.white), border = Border( color = Color(0xF2F2F8FF), width = 2f ), shape = Shape.Rectangle(cornerRadius = corners) ), pressed = Background(...), disabled = Background(...) ), textStyle = TextStyle(color = Color(0x777889FF)) ) common
  • 76. DEVELOPMENT The basic architecture concepts: 1. compliance with platform rules 2. declare structure, not rendering 3. compile-time safety 4. reactive data handling 76 concepts
  • 77. DEVELOPMENT 77 concepts Compliance with platform rules: 1. Activity recreation on Android 2. Save instance state on Android 3. All elements are native (UI/UX)
  • 79. DEVELOPMENT Compile-time safety: 1. Type match of WidgetFactory and Widget 2. Child Widgets sizes compile-time checks 3. Widgets Id match to Widget type 4. Arguments in Screens 79 concepts
  • 80. DEVELOPMENT 80 concepts Type match of WidgetFactory and Widget val theme = Theme { textFactory = DefaultTextWidgetViewFactory() } val theme = Theme { textFactory = DefaultContainerWidgetViewFactory() }
  • 81. DEVELOPMENT 81 concepts Child Widgets sizes compile-time checks override fun createContentWidget() = with(theme) { container(size = WidgetSize.AsParent) { } } override fun createContentWidget() = with(theme) { container(size = WidgetSize.WrapContent) { } }
  • 82. DEVELOPMENT 82 concepts Child Widgets sizes compile-time checks fun createContentWidget(): Widget<WidgetSize.Const<SizeSpec.AsParent, SizeSpec.AsParent>>
  • 83. DEVELOPMENT 83 concepts Widgets Id match to Widget type setContainerFactory( DefaultContainerWidgetViewFactory(), RootContainerId ) setTextFactory( DefaultTextWidgetViewFactory(), RootContainerId ) object RootContainerId: ContainerWidget.Id
  • 85. DEVELOPMENT 85 concepts Arguments in Screens routeToScreen(ArgsScreen::class, ArgsScreen.Arg(10)) routeToScreen(ArgsScreen::class) class ArgsScreen : WidgetScreen<Args.Parcel<ArgsScreen.Arg>>()
  • 86. DEVELOPMENT Reactive data handling: 1. One-way binding via LiveData 2. Two-way binding via MutableLiveData 86 concepts
  • 87. DEVELOPMENT 87 concepts One-way binding via LiveData class TimerViewModel : ViewModel() { val text: LiveData<StringDesc> } val viewModel = getViewModel { TimerViewModel() } container(size = WidgetSize.AsParent) { center { text(size = WidgetSize.WrapContent, text = viewModel.text) } }
  • 88. DEVELOPMENT 88 concepts Two-way binding via MutableLiveData class InputViewModel : ViewModel() { val nameField: FormField<String, StringDesc> = FormField("") } val viewModel = getViewModel { InputViewModel() } input( size = WidgetSize.WidthAsParentHeightWrapContent, id = Id.NameInput, label = const(MR.strings.name_label.desc()), field = viewModel.nameField )
  • 89. DEVELOPMENT 89 concepts Two-way binding via MutableLiveData class FormField<D, E> { val data: MutableLiveData<D> val error: LiveData<E?> val isValid: LiveData<Boolean> }
  • 90. DEVELOPMENT 90 current list of widgets with(theme) { constraint(...) container(...) linear(...) scroll(...) stateful(...) tabs(...) clickable(...) image(...) text(...) input(...) button(...) list(...) collection(...) flatAlert(...) progressBar(...) singleChoice(...) switch(...) }
  • 91. DEVELOPMENT 91 current list of widgets public abstract class Widget<WS : WidgetSize> public constructor() { public abstract val size: WS public abstract fun buildView(viewFactoryContext: ViewFactoryContext): ViewBundle<WS> } public interface ViewFactory<W : Widget<out WidgetSize>> { public abstract fun <WS : WidgetSize> build(widget: W, size: WS, viewFactoryContext: ViewFactoryContext): ViewBundle<WS> }
  • 92. DEVELOPMENT โ— Widgets declare screens and structure of screens, but rendering is native โ— Jetpack Compose & SwiftUI can be used to render widgets 92 references
  • 93. DEVELOPMENT โ— 1 kotlin developer can create for both platforms โ— natively for developer and customer โ— no limits with any modi๏ฌcations (feature, screen, โ€ฆ) โ— MVP quickly โ‰  must redo natively in the future 93 bene๏ฌts
  • 94. DEVELOPMENT Whatโ€™s available today (December, 19): โ— Base widgets set โ— Base navigation patterns โ— Base styles for default widget-views โ— A set of samples โ— Actual version โ€“ 0.1.0-dev-5 94 roadmap
  • 95. DEVELOPMENT 95 December-January: โ— Implement in production project โ— Check ๏ฌ‚exibility of API to detect and ๏ฌx limits โ€“ you can help with it. Just try self and send feedback to github issues โ— Screens actions API design (show toast, alert, route) โ— More documentation and samples roadmap
  • 96. DEVELOPMENT February-March: โ— Release 0.1.0 (with ๏ฌ‚exible API for customization) โ— Codelabs and Medium posts with details of new version 96 roadmap
  • 97. DEVELOPMENT 2020 Q2-Q3: โ— New widgets โ— More variations of widgets renders โ— More styles โ— Production usage 97 roadmap
  • 98. DEVELOPMENT 98 [email protected] Try MOKO widgets today => @kotlinmpp github/icerockdev