Slide 1

Slide 1 text

iOS Architecture with Multiplatform Kevin Galligan

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

Touchlab

Slide 4

Slide 4 text

Community community!

Slide 5

Slide 5 text

2016

Slide 6

Slide 6 text

Doppl

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

JRE
 (lang, io, util, etc) Android
 (Context, SQLiteDatabase, Threading, Shared Preferences) J2ObjC Doppl JRE JUnit Mockito

Slide 9

Slide 9 text

JRE
 (lang, io, util, etc) Android
 (Context, SQLiteDatabase, Threading, Shared Preferences) Gradle Plugin Library Format Testing Support Xcode Support J2ObjC Doppl JRE JUnit Mockito

Slide 10

Slide 10 text

JRE
 (lang, io, util, etc) Android
 (Context, SQLiteDatabase, Threading, Shared Preferences) Gradle Plugin Library Format Retrofit RxJava RxAndroid Gson Dagger SQLDelight Room DB Android Architecture etc… Testing Support Xcode Support J2ObjC Doppl JRE JUnit Mockito

Slide 11

Slide 11 text

Fractivities Architecture Components Looper, Handler, Message Queue Retrofit SQLite
 (Room, etc) java.io.File Android Android Native Stuff

Slide 12

Slide 12 text

Fractivities Architecture Components Looper, Handler, Message Queue Retrofit SQLite
 (Room, etc) java.io.File Android Android Native Stuff ViewControllers Architecture Components Looper, Handler, Message Queue Retrofit SQLite
 (Room, etc) java.io.File iOS iOS Native Stuff

Slide 13

Slide 13 text

no thanks

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

https://medium.com/@kpgalligan/the-future-of-shared-code-is-kotlin-multiplatform-9aac94517f95

Slide 16

Slide 16 text

I approve!

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

still no thanks

Slide 20

Slide 20 text

swift is life!!!

Slide 21

Slide 21 text

the future? now

Slide 22

Slide 22 text

reach out for repos

Slide 23

Slide 23 text

chief hacking officer

Slide 24

Slide 24 text

kotlin

Slide 25

Slide 25 text

kotlin

Slide 26

Slide 26 text

SHARED ARHICTECTURE

Slide 27

Slide 27 text

Mobile & Web Architecture, not UI

Slide 28

Slide 28 text

Shared UI == Failure!

Slide 29

Slide 29 text

Shared Loigc == Computers

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

Web is more difficult No SQL :(

Slide 32

Slide 32 text

Advocate for new standards AKA The Long Game

Slide 33

Slide 33 text

mobile is MUCH simpler

Slide 34

Slide 34 text

DROIDCON WITH KOTLIN MULTIPLATFORM

Slide 35

Slide 35 text

Funky Code Testbed

Slide 36

Slide 36 text

Funky Code Testbed Kotlin in 2014!

Slide 37

Slide 37 text

Droidcon NYC & SF

Slide 38

Slide 38 text

Droidcon NYC & SF KotlinConf fork, but use the official :)

Slide 39

Slide 39 text

SQLite Knarch.db Android iOS

Slide 40

Slide 40 text

SQLite Knarch.db SQLDelight Android iOS

Slide 41

Slide 41 text

SQLite Knarch.db SQLDelight Logic! Reactive (LiveData) Android iOS

Slide 42

Slide 42 text

SQLite Knarch.db SQLDelight Logic! Reactive (LiveData) Android iOS

Slide 43

Slide 43 text

SQLite Knarch.db SQLDelight MP Settings Logic! Reactive (LiveData) Android iOS

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

viewModel = EventViewModel(sessionId: sessionId) viewModel.registerForChanges(proc: updateUi)

Slide 50

Slide 50 text

viewModel = EventViewModel(sessionId: sessionId) viewModel.registerForChanges(proc: updateUi) func updateUi(sessionInfo:SessionInfo) -> KotlinUnit{ self.sessionInfo = sessionInfo styleButton() updateAllUi() return KotlinUnit() }

Slide 51

Slide 51 text

Droidcon App Kotlin Multiplatform https://www.youtube.com/watch?v=YAeDK3Ei0Lk https://github.com/touchlab/DroidconKotlin/ Now with 0.9.3!

Slide 52

Slide 52 text

