0% found this document useful (0 votes)
27 views150 pages

2 - Ios Architecture

The document discusses the architecture of iOS and Android applications using Kotlin Multiplatform, highlighting the importance of shared logic over shared UI. It emphasizes the use of various libraries and tools such as Ktor, SQLDelight, and Kotlinx for building cross-platform applications. Additionally, it outlines future changes and community wishes for improving Kotlin Multiplatform development.

Uploaded by

crubilar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
27 views150 pages

2 - Ios Architecture

The document discusses the architecture of iOS and Android applications using Kotlin Multiplatform, highlighting the importance of shared logic over shared UI. It emphasizes the use of various libraries and tools such as Ktor, SQLDelight, and Kotlinx for building cross-platform applications. Additionally, it outlines future changes and community wishes for improving Kotlin Multiplatform development.

Uploaded by

crubilar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 150

iOS Architecture with Multiplatform

Kevin Galligan
Touchlab
community!
Community
2016
Doppl
J2ObjC

JUnit Mockito

JRE
JRE
(lang, io, util, etc)
J2ObjC

JUnit Mockito

JRE
JRE
(lang, io, util, etc) Android
(Context, SQLiteDatabase, Threading,
Shared Preferences)

Doppl
J2ObjC

JUnit Mockito

JRE
JRE
(lang, io, util, etc) Android
(Context, SQLiteDatabase, Threading,
Shared Preferences)

Gradle Plugin Library Format

Testing Support Xcode Support

Doppl
J2ObjC

JUnit Mockito

JRE
JRE
(lang, io, util, etc) Android
(Context, SQLiteDatabase, Threading,
Shared Preferences)

Retrofit Gson Room DB


Gradle Plugin Library Format
Android
RxJava Dagger Architecture

Testing Support Xcode Support


RxAndroid SQLDelight etc…

Doppl
Fractivities

Architecture
Components

Looper,
Android Native Handler,
Message Retrofit
Stuff Queue

SQLite
java.io.File
(Room, etc)

Android
Fractivities ViewControllers

Architecture Architecture
Components Components

Looper, Looper,
Android Native Handler, Handler,
Message Retrofit Message Retrofit iOS Native Stuff
Stuff Queue Queue

SQLite SQLite
java.io.File java.io.File
(Room, etc) (Room, etc)

Android iOS
no thanks
https://medium.com/@kpgalligan/the-future-of-shared-code-is-kotlin-multiplatform-9aac94517f95
I approve!
still no thanks
swift is life!!!
the future?

now
reach out for repos
chief hacking officer
kotlin
kotlin
SHARED ARHICTECTURE
Mobile & Web
Architecture, not UI
Shared UI == Failure!
Shared Loigc == Computers
Web is more difficult
No SQL :(
Advocate for new standards
AKA The Long Game
mobile is MUCH simpler
DROIDCON
WITH

KOTLIN MULTIPLATFORM
Funky Code Testbed
Funky Code Testbed
Kotlin in 2014!
Droidcon NYC & SF
Droidcon NYC & SF
KotlinConf fork, but use the official :)
Android iOS

SQLite
Knarch.db
Android iOS

SQLite SQLDelight
Knarch.db
Android iOS

Reactive (LiveData)

Logic!

SQLite SQLDelight
Knarch.db
Android iOS

Reactive (LiveData)

Logic!

SQLite SQLDelight
Knarch.db
Android iOS

Reactive (LiveData)

Logic!

SQLite SQLDelight MP Settings


Knarch.db
val evenLiveData:EventLiveData

init {
val query = goFreeze(AppContext.dbHelper.
queryWrapper.sessionQueries.
sessionById(sessionId))
evenLiveData = EventLiveData(query)
}

fun shutDown(){
evenLiveData.removeListener()
}
val evenLiveData:EventLiveData

init {
val query = goFreeze(AppContext.dbHelper.
queryWrapper.sessionQueries.
sessionById(sessionId))
evenLiveData = EventLiveData(query)
}

