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

A tale of Multiplatform

A tale of Multiplatform

In the current wave of cross-platform solutions, Kotlin’s multiplatform is shaping up to be a unique proponent of code reuse. Unlike write once run everywhere, Multiplatform offers a unique space of reusability and formalization of code across platforms and also removes dependency on custom VMs or runtime. Through this talk, we'll go through building an app for Android and iOS and use Kotlin multiplatform for code sharing and building an abstraction layer across platforms.

Bedanta Bikash Borah

August 04, 2019
Tweet

More Decks by Bedanta Bikash Borah

Other Decks in Programming

Transcript

  1. Multiplatform A tale of @iamBedant | @_jitinsharma HISTORY KOTLIN MP

    KOTLIN ANDROID & IOS SAMPLE APP VALUE PROPOSITION ADVANTAGES DISADVANTAGES RESOURCES
  2. 0 1 1 0 0 0 O 1 1 1

    0 0 1 0 1 1 0 1 1 0 0 0 O 1 0 0 1 0 1 0 O 1
  3. START: MOV AX,DATA MOV DS,AX LEA DX,MSG1 MOV AH,9 INT

    21H MOV AH,1 INT 21H SUB AL,30H MOV NUM1,AL LEA DX,MSG2 MOV AH,9 INT 21H MOV AH,1
  4. START: MOV AX,DATA MOV DS,AX LEA DX,MSG1 MOV AH,9 INT

    21H MOV AH,1 INT 21H SUB AL,30H MOV NUM1,AL LEA DX,MSG2 MOV AH,9 INT 21H MOV AH,1 0 1 0 1 0 0 1 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 0
  5. 0 1 0 1 0 0 1 0 1 1

    1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 0
  6. 0 1 0 1 0 0 1 0 1 1

    1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 0
  7. 0 1 0 1 0 0 1 0 1 1

    1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 0
  8. START: MOV AX,DATA MOV DS,AX LEA DX,MSG1 MOV AH,9 INT

    21H MOV AH,1 INT 21H SUB AL,30H MOV NUM1,AL LEA DX,MSG2 MOV AH,9 INT 21H MOV AH,1 0 1 0 1 0 0 1 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 0 Code 1
  9. START: MOV AX,DATA MOV DS,AX LEA DX,MSG1 MOV AH,9 INT

    21H MOV AH,1 INT 21H SUB AL,30H MOV NUM1,AL LEA DX,MSG2 MOV AH,9 INT 21H MOV AH,1 START: MOV AX,DATA MOV DS,AX LEA DX,MSG1 MOV AH,9 MOV AH,1 INT 21H SUB AL,30H MOV NUM1,AL LEA DX,MSG2 MOV AH,9 INT 21H LEA DX,MSG3 Code 1 Code 2
  10. START: MOV AX,DATA MOV DS,AX LEA DX,MSG1 MOV AH,9 INT

    21H MOV AH,1 INT 21H SUB AL,30H MOV NUM1,AL LEA DX,MSG2 MOV AH,9 INT 21H MOV AH,1 0 1 0 1 0 0 1 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 0 0 1 0 1 0 0 1 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 0 START: MOV AX,DATA MOV DS,AX LEA DX,MSG1 MOV AH,9 MOV AH,1 INT 21H SUB AL,30H MOV NUM1,AL LEA DX,MSG2 MOV AH,9 INT 21H LEA DX,MSG3 Code 1 Code 2
  11. 0 1 0 1 0 0 1 0 1 1

    1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 0 0 1 0 1 0 0 1 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 0
  12. #include <stdio.h> int main() { !" printf() displays the string

    inside quotation printf("Hello, World!"); return 0; } C / C++
  13. #include <stdio.h> int main() { !" printf() displays the string

    inside quotation printf("Hello, World!"); return 0; } 0 1 0 1 0 0 1 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 0
  14. #include <stdio.h> int main() { !" printf() displays the string

    inside quotation printf("Hello, World!"); return 0; } 0 1 0 1 0 0 1 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 0 0 1 0 1 0 0 1 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 0
  15. J V M HISTORY KOTLIN MP KOTLIN ANDROID & IOS

    SAMPLE APP VALUE PROPOSITION ADVANTAGES DISADVANTAGES RESOURCES
  16. class HelloWorld { public static void main(String args[]) { System.out.println("Hello,

    World"); } } HISTORY KOTLIN MP KOTLIN ANDROID & IOS SAMPLE APP VALUE PROPOSITION ADVANTAGES DISADVANTAGES RESOURCES
  17. JVM JVM HISTORY KOTLIN MP KOTLIN ANDROID & IOS SAMPLE

    APP VALUE PROPOSITION ADVANTAGES DISADVANTAGES RESOURCES
  18. JVM JVM HISTORY KOTLIN MP KOTLIN ANDROID & IOS SAMPLE

    APP VALUE PROPOSITION ADVANTAGES DISADVANTAGES RESOURCES
  19. JVM JVM HISTORY KOTLIN MP KOTLIN ANDROID & IOS SAMPLE

    APP VALUE PROPOSITION ADVANTAGES DISADVANTAGES RESOURCES
  20. <!DOCTYPE HTML> <html> <body> <p>Before the script...</p> <script> alert( 'Hello,

    world!' ); </script> <p>...After the script.</p> </body> </html>
  21. <!DOCTYPE HTML> <html> <body> <p>Before the script...</p> <script> alert( 'Hello,

    world!' ); </script> <p>...After the script.</p> </body> </html> 0 1 0 1 0 0 1 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 0
  22. Multiplatform HISTORY KOTLIN MP KOTLIN ANDROID & IOS SAMPLE APP

    VALUE PROPOSITION ADVANTAGES DISADVANTAGES RESOURCES
  23. HISTORY KOTLIN MP KOTLIN ANDROID & IOS SAMPLE APP VALUE

    PROPOSITION ADVANTAGES DISADVANTAGES RESOURCES
  24. ▸ Create UI. ▸ Create Models. ▸ Call Api. ▸

    Parse Response. ▸ Add Business Logic. ▸ Store in DB Task
  25. Task ▸ Create UI. ▸ Create Models. ▸ Call Api.

    ▸ Parse Response. ▸ Add Business Logic. ▸ Store in DB
  26. Task ▸ Create UI. ▸ Create Models. ▸ Call Api.

    ▸ Parse Response. ▸ Add Business Logic. ▸ Store in DB
  27. Task ▸ Create UI. ▸ Create Models. ▸ Call Api.

    ▸ Parse Response. ▸ Add Business Logic. ▸ Store in DB
  28. Task ▸ Create UI. ▸ Create Models. ▸ Call Api.

    ▸ Parse Response. ▸ Add Business Logic. ▸ Store in DB
  29. Task ▸ Create UI. ▸ Create Models. ▸ Call Api.

    ▸ Parse Response. ▸ Add Business Logic. ▸ Store in DB
  30. ▸ Create Models. ▸ Parse Response. ▸ Add Business Logic.

    ▸ Call Api. ▸ Store in DB ▸ Create UI.
  31. HTTP - GET - POST - PUT - host -

    contentType - headers - Serialize - Threading
  32. private val httpClient = HttpClient { install(JsonFeature){ serializer = KotlinxSerializer().apply

    { setMapper(AllData#$class, AllData.serializer()) } } install(ExpectSuccess) } Ktor
  33. private val httpClient = HttpClient { install(JsonFeature){ serializer = KotlinxSerializer().apply

    { setMapper(AllData#$class, AllData.serializer()) } } install(ExpectSuccess) } Ktor
  34. Ktor fun getAll(userId: String, callback: (String) %& Unit) { GlobalScope.launch(NetworkDispatcher)

    { val result: String = client.get { protocol = URLProtocol.HTTPS host = "api.github.com" encodedPath = "users/$userId" } callback(result) } }
  35. Ktor fun getAll(callback: (String) %& Unit) { GlobalScope.launch(NetworkDispatcher) { val

    result: String = client.get { protocol = URLProtocol.HTTPS host = "newsapi.org/v2" encodedPath = "top-headlines?country=us" } callback(result) } }
  36. Ktor fun getAll(callback: (String) %& Unit) { GlobalScope.launch(NetworkDispatcher) { val

    result: String = client.get { protocol = URLProtocol.HTTPS host = "newsapi.org/v2" encodedPath = "top-headlines?country=us" } callback(result) } }
  37. import platform.darwin.dispatch_async import platform.darwin.dispatch_get_main_queue import platform.darwin.dispatch_queue_t internal class NsQueueDispatcher(private val

    dispatchQueue: dispatch_queue_t) : CoroutineDispatcher() { override fun dispatch(context: CoroutineContext, block: Runnable) { dispatch_async(dispatchQueue) { block.run() } } }
  38. import platform.darwin.dispatch_async import platform.darwin.dispatch_get_main_queue import platform.darwin.dispatch_queue_t internal class NsQueueDispatcher(private val

    dispatchQueue: dispatch_queue_t) : CoroutineDispatcher() { override fun dispatch(context: CoroutineContext, block: Runnable) { dispatch_async(dispatchQueue) { block.run() } } }
  39. import platform.darwin.dispatch_async import platform.darwin.dispatch_get_main_queue import platform.darwin.dispatch_queue_t internal class NsQueueDispatcher(private val

    dispatchQueue: dispatch_queue_t) : CoroutineDispatcher() { override fun dispatch(context: CoroutineContext, block: Runnable) { dispatch_async(dispatchQueue) { block.run() } } }
  40. Ktor internal expect val NetworkDispatcher: CoroutineDispatcher iOS internal actual val

    NetworkDispatcher = NsQueueDispatcher(dispatch_get_main_queue())
  41. CREATE TABLE BookmarkedArticle ( author TEXT NOT NULL, content TEXT

    NOT NULL, ); insert: INSERT INTO BookmarkedArticle (author, content) VALUES (?,?); getAll: SELECT * FROM BookmarkedArticle; BookmarkedArticle.sq
  42. CREATE TABLE BookmarkedArticle ( author TEXT NOT NULL, content TEXT

    NOT NULL, ); insert: INSERT INTO BookmarkedArticle (author, content) VALUES (?,?); getAll: SELECT * FROM BookmarkedArticle; BookmarkedArticle.sq
  43. CREATE TABLE BookmarkedArticle ( author TEXT NOT NULL, content TEXT

    NOT NULL, ); insert: INSERT INTO BookmarkedArticle (author, content) VALUES (?,?); getAll: SELECT * FROM BookmarkedArticle; BookmarkedArticle.sq
  44. class MainPresenter(private val view: MainView, private val dataRepository: DataRepository) {

    fun loadData() { view.showLoader() dataRepository.getTopHeadLines { view.displayHeadLines(it.mapToNewsArticleList()) view.hideLoader() } } fun storeArticle(newsArticle: NewsArticle) { dataRepository.saveArticle(newsArticle) } }
  45. class MainPresenter(private val view: MainView, private val dataRepository: DataRepository) {

    fun loadData() { view.showLoader() dataRepository.getTopHeadLines { view.displayHeadLines(it.mapToNewsArticleList()) view.hideLoader() } } fun storeArticle(newsArticle: NewsArticle) { dataRepository.saveArticle(newsArticle) } }
  46. class MainPresenter(private val view: MainView, private val dataRepository: DataRepository) {

    fun loadData() { view.showLoader() dataRepository.getTopHeadLines { view.displayHeadLines(it.mapToNewsArticleList()) view.hideLoader() } } fun storeArticle(newsArticle: NewsArticle) { dataRepository.saveArticle(newsArticle) } }
  47. interface MainView : BaseView { fun showLoader() fun hideLoader() fun

    displayHeadLines(headlines: List<NewsArticle>) fun displayBookmarkedHeadLines(headlines: List<NewsArticle>) }
  48. class MainActivity : AppCompatActivity(), MainView { override fun displayHeadLines(headlines: List<NewsArticle>)

    {...} override fun showLoader() {...} override fun hideLoader() {...} override fun showError(error: String) {...} private val mainPresenter by lazy { inject<MainPresenter>() } override fun onCreate(savedInstanceState: Bundle?) { mainPresenter.loadData() } }
  49. class MainActivity : AppCompatActivity(), MainView { override fun displayHeadLines(headlines: List<NewsArticle>)

    {...} override fun showLoader() {...} override fun hideLoader() {...} override fun showError(error: String) {...} private val mainPresenter by lazy { inject<MainPresenter>() } override fun onCreate(savedInstanceState: Bundle?) { mainPresenter.loadData() } }
  50. class MainActivity : AppCompatActivity(), MainView { override fun displayHeadLines(headlines: List<NewsArticle>)

    {...} override fun showLoader() {...} override fun hideLoader() {...} override fun showError(error: String) {...} private val mainPresenter by lazy { inject<MainPresenter>() } override fun onCreate(savedInstanceState: Bundle?) { mainPresenter.loadData() } }
  51. class ViewController: UIViewController , MainView { func displayHeadLines(headlines: [NewsArticle]) {...}

    func showError(error: String) {...} func showLoader() {...} func hideLoader() {...} lazy var presenter : MainPresenter = { IOSInjectorKt.injectMainPresenter() }() override func viewDidLoad() { super.viewDidLoad() presenter.loadData() } }
  52. class ViewController: UIViewController , MainView { func displayHeadLines(headlines: [NewsArticle]) {...}

    func showError(error: String) {...} func showLoader() {...} func hideLoader() {...} lazy var presenter : MainPresenter = { IOSInjectorKt.injectMainPresenter() }() override func viewDidLoad() { super.viewDidLoad() presenter.loadData() } }
  53. class ViewController: UIViewController , MainView { func displayHeadLines(headlines: [NewsArticle]) {...}

    func showError(error: String) {...} func showLoader() {...} func hideLoader() {...} lazy var presenter : MainPresenter = { IOSInjectorKt.injectMainPresenter() }() override func viewDidLoad() { super.viewDidLoad() presenter.loadData() } }
  54. HISTORY KOTLIN MP KOTLIN ANDROID & IOS SAMPLE APP VALUE

    PROPOSITION ADVANTAGES DISADVANTAGES RESOURCES ios Android web WhatÊs great
  55. - Kotlin language - No custom runtime - Platform specific

    libraries with common kotlin code HISTORY KOTLIN MP KOTLIN ANDROID & IOS SAMPLE APP VALUE PROPOSITION ADVANTAGES DISADVANTAGES RESOURCES WhatÊs great
  56. WhatÊs not great - Dependency on multiplatform libs for better

    code sharing - Still experimental HISTORY KOTLIN MP KOTLIN ANDROID & IOS SAMPLE APP VALUE PROPOSITION ADVANTAGES DISADVANTAGES RESOURCES RESOURCES
  57. Resources - https://kotlinlang.org/docs/reference/multiplatform.html - https://github.com/Kotlin/kotlinx.coroutines - https://github.com/square/sqldelight - https://github.com/Kotlin/kotlinx.serialization -

    https://ktor.io/clients/http-client/multiplatform.html - https://github.com/iamBedant/Multiplatform-Sample HISTORY KOTLIN MP KOTLIN ANDROID & IOS SAMPLE APP VALUE PROPOSITION ADVANTAGES DISADVANTAGES RESOURCES