Upgrade to Pro — share decks privately, control downloads, hide ads and more …

All stacks Kotlin

All stacks Kotlin

Guillermo Orellana

June 07, 2019
Tweet

More Decks by Guillermo Orellana

Other Decks in Programming

Transcript

  1. + =

  2. 1.2

  3. Common Module apply plugin: 'kotlin-multiplatform' apply plugin: 'kotlinx-serialization' apply plugin:

    'org.jetbrains.kotlin.native.cocoapods' apply plugin: 'co.touchlab.kotlinxcodesync' kotlin { targets { def iOSTarget = System.getenv('SDK_NAME') ?.startsWith("iphoneos") ? presets.iosArm64 : presets.iosX64 fromPreset(iOSTarget, 'ios') {
  4. Common Module compilations.test.outputKinds("FRAMEWORK") } } jvm { } js {

    compileKotlinJs { kotlinOptions.metaInfo = true kotlinOptions.sourceMap = true kotlinOptions.moduleKind = "commonjs" kotlinOptions.main = "call" } }
  5. Common Module compilations.test.outputKinds("FRAMEWORK") } } jvm { } js {

    compileKotlinJs { kotlinOptions.metaInfo = true kotlinOptions.sourceMap = true kotlinOptions.moduleKind = "commonjs" kotlinOptions.main = "call" } }
  6. Common Module sourceSets { commonMain { dependencies { api Libs.kotlinStdlibCommon

    api Libs.kotlinxCoroutinesCoreCommon api Libs.serializationRuntimeCommon api Libs.ktorClientCore api Libs.ktorClientAuth api Libs.ktorClientJson api Libs.ktorClientLogging } } commonTest { dependencies {
  7. Common Module api Libs.kotlinTestCommon } } iosMain { dependencies {

    api Libs.kotlinxCoroutinesCoreNative api Libs.serializationRuntimeNative api Libs.ktorClientIos api Libs.ktorClientJsonNative api Libs.ktorClientLoggingNative } } jvmMain { dependencies {
  8. Platform specific code actual class Storage actual constructor(val foo: String)

    { actual fun save() { println("Save") } actual fun load() { println("Load") } } Native Common expect class Storage { fun save() fun load() }
  9. •Works well if your UI is consistent across •Requires careful

    planning of API Repository Domain Logic Presenters View Binding UI Network
  10. •World of pain and fighting the frameworks •Your iOS teammates

    won't be happy •Just, why? Repository Domain Logic Presenters View Binding UI Network
  11. apply plugin: "kotlin-multiplatform" apply plugin: "com.android.application" android { compileSdkVersion 28

    defaultConfig { applicationId "es.guillermoorellan minSdkVersion 21 targetSdkVersion 28 versionCode 1
  12. org.gradle.api.ProjectConfigurationException: A problem occurred configuring project ':common' ...(150 lines of

    trace) Caused by: java.lang.RuntimeException: SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable. ...(150 lines of trace)
  13. jvmMain actual class SessionStorage { var proxy: SessionStorageProxy = object

    : SessionStorageProxy { override fun put(value: String?): Unit = TODO() override fun get(): String? = TODO() override fun clear(): Unit = TODO() } actual fun put(value: String?): Unit = proxy.put(value) actual fun get(): String? = proxy.get() actual fun clear(): Unit = proxy.clear() } interface SessionStorageProxy { fun put(value: String?) fun get(): String? fun clear() }
  14. jvmMain override fun clear(): Unit = TODO() } actual fun

    put(value: String?): Unit = proxy.put(value) actual fun get(): String? = proxy.get() actual fun clear(): Unit = proxy.clear() } interface SessionStorageProxy { fun put(value: String?) fun get(): String? fun clear() }
  15. main class AndroidSessionStorage( applicationContext: Context, private val prefs: SharedPreferences =

    applicationContext.getSharedPreferences( "prefs", Context.MODE_PRIVATE ) ) : SessionStorageProxy { @SuppressLint("ApplySharedPref") override fun put(value: String?) { prefs.edit() .putString(KEY_SESSION, value) .commit()
  16. class ProfilePresenter( private val view: ProfileView, private val getUserProfile: GetUserProfile,

    private val mainScope: CoroutineScope = MainScope() ) : CoroutineScope by mainScope { init { loadSessions() } private lateinit var _state: ProfileViewState private var state: ProfileViewState get() = _state set(value) = when (value) { is ProfileViewState.Loading -> view.showLoading() is ProfileViewState.Content ->
  17. class ProfilePresenter( private val view: ProfileView, private val getUserProfile: GetUserProfile,

    private val mainScope: CoroutineScope = MainScope() ) : CoroutineScope by mainScope { init { loadSessions() } private lateinit var _state: ProfileViewState private var state: ProfileViewState get() = _state set(value) = when (value) { is ProfileViewState.Loading -> view.showLoading() is ProfileViewState.Content ->
  18. kotlin.IllegalStateException: There is no event loop. Use runBlocking { ...

    } to start one. at 0 Keynotedex 0x000000010b170f05 kfun:kotlin.Exception.<init>(kotlin.String?)kotlin.Exception + 21 at 1 Keynotedex 0x000000010b170ec5 kfun:kotlin.RuntimeException.<init>(kotlin.String?)kotlin.RuntimeException + 21 at 2 Keynotedex 0x000000010b182925 kfun:kotlin.IllegalStateException.<init>(kotlin.String?)kotlin.IllegalStateException + 21 at 3 Keynotedex 0x000000010b19ff56 kfun:kotlinx.coroutines.takeEventLoop#internal + 294 at 4 Keynotedex 0x000000010b19fdd6 kfun:kotlinx.coroutines.DefaultExecutor.dispatch(kotlin.coroutines.CoroutineContext;kotlinx. coroutines.Runnable) + 86 at 5 Keynotedex 0x000000010b2bd004 kfun:kotlinx.coroutines.NativeMainDispatcher.dispatch#internal + 116 at 6 Keynotedex 0x000000010b19b705 kfun:kotlinx.coroutines.resumeCancellable$kotlinx-coroutines- [email protected]<#GENERIC>.(#GENERIC)Generic + 341 at 7 Keynotedex 0x000000010b266d91 kfun:kotlinx.coroutines.intrinsics.startCoroutineCancellable$kotlinx-coroutines- [email protected]<#GENERIC,#GENERIC>. (#GENERIC;kotlin.coroutines.Continuation<#GENERIC>)Generic
  19. kotlin.IllegalStateException: There is no event loop. Use runBlocking { ...

    } to start one. at 0 Keynotedex 0x000000010b170f05 kfun:kotlin.Exception.<init>(kotlin.String?)kotli n.Exception + 21 at 1 Keynotedex 0x000000010b170ec5 kfun:kotlin.RuntimeException.<init>(kotlin.String ?)kotlin.RuntimeException + 21 at 2 Keynotedex 0x000000010b182925
  20. class ProfilePresenter( private val view: ProfileView, private val getUserProfile: GetUserProfile,

    private val mainScope: CoroutineScope = CustomMainScope() ) : CoroutineScope by mainScope { init { loadSessions() } private lateinit var _state: ProfileViewState private var state: ProfileViewState get() = _state set(value) = when (value) { is ProfileViewState.Loading -> view.showLoading() is ProfileViewState.Content ->
  21. internal actual fun CustomMainScope(): CoroutineScope = CustomMainScopeImpl() internal class CustomMainScopeImpl

    : CoroutineScope { private val dispatcher = MainDispatcher() private val job = Job() private val exceptionHandler = CoroutineExceptionHandler { _, throwable -> println("${throwable.message}: ${throwable.cause}") } override val coroutineContext: CoroutineContext get() = dispatcher + job + exceptionHandler }