KOTLINCONF WITH KOTLIN MULTIPLATFORM (OBV)

Slide 53

Slide 53 text

Settings Android iOS Ktor

Slide 54

Slide 54 text

Settings Android iOS Ktor DataRepository

Slide 55

Slide 55 text

Settings Android iOS Ktor DataRepository SessionDetailsPresenter

Slide 56

Slide 56 text

Settings Android iOS Ktor DataRepository SessionDetailsPresenter SessionDetailsView

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

Settings Android iOS Ktor DataRepository SessionDetailsPresenter SessionDetailsView

Slide 59

Slide 59 text

KotlinConf App https://github.com/JetBrains/kotlinconf-app

Slide 60

Slide 60 text

SHARED CODE FOR ANDROID & IOS

Slide 61

Slide 61 text

Common

Slide 62

Slide 62 text

Common mainThread?

Slide 63

Slide 63 text

expect val mainThread:Boolean

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

expect fun currentTimeMillis():Long expect fun backgroundTask(backJob:()-> B, mainJob:(B) -> Unit) expect fun backgroundTask(backJob:()->Unit) expect fun networkBackgroundTask(backJob:()->Unit) expect fun initContext():NativeOpenHelperFactory expect fun goFreeze(a:T):T expect fun T.freeze2(): T expect fun simpleGet(url:String):String expect fun logException(t:Throwable) expect fun settingsFactory(): Settings.Factory expect fun createUuid():String

Slide 68

Slide 68 text

expect class Date { fun toLongMillis():Long } expect class DateFormatHelper(format:String){ fun toDate(s:String):Date fun format(d:Date):String }

Slide 69

Slide 69 text

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(){ 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) }

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

fun initPlatformClient( staticFileLoader: (filePrefix: String, fileType: String) -> String?, analyticsCallback: (name: String, params: Map) -> Unit, clLogCallback: (s: String) -> Unit) { AppContext.initPlatformClient ({filePrefix, fileType -> loadAsset("${filePrefix}.${fileType}")}, {name: String, params: Map -> val event = CustomEvent(name) //Loop Answers.getInstance().logCustom(event) }, { Log.w("MainApp", it) })

Slide 72

Slide 72 text

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 } }

Slide 73

Slide 73 text

Common

Slide 74

Slide 74 text

JVM Native Common

Slide 75

Slide 75 text

JVM Native Common Framework

Slide 76

Slide 76 text

JVM Native Common Framework

Slide 77

Slide 77 text

JVM Native Common Android Stuff Framework iOS Stuff

Slide 78

Slide 78 text

JVM Native Common

Slide 79

Slide 79 text

JVM Native Common Ktor-JVM Ktor-Native Ktor

Slide 80

Slide 80 text

iOS Dev Info

Slide 81

Slide 81 text

Reference Counting but not your reference counting

Slide 82

Slide 82 text

No Reference Cycles

Slide 83

Slide 83 text

Can call from Swift although some complaints

Slide 84

Slide 84 text

No bitcode support yet…

Slide 85

Slide 85 text

Threading is Different that’s for everybody

Slide 86

Slide 86 text

No content

Slide 87

Slide 87 text

https://medium.com/@kpgalligan/kotlin-native-stranger-threads-c0cf0e0fb847

Slide 88

Slide 88 text

Episode 2 soon!

Slide 89

Slide 89 text

No content

Slide 90

Slide 90 text

IDE TOOLS & GRADLE PLUGINS

Slide 91

Slide 91 text

¯\_(ツ)_/¯

Slide 92

Slide 92 text

Multiplatform IDE Intellij community and Android Studio!

Slide 93

Slide 93 text

Multiplatform Gradle new and changing

Slide 94

Slide 94 text

Other Plugins?

Slide 95

Slide 95 text

LIBRARIES

Slide 96

Slide 96 text

Stdlib not exactly a library, but…

Slide 97

Slide 97 text

Kotlin/Native Runtime also not a library, still… https://github.com/JetBrains/kotlin-native

Slide 98

Slide 98 text

• kotlin/native/concurrent/Freezing.kt • kotlin/native/Annotations.kt • kotlin/native/concurrent/Worker.kt (maybe)

Slide 99

Slide 99 text

No content

Slide 100

Slide 100 text

https://github.com/ktorio/ktor Ktor asynchronous server and client(s)

Slide 101

Slide 101 text

Kotlinx.serialization cross-platform / multi-format reflectionless serialization https://github.com/Kotlin/kotlinx.serialization

Slide 102

Slide 102 text

Kotlinx.coroutines makes coroutines usable https://github.com/Kotlin/kotlinx.coroutines

Slide 103

Slide 103 text

No content

Slide 104

Slide 104 text

No content

Slide 105

Slide 105 text

KNArch.db Kotlin Native Architecture - Database https://github.com/touchlab/knarch.db

Slide 106

Slide 106 text

No content

Slide 107

Slide 107 text

No content

Slide 108

Slide 108 text

No content

Slide 109

Slide 109 text

Future Changes •Add multithreaded reads and WAL support •Coroutines aware api •CursorWindow? •Other stuff

Slide 110

Slide 110 text

https://github.com/square/sqldelight Sqldelight A Multiplatform Delight

Slide 111

Slide 111 text

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 = ?;

Slide 112

Slide 112 text

--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 ;

Slide 113

Slide 113 text

No content

Slide 114

Slide 114 text

No content

Slide 115

Slide 115 text

SQLDelight + KNArch.db

Slide 116

Slide 116 text

KNArch.threads Kotlin Native Architecture - Threads https://github.com/touchlab/knarch.threads

Slide 117

Slide 117 text

KNArch.threads • Temporary-ish until better tools emerge • Atomic support (deprecated) • ThreadLocal • LiveData

Slide 118

Slide 118 text

No content

Slide 119

Slide 119 text

No content

Slide 120

Slide 120 text

Multiplatform Settings Really Shared Preferences https://github.com/russhwolf/multiplatform-settings

Slide 121

Slide 121 text

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 }