fun shutDown(){
evenLiveData.removeListener()
}
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?, savedInstanceState: Bundle?): View?
{
eventViewModel.eventModel.evenLiveData.
observe(viewLifecycleOwner,
Observer { dataRefresh(it) })

return initView(inflater, container)


}
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?, savedInstanceState: Bundle?): View?
{
eventViewModel.eventModel.evenLiveData.
observe(viewLifecycleOwner,
Observer { dataRefresh(it) })

return initView(inflater, container)


}
fun registerForChanges(proc:(sessionInfo:SessionInfo)->Unit){
eventObserver = object : Observer<SessionInfo>{
override fun onChanged(t: SessionInfo?){
if(t != null)
proc(t)
}
}

eventModel.evenLiveData.observeForever(eventObserver!!)
}
viewModel = EventViewModel(sessionId: sessionId)
viewModel.registerForChanges(proc: updateUi)
viewModel = EventViewModel(sessionId: sessionId)
viewModel.registerForChanges(proc: updateUi)

func updateUi(sessionInfo:SessionInfo) -> KotlinUnit{


self.sessionInfo = sessionInfo
styleButton()
updateAllUi()
return KotlinUnit()
}
No
w
wi
th
0
.9
.3
!
Droidcon App Kotlin Multiplatform
https://www.youtube.com/watch?v=YAeDK3Ei0Lk
https://github.com/touchlab/DroidconKotlin/
KOTLINCONF
WITH

KOTLIN MULTIPLATFORM
(OBV)
Android iOS

Settings Ktor
Android iOS

DataRepository

Settings Ktor
Android iOS

SessionDetailsPresenter

DataRepository

Settings Ktor
Android iOS

SessionDetailsView

SessionDetailsPresenter

DataRepository

Settings Ktor
interface SessionDetailsView : BaseView {
fun updateView(isFavorite: Boolean, session: SessionModel)
fun setupRatingButtons(rating: SessionRating?)
fun setRatingClickable(clickable: Boolean)
}

override fun updateView(isFavorite: Boolean, session: SessionModel)


