iOS Architecture with Multiplatform

iOS Architecture with Multiplatform

58d1281770fe55a05a96600244ec8341?s=128

Kevin Galligan

October 05, 2018
Tweet

Transcript

  1. iOS Architecture with Multiplatform Kevin Galligan

  2. None
  3. Touchlab

  4. Community community!

  5. 2016

  6. Doppl

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

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

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

    Preferences) Gradle Plugin Library Format Testing Support Xcode Support J2ObjC Doppl JRE JUnit Mockito
  10. 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
  11. Fractivities Architecture Components Looper, Handler, Message Queue Retrofit SQLite
 (Room,

    etc) java.io.File Android Android Native Stuff
  12. 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
  13. no thanks

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

  16. I approve!

  17. None
  18. None
  19. still no thanks

  20. swift is life!!!

  21. the future? now

  22. reach out for repos

  23. chief hacking officer

  24. kotlin

  25. kotlin

  26. SHARED ARHICTECTURE

  27. Mobile & Web Architecture, not UI

  28. Shared UI == Failure!

  29. Shared Loigc == Computers

  30. None
  31. Web is more difficult No SQL :(

  32. Advocate for new standards AKA The Long Game

  33. mobile is MUCH simpler

  34. DROIDCON WITH KOTLIN MULTIPLATFORM

  35. Funky Code Testbed

  36. Funky Code Testbed Kotlin in 2014!

  37. Droidcon NYC & SF

  38. Droidcon NYC & SF KotlinConf fork, but use the official

    :)
  39. SQLite Knarch.db Android iOS

  40. SQLite Knarch.db SQLDelight Android iOS

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

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

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

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

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

    evenLiveData = EventLiveData(query) } fun shutDown(){ evenLiveData.removeListener() }
  46. override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

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

    eventViewModel.eventModel.evenLiveData. observe(viewLifecycleOwner, Observer { dataRefresh(it) }) return initView(inflater, container) }
  48. fun registerForChanges(proc:(sessionInfo:SessionInfo)->Unit){ eventObserver = object : Observer<SessionInfo>{ override fun onChanged(t:

    SessionInfo?){ if(t != null) proc(t) } } eventModel.evenLiveData.observeForever(eventObserver!!) }
  49. viewModel = EventViewModel(sessionId: sessionId) viewModel.registerForChanges(proc: updateUi)

  50. viewModel = EventViewModel(sessionId: sessionId) viewModel.registerForChanges(proc: updateUi) func updateUi(sessionInfo:SessionInfo) -> KotlinUnit{

    self.sessionInfo = sessionInfo styleButton() updateAllUi() return KotlinUnit() }
  51. Droidcon App Kotlin Multiplatform https://www.youtube.com/watch?v=YAeDK3Ei0Lk https://github.com/touchlab/DroidconKotlin/ Now with 0.9.3!

  52. KOTLINCONF WITH KOTLIN MULTIPLATFORM (OBV)

  53. Settings Android iOS Ktor

  54. Settings Android iOS Ktor DataRepository

  55. Settings Android iOS Ktor DataRepository SessionDetailsPresenter

  56. Settings Android iOS Ktor DataRepository SessionDetailsPresenter SessionDetailsView

  57. 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
  58. Settings Android iOS Ktor DataRepository SessionDetailsPresenter SessionDetailsView

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

  60. SHARED CODE FOR ANDROID & IOS

  61. Common

  62. Common mainThread?

  63. expect val mainThread:Boolean

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

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

    === Looper.getMainLooper() actual val mainThread: Boolean get() = NSThread.isMainThread()
  66. 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
  67. 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
  68. expect class Date { fun toLongMillis():Long } expect class DateFormatHelper(format:String){

    fun toDate(s:String):Date fun format(d:Date):String }
  69. 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) }
  70. fun initPlatformClient( staticFileLoader: (filePrefix: String, fileType: String) -> String?, analyticsCallback:

    (name: String, params: Map<String, Any>) -> Unit, clLogCallback: (s: String) -> Unit) {
  71. 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) })
  72. 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 } }
  73. Common

  74. JVM Native Common

  75. JVM Native Common Framework

  76. JVM Native Common Framework

  77. JVM Native Common Android Stuff Framework iOS Stuff

  78. JVM Native Common

  79. JVM Native Common Ktor-JVM Ktor-Native Ktor

  80. iOS Dev Info

  81. Reference Counting but not your reference counting

  82. No Reference Cycles

  83. Can call from Swift although some complaints

  84. No bitcode support yet…

  85. Threading is Different that’s for everybody

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

  88. Episode 2 soon!

  89. None
  90. IDE TOOLS & GRADLE PLUGINS

  91. ¯\_(ツ)_/¯

  92. Multiplatform IDE Intellij community and Android Studio!

  93. Multiplatform Gradle new and changing

  94. Other Plugins?

  95. LIBRARIES

  96. Stdlib not exactly a library, but…

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

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

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

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

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

  103. None
  104. None
  105. KNArch.db Kotlin Native Architecture - Database https://github.com/touchlab/knarch.db

  106. None
  107. None
  108. None
  109. Future Changes •Add multithreaded reads and WAL support •Coroutines aware

    api •CursorWindow? •Other stuff
  110. https://github.com/square/sqldelight Sqldelight A Multiplatform Delight

  111. 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 = ?;
  112. --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 ;
  113. None
  114. None
  115. SQLDelight + KNArch.db

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

  117. KNArch.threads • Temporary-ish until better tools emerge • Atomic support

    (deprecated) • ThreadLocal • LiveData
  118. None
  119. None
  120. Multiplatform Settings Really Shared Preferences https://github.com/russhwolf/multiplatform-settings

  121. 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 }
  122. Timber Multiplatform logging https://github.com/JakeWharton/timber

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

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

  125. OKIO2 MULTIPLATFORM

  126. None
  127. MY WISH LIST

  128. Stable Gradle Plugins I know, but

  129. Significant Library Examples With publishing, for all targets

  130. Multithreaded Native Coroutines If I get 1 thing for Christmas…

  131. A Reactive Library Or maybe just coroutines?

  132. Xcode Debugging? Asking a lot, but still

  133. COMMUNITY WISH LIST

  134. Mocking Library See mockk repo

  135. Dependency Injection Or service locator I guess…

  136. Build Instrumentation kapt, compiler plugins

  137. Date Support JSR 310 or similar

  138. UI Stuff Here be dragons

  139. Getting Started

  140. Build Samples Conference apps, several others

  141. Kotlin/Native Docs Learn threads and state

  142. For Libraries? Multiplatform Settings (then the rest)

  143. Join the Kotlin Slack

  144. When?

  145. Q3 Q2 Q4 Q1 Q2 2018 2019 0 .6 v0.7

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

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

    v0.8 v0.8.2 v0.9.3 Coroutines? Other Libraries Docs/tutorials
  148. Thanks for the Images! Source Links at: https://bit.ly/2O0c469

  149. kevin@touchlab.co @kpgalligan

  150. kevin@touchlab.co @kpgalligan Join the team !