Slide 122

Slide 122 text

Timber Multiplatform logging https://github.com/JakeWharton/timber

Slide 123

Slide 123 text

Atomic Fu Atomic operation support https://github.com/Kotlin/kotlinx.atomicfu

Slide 124

Slide 124 text

Kotlinx.io multiplatform I/O library https://github.com/Kotlin/kotlinx-io

Slide 125

Slide 125 text

OKIO2 MULTIPLATFORM

Slide 126

Slide 126 text

No content

Slide 127

Slide 127 text

MY WISH LIST

Slide 128

Slide 128 text

Stable Gradle Plugins I know, but

Slide 129

Slide 129 text

Significant Library Examples With publishing, for all targets

Slide 130

Slide 130 text

Multithreaded Native Coroutines If I get 1 thing for Christmas…

Slide 131

Slide 131 text

A Reactive Library Or maybe just coroutines?

Slide 132

Slide 132 text

Xcode Debugging? Asking a lot, but still

Slide 133

Slide 133 text

COMMUNITY WISH LIST

Slide 134

Slide 134 text

Mocking Library See mockk repo

Slide 135

Slide 135 text

Dependency Injection Or service locator I guess…

Slide 136

Slide 136 text

Build Instrumentation kapt, compiler plugins

Slide 137

Slide 137 text

Date Support JSR 310 or similar

Slide 138

Slide 138 text

UI Stuff Here be dragons

Slide 139

Slide 139 text

Getting Started

Slide 140

Slide 140 text

Build Samples Conference apps, several others

Slide 141

Slide 141 text

Kotlin/Native Docs Learn threads and state

Slide 142

Slide 142 text

For Libraries? Multiplatform Settings (then the rest)

Slide 143

Slide 143 text

Join the Kotlin Slack

Slide 144

Slide 144 text

When?

Slide 145

Slide 145 text

Q3 Q2 Q4 Q1 Q2 2018 2019 0 .6 v0.7 v0.8 v0.8.2 v0.9 Coroutines (and other libs)

Slide 146

Slide 146 text

Q3 Q2 Q4 Q1 Q2 2018 2019 0 .6 v0.7 v0.8 v0.8.2 v0.9.3 Coroutines?

Slide 147

Slide 147 text

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

Slide 148

Slide 148 text

Thanks for the Images! Source Links at: https://bit.ly/2O0c469

Slide 149

Slide 149 text

[email protected] @kpgalligan

Slide 150

Slide 150 text

[email protected] @kpgalligan Join the team !