func updateView(isFavorite: Bool, session: SessionModel) { {
collapsingToolbar.title = session.title
titleLabel.text = session.title
speakersTextView.text = session.speakers.joinToString(separator = ", ")
{ it.fullName }
let startsAt = session.startsAt
let endsAt = session.endsAt
timeTextView.text = session.timeString
detailsTextView.text = listOfNotNull(session.roomText,
if (startsAt != nil && endsAt != nil) {
session.category).joinToString(", ")
timeLabel.text = KotlinPair(first: startsAt, second:
descriptionTextView.text
endsAt).toReadableString() = session.descriptionText
}
val online = context?.let { it.isConnected?.and(!it.isAirplaneModeOn) } ?:
false let image = UIImage(named: isFavorite ? "star_full" : "star_empty")!
for favoriteButton.image
(button in listOf(votingButtonsLayout,
= image favoriteButton)) {
Android iOS

SessionDetailsView

SessionDetailsPresenter

DataRepository

Settings Ktor
KotlinConf App
https://github.com/JetBrains/kotlinconf-app
SHARED CODE
FOR

ANDROID & IOS


Common
Common mainThread?
expect val mainThread:Boolean
expect val mainThread:Boolean

actual val mainThread: Boolean


get() = Looper.myLooper() === Looper.getMainLooper()
expect val mainThread:Boolean

actual val mainThread: Boolean


get() = Looper.myLooper() === Looper.getMainLooper()

actual val mainThread: Boolean


get() = NSThread.isMainThread()
expect val mainThread:Boolean

actual val mainThread: Boolean


get() = Looper.myLooper() === Looper.getMainLooper()

actual val mainThread: Boolean


get() = NSThread.isMainThread()

actual val mainThread: Boolean = true


expect fun currentTimeMillis():Long

expect fun <B> backgroundTask(backJob:()-> B, mainJob:(B) -> Unit)

expect fun backgroundTask(backJob:()->Unit)

expect fun networkBackgroundTask(backJob:()->Unit)

expect fun initContext():NativeOpenHelperFactory

expect fun <T> goFreeze(a:T):T

expect fun <T> T.freeze2(): T

expect fun simpleGet(url:String):String

expect fun logException(t:Throwable)

expect fun settingsFactory(): Settings.Factory

expect fun createUuid():String


expect class Date {
fun toLongMillis():Long
}

expect class DateFormatHelper(format:String){


fun toDate(s:String):Date
fun format(d:Date):String
}
actual class Date(val date:java.util.Date) {
actual fun toLongMillis(): Long = date.time
}

actual class DateFormatHelper actual constructor(format: String) {


val dateFormatter = object : ThreadLocal<DateFormat>(){
override fun initialValue(): DateFormat = SimpleDateFormat(format)
}

actual fun toDate(s: String): Date = Date(dateFormatter.get()!!.parse(s))

actual fun format(d: Date): String = dateFormatter.get()!!.format(d.date)


}
fun initPlatformClient(
staticFileLoader: (filePrefix: String, fileType: String) -> String?,
analyticsCallback: (name: String, params: Map<String, Any>) -> Unit,
clLogCallback: (s: String) -> Unit) {
fun initPlatformClient(
staticFileLoader: (filePrefix: String, fileType: String) -> String?,
analyticsCallback: (name: String, params: Map<String, Any>) -> Unit,
clLogCallback: (s: String) -> Unit) {

AppContext.initPlatformClient ({filePrefix, fileType ->


loadAsset("${filePrefix}.${fileType}")},
{name: String, params: Map<String, Any> ->

val event = CustomEvent(name)


//Loop
Answers.getInstance().logCustom(event)
},
{ Log.w("MainApp", it) })
let appContext = AppContext()
appContext.doInitPlatformClient(staticFileLoader: loadAsset,
analyticsCallback:
analyticsCallback,
clLogCallback: csLog)

func loadAsset(filePrefix:String, fileType:String) -> String?{


do{
let bundleFile = Bundle.main.path(forResource: filePrefix,
ofType: fileType)
return try String(contentsOfFile: bundleFile!)
} catch {
return nil
}
}
Common
JVM Native

Common
Framework

JVM Native

Common
Framework

JVM Native

Common
Framework

JVM Native

Android
iOS Stuff
Stuff

Common
JVM Native

Common
JVM Native

Common

Ktor-JVM Ktor-Native

Ktor
📱iOS Dev Info
Reference Counting
but not your reference counting
No Reference Cycles
Can call from Swift
although some complaints
No bitcode support
yet…
Threading is Different
that’s for everybody
https://medium.com/@kpgalligan/kotlin-native-stranger-threads-c0cf0e0fb847
o n!
so
e2
od
is
Ep
IDE TOOLS
&

GRADLE PLUGINS
¯\_(ツ)_/¯
Multiplatform IDE
Intellij community and Android Studio!
Multiplatform Gradle
new and changing
Other Plugins?
LIBRARIES
Stdlib
not exactly a library, but…
Kotlin/Native Runtime
also not a library, still…
https://github.com/JetBrains/kotlin-native
• kotlin/native/concurrent/Freezing.kt
• kotlin/native/Annotations.kt
• kotlin/native/concurrent/Worker.kt (maybe)
Ktor
asynchronous server and client(s)
https://github.com/ktorio/ktor
Kotlinx.serialization
cross-platform / multi-format reflectionless serialization
https://github.com/Kotlin/kotlinx.serialization
Kotlinx.coroutines
makes coroutines usable
https://github.com/Kotlin/kotlinx.coroutines
KNArch.db
Kotlin Native Architecture - Database
https://github.com/touchlab/knarch.db
Future Changes

• Add multithreaded reads and WAL support


• Coroutines aware api
• CursorWindow?
• Other stuff
Sqldelight
A Multiplatform Delight
https://github.com/square/sqldelight
CREATE TABLE session(
id TEXT NOT NULL PRIMARY KEY,
title TEXT NOT NULL,
description TEXT NOT NULL,
startsAt TEXT AS Date NOT NULL,
endsAt TEXT AS Date NOT NULL,
serviceSession INTEGER NOT NULL DEFAULT 0,
rsvp INTEGER NOT NULL DEFAULT 0,
roomId INTEGER,
FOREIGN KEY (roomId) REFERENCES room(id)
);

insert:
INSERT INTO session(id, title, description, startsAt, endsAt, serviceSession, roomId)
VALUES (?,?,?,?,?,?,?)
;

update:
UPDATE session SET title = ?, description = ?, startsAt = ?,
endsAt = ?, serviceSession = ?, roomId = ?, rsvp = ?
WHERE id = ?;

deleteById:
DELETE FROM session WHERE id = ?;

allSessions:
SELECT * FROM session;

sessionById:
SELECT * FROM session WHERE id = ?;
--Special query for schedule view
sessionWithRoom:
SELECT session.id, session.title, session.description, session.startsAt,
session.endsAt,
session.serviceSession, session.rsvp, session.roomId, room.name AS roomName,
speakers.allNames
FROM session
LEFT JOIN (
SELECT sessionId,group_concat(fullName, ', ') AS allNames
FROM sessionSpeaker
JOIN userAccount ON userAccount.id = sessionSpeaker.userAccountId
GROUP BY sessionId
) AS speakers ON speakers.sessionId = session.id
JOIN room ON session.roomId = room.id
;
SQLDelight + KNArch.db
KNArch.threads
Kotlin Native Architecture - Threads
https://github.com/touchlab/knarch.threads
KNArch.threads

• Temporary-ish until better tools emerge


• Atomic support (deprecated)
• ThreadLocal
• LiveData
Multiplatform Settings
Really Shared Preferences
https://github.com/russhwolf/multiplatform-settings
public expect class PlatformSettings : Settings {

/**
* A factory that can produce [Settings] instances.
*/
public class Factory : Settings.Factory {
public override fun create(name: String?): Settings
}

public override fun clear()


public override fun remove(key: String)
public override fun hasKey(key: String): Boolean
public override fun putInt(key: String, value: Int)
public override fun getInt(key: String, defaultValue: Int): Int
public override fun putLong(key: String, value: Long)
public override fun getLong(key: String, defaultValue: Long): Long
public override fun putString(key: String, value: String)
public override fun getString(key: String, defaultValue: String): String
public override fun putFloat(key: String, value: Float)
public override fun getFloat(key: String, defaultValue: Float): Float
public override fun putDouble(key: String, value: Double)
public override fun getDouble(key: String, defaultValue: Double): Double
public override fun putBoolean(key: String, value: Boolean)
public override fun getBoolean(key: String, defaultValue: Boolean): Boolean
}
Timber
Multiplatform logging
https://github.com/JakeWharton/timber
Atomic Fu
Atomic operation support
https://github.com/Kotlin/kotlinx.atomicfu
Kotlinx.io
multiplatform I/O library
https://github.com/Kotlin/kotlinx-io
OKIO2 MULTIPLATFORM
MY WISH LIST
Stable Gradle Plugins
I know, but 😢
Significant Library Examples
With publishing, for all targets
Multithreaded Native Coroutines
If I get 1 thing for Christmas…
A Reactive Library
Or maybe just coroutines?
Xcode Debugging?
Asking a lot, but still
COMMUNITY WISH LIST
Mocking Library
See mockk repo
Dependency Injection
Or service locator I guess…
Build Instrumentation
kapt, compiler plugins
Date Support
JSR 310 or similar
UI Stuff
Here be dragons
Getting Started
Build Samples
Conference apps, several others
Kotlin/Native Docs
Learn threads and state
For Libraries?
Multiplatform Settings (then the rest)
Join the Kotlin Slack
When?
v0.9
Coroutines
(and other libs)

v0.7 v0.8.2
0 .6 v0.8

Q2 Q3 Q4 Q1 Q2

2018 2019
v0.9.3
Coroutines?

v0.7 v0.8.2
0 .6 v0.8

Q2 Q3 Q4 Q1 Q2

2018 2019
v0.9.3
Coroutines?
Other Libraries
Docs/tutorials
v0.7 v0.8.2
0 .6 v0.8

Q2 Q3 Q4 Q1 Q2

2018 2019
Thanks for the Images!
Source Links at: https://bit.ly/2O0c469
[email protected]

@kpgalligan
Jo
in
th
et
ea
m
!
[email protected]

@kpgalligan

You might also like