12/08/2018, 17:06

Kotlin trong IOS

kotlin / Native là một công cụ cho phép chúng ta biên dịch mã Kotlin cho các nền mà không có JVM hoặc một công cụ JavaScript. Ở đây, chúng ta sẽ sử dụng nó để xây dựng một mô hình Objective-C và tích hợp vào một dự án XCode. Tooling Các dự án nhiều tầng của Kotlin sử dụng công cụ Gradle như ...

kotlin / Native là một công cụ cho phép chúng ta biên dịch mã Kotlin cho các nền mà không có JVM hoặc một công cụ JavaScript. Ở đây, chúng ta sẽ sử dụng nó để xây dựng một mô hình Objective-C và tích hợp vào một dự án XCode.

  1. Tooling

Các dự án nhiều tầng của Kotlin sử dụng công cụ Gradle như build tool và JetBrains publish một plugin cho Kotlin / Native.

apply plugin: 'konan'

konan.targets = ['iphone', 'iphone_sim']

konanArtifacts {  
    framework('KotlinGameOfLife') {
        enableMultiplatform true
    }
}

dependencies {  
    expectedBy project(':common')
}

Sử dụng konanArtifacts, chúng ta có thể chỉ định loại artefact mà mình muốn compiler build. Bên cạnh đó, nó cũng hỗ trợ nhiều framework, nó sẽ tạo ra một Objective-C framework.. Sau đó, chúng ta sẽ tìm hiểu làm thế nào để có thể đưa vào một dự án XCode hiện có. Bên cạnh đó, chúng ta cũng cần phải cho phép hỗ trợ nhiều nền tảng. Tương tự như các artefact có thể chỉ định một konan.target cho một nền tảng cụ thể. Theo mặc định compiler sẽ xây dựng các artefact chỉ cho máy chủ, có nghĩa là máy tính được sử dụng để build.

Đối với bất kỳ mô đun nền tảng nào khác trong một dự án nhiều nền tảng, chúng ta cũng cần xác định sự phụ thuộc vào mô đun chung. Plugin tạo ra một vài task, trong ví dụ này compileKonanKotlinGameOfLifeIphone và compileKonanKotlinGameOfLifeIphoneSim sẽ tạo ra Objective-C framework. Vì vậy, những gì chúng ta phải làm là chạy gradle build trên dự án nhiều nền tảng để tạo ra rằng artefact, mà sẽ được đặt tại build / konan / bin.

  1. Khai báo thực tế cho IOS

Dự án đa nền tảng này implement Game of Life, nơi business logic và lớp presentation trong mô đun chung. Một phần của nó là một class GameLoop thực hiện cho mỗi nền tảng.

interface GameLoop {

    var onTick: () -> Unit

    fun startWith(intervalMs: Int)

    fun stop()

    fun isLooping(): Boolean
}

expect class GameLoopImpl() : GameLoop  

Kể từ GameLoop của chúng ta yêu cầu một số loại asynchronicity là API mà có thể sử dụng để thực hiện nó ở phía Native. Triển khai JVM sử dụng RxJava, trong khi phiên bản Javascript sử dụng cửa sổ từ môi trường trình duyệt. Đối với Kotlin / Native, có thể bạn sẽ muốn tìm hiểu về coroutines của Kotlin, nhưng tiếc là chúng chưa có trên nền tảng này. Một lựa chọn khác là dựa vào một thư viện C sử dụng tính năng tương hợp của Kotlin / Native. Tính năng này phân tích tiêu đề C và tạo ra các ràng buộc có thể được gọi từ Kotlin. May mắn là Kotlin / Native đã có các ràng buộc cho một số thư viện iOS, ví dụ như NSTimer.

package com.novoda.gol

import platform.Foundation.*

actual class GameLoopImpl : GameLoop {

    private var timer: NSTimer? = null

    override var onTick: () -> Unit = {}

    override fun startWith(intervalMs: Int) {
        timer = NSTimer(NSDate(), 0.5, true, {
            onTick()
        })
        NSRunLoop.currentRunLoop().addTimer(timer!!, NSRunLoopCommonModes)
    }

    override fun stop() {
        timer?.invalidate()
        timer = null
    }

    override fun isLooping() = timer != null

}

Hạn chế của việc sử dụng interop là chúng ta đang thiếu hỗ trợ IDE thông thường; những thứ như autocompletion không khả dụng khi sử dụng các ràng buộc như vậy.

  1. Tích hợp generated Objective-C framework vào XCode

Điều này khá dễ. Mở XCode, chọn tab General và nhấp vào + bên cạnh Embedded Libraries. Trong hộp thoại chooser chọn Add other và chọn framework tạo ra nằm trong build / konan / bin. Tiếp theo chỉ có thể nhập framework vào bất kỳ tập tin Swift và truy cập mã Kotlin của bạn.

import UIKit  
import KotlinGameOfLife

class UICell: UIButton {

    let position:KGOLPositionEntity?

    init(frame: CGRect,position:KGOLPositionEntity) {
        self.position = position
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        self.position = nil
        super.init(coder: aDecoder)
    }

}

Xin lưu ý rằng các tệp được tạo ra được đặt trước bằng tên framework, đã được chỉ định trong build.gradle, như được hiển thị ở trên. Trong ví dụ này KGOLPositionEntity được tạo ra từ PositionEntity.kt.

0