KMP 앱의 Swift 코드의 Kotlin Coroutines를 사용하는 라이브러리.
KMP와 Kotlin Coroutines는 모두 훌륭하지만 함께 몇 가지 제한 사항이 있습니다.
가장 중요한 한계는 취소 지원입니다.
KOTLIN SPENTEND 기능은 완료 핸들러와 함께 함수로 Swift에 노출됩니다.
이를 통해 신속한 코드에서 쉽게 사용할 수 있지만 취소를 지원하지 않습니다.
메모
Swift 5.5는 Swift에 비동기 기능을 제공하지만이 문제를 해결하지는 않습니다.
OBJC와의 상호 운용성을 위해 완료 핸들러를 사용한 모든 함수는 비동기 기능처럼 호출 될 수 있습니다.
이는 Swift 5.5로 시작하여 Kotlin Spelend 기능이 Swift Async 기능처럼 보입니다.
그러나 그것은 단지 구문 설탕이므로 여전히 취소 지원이 없습니다.
취소 지원 외에도 OBJC는 프로토콜의 제네릭을 지원하지 않습니다.
따라서 모든 Flow 인터페이스는 일반적인 값 유형을 잃어 사용하기가 어렵습니다.
이 라이브러리는이 두 제한 사항을 모두 해결합니다.
도서관의 최신 버전은 Kotlin 버전 2.1.0 사용합니다.
이전 및/또는 미리보기 Kotlin 버전에 대한 호환성 버전도 제공됩니다.
| 버전 | 버전 접미사 | 코 틀린 | KSP | 코 루틴 |
|---|---|---|---|---|
| 최신 | 접미사 없음 | 2.1.0 | 1.0.29 | 1.9.0 |
| 1.0.0- 알파 -37 | 접미사 없음 | 2.0.21 | 1.0.25 | 1.9.0 |
| 1.0.0- 알파 -36 | 접미사 없음 | 2.0.20 | 1.0.25 | 1.9.0 |
| 1.0.0- 알파 -35 | 접미사 없음 | 2.0.20 | 1.0.24 | 1.8.1 |
| 1.0.0-Alpha-34 | 접미사 없음 | 2.0.10 | 1.0.24 | 1.8.1 |
| 1.0.0-Alpha-33 | 접미사 없음 | 2.0.0 | 1.0.24 | 1.8.1 |
| 1.0.0- 알파 -30 | 접미사 없음 | 1.9.24 | 1.0.20 | 1.8.1 |
| 1.0.0- 알파 -28 | 접미사 없음 | 1.9.23 | 1.0.20 | 1.8.0 |
| 1.0.0- 알파 -25 | 접미사 없음 | 1.9.22 | 1.0.17 | 1.8.0 |
| 1.0.0- 알파 -23 | 접미사 없음 | 1.9.21 | 1.0.16 | 1.7.3 |
| 1.0.0- 알파 -21 | 접미사 없음 | 1.9.20 | 1.0.14 | 1.7.3 |
| 1.0.0- 알파 -18 | 접미사 없음 | 1.9.10 | 1.0.13 | 1.7.3 |
| 1.0.0- 알파 -17 | 접미사 없음 | 1.9.0 | 1.0.12 | 1.7.3 |
| 1.0.0- 알파 -12 | 접미사 없음 | 1.8.22 | 1.0.11 | 1.7.2 |
| 1.0.0- 알파 -10 | 접미사 없음 | 1.8.21 | 1.0.11 | 1.7.1 |
| 1.0.0- 알파 -7 | 접미사 없음 | 1.8.20 | 1.0.10 | 1.6.4 |
몇 가지 신속한 구현 중에서 선택할 수 있습니다.
구현에 따라 iOS 9, MacOS 10.9, TVOS 9 및 WatchOS 3만큼 낮은 지원을받을 수 있습니다.
| 구현 | 스위프트 | iOS | 마코스 | TVOS | watchos |
|---|---|---|---|---|---|
| 비동기 | 5.5 | 13.0 | 10.15 | 13.0 | 6.0 |
| 결합하다 | 5.0 | 13.0 | 10.15 | 13.0 | 6.0 |
| rxswift | 5.0 | 9.0 | 10.9 | 9.0 | 3.0 |
도서관은 Kotlin 및 Swift 부분으로 구성되어 프로젝트에 추가해야합니다.
Kotlin 부분은 Maven Central에서 사용할 수 있으며 Swift 부품은 Cocoapods 또는 Swift 패키지 관리자를 통해 설치할 수 있습니다.
모든 라이브러리에 항상 동일한 버전을 사용해야합니다!
Kotlin의 경우 플러그인을 build.gradle.kts 에 추가하십시오.
plugins {
id( " com.google.devtools.ksp " ) version " 2.1.0-1.0.29 "
id( " com.rickclephas.kmp.nativecoroutines " ) version " 1.0.0-ALPHA-38 "
} 실험 @ObjCName 주석을 선택하십시오.
kotlin.sourceSets.all {
languageSettings.optIn( " kotlin.experimental.ExperimentalObjCName " )
} Swift 구현은 Swift 패키지 관리자를 통해 제공됩니다.
Package.swift 파일에 추가하기 만하면됩니다.
dependencies: [
. package ( url : " https://github.com/rickclephas/KMP-NativeCoroutines.git " , exact : " 1.0.0-ALPHA-38 " )
] ,
targets: [
. target (
name : " MyTargetName " ,
dependencies : [
// Swift Concurrency implementation
. product ( name : " KMPNativeCoroutinesAsync " , package : " KMP-NativeCoroutines " ) ,
// Combine implementation
. product ( name : " KMPNativeCoroutinesCombine " , package : " KMP-NativeCoroutines " ) ,
// RxSwift implementation
. product ( name : " KMPNativeCoroutinesRxSwift " , package : " KMP-NativeCoroutines " )
]
)
] 또는 File > Add Packages... 로 이동하여 Xcode에 추가하고 URL을 제공합니다 : https://github.com/rickclephas/KMP-NativeCoroutines.git .
메모
Swift 패키지의 버전에는 Kotlin 버전 접미사 (예 : -new-mm 또는 -kotlin-1.6.0 )가 포함되어 있지 않아야합니다.
메모
단일 구현 만 있으면 서 접미사 -spm-async , -spm-combine 및 -spm-rxswift 와 함께 SPM 특정 버전을 사용할 수도 있습니다.
Cocoapods를 사용하는 경우 Podfile 에 다음 라이브러리를 하나 이상 추가하십시오.
pod 'KMPNativeCoroutinesAsync' , '1.0.0-ALPHA-38' # Swift Concurrency implementation
pod 'KMPNativeCoroutinesCombine' , '1.0.0-ALPHA-38' # Combine implementation
pod 'KMPNativeCoroutinesRxSwift' , '1.0.0-ALPHA-38' # RxSwift implementation 메모
Cocoapod의 버전에는 Kotlin 버전 접미사 (예 : -new-mm 또는 -kotlin-1.6.0 )가 포함되어서는 안됩니다.
JetBrains Marketplace에서 IDE 플러그인을 설치하려면 다음을 얻으십시오.
Swift의 Kotlin Coroutines 코드를 사용하는 것은 Kotlin 코드를 호출하는 것만 큼 쉽습니다.
신속하게 래퍼 함수를 사용하여 비동기 함수, 비동기 스트림, 게시자 또는 관찰 가능성을 얻으십시오.
플러그인은 필요한 코드를 자동으로 생성합니다! ?
@NativeCoroutines (또는 @NativeCoroutinesState )로 Coroutines 선언에 주석을 달 수 있습니다.
Flow 속성/함수는 기본 버전을 얻습니다.
import com.rickclephas.kmp.nativecoroutines.NativeCoroutines
class Clock {
// Somewhere in your Kotlin code you define a Flow property
// and annotate it with @NativeCoroutines
@NativeCoroutines
val time : StateFlow < Long > // This can be any kind of Flow
}플러그인은이 기본 속성을 생성합니다.
import com.rickclephas.kmp.nativecoroutines.asNativeFlow
import kotlin.native.ObjCName
@ObjCName(name = " time " )
val Clock .timeNative
get() = time.asNativeFlow() 위에 정의 된 StateFlow 의 경우 플러그인 도이 값 속성을 생성합니다.
val Clock .timeValue
get() = time.value SharedFlow 의 경우 플러그인은 재생 캐시 속성을 생성합니다.
val Clock .timeReplayCache
get() = time.replayCache StateFlow 속성을 사용하여 상태를 추적합니다 (예 :보기 모델에서와 같이)?
대신 @NativeCoroutinesState 주석을 사용하십시오.
import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesState
class Clock {
// Somewhere in your Kotlin code you define a StateFlow property
// and annotate it with @NativeCoroutinesState
@NativeCoroutinesState
val time : StateFlow < Long > // This must be a StateFlow
}플러그인은 이러한 기본 속성을 생성합니다.
import com.rickclephas.kmp.nativecoroutines.asNativeFlow
import kotlin.native.ObjCName
@ObjCName(name = " time " )
val Clock .timeValue
get() = time.value
val Clock .timeFlow
get() = time.asNativeFlow()플러그인은 또한 주석이 달린 일시 중지 기능에 대한 기본 버전을 생성합니다.
import com.rickclephas.kmp.nativecoroutines.NativeCoroutines
class RandomLettersGenerator {
// Somewhere in your Kotlin code you define a suspend function
// and annotate it with @NativeCoroutines
@NativeCoroutines
suspend fun getRandomLetters (): String {
// Code to generate some random letters
}
}플러그인은이 기본 기능을 생성합니다.
import com.rickclephas.kmp.nativecoroutines.nativeSuspend
import kotlin.native.ObjCName
@ObjCName(name = " getRandomLetters " )
fun RandomLettersGenerator. getRandomLettersNative () =
nativeSuspend { getRandomLetters() }불행히도 확장 기능/속성은 Objective-C 프로토콜에서는 지원되지 않습니다.
그러나이 한계는 신속한 마법으로 "극복"될 수 있습니다.
RandomLettersGenerator 가 class 대신 interface 라고 가정하면 다음을 수행 할 수 있습니다.
import KMPNativeCoroutinesCore
extension RandomLettersGenerator {
func getRandomLetters ( ) -> NativeSuspend < String , Error , KotlinUnit > {
RandomLettersGeneratorNativeKt . getRandomLetters ( self )
}
} 일시 중단 기능 및/또는 Flow 선언이 OBJC/Swift에 노출되면 컴파일러 및 IDE 플러그인은 경고를 생성하여 KMP-NativeCoroutines 주석 중 하나를 추가하도록 상기시켜줍니다.
build.gradle.kts 파일에서 이러한 검사의 심각도를 사용자 정의 할 수 있습니다.
nativeCoroutines {
exposedSeverity = ExposedSeverity . ERROR
}또는 이러한 수표에 관심이없는 경우 비활성화하십시오.
nativeCoroutines {
exposedSeverity = ExposedSeverity . NONE
} 비동기 구현은 비동기 신속한 함수 및 AsyncSequence S를 얻는 일부 기능을 제공합니다.
asyncFunction(for:) 함수를 사용하여 기다릴 수있는 비동기 함수를 얻으십시오.
import KMPNativeCoroutinesAsync
let handle = Task {
do {
let letters = try await asyncFunction ( for : randomLettersGenerator . getRandomLetters ( ) )
print ( " Got random letters: ( letters ) " )
} catch {
print ( " Failed with error: ( error ) " )
}
}
// To cancel the suspend function just cancel the async task
handle . cancel ( ) 또는 이러한 DO 캐치가 마음에 들지 않으면 asyncResult(for:) 기능을 사용할 수 있습니다.
import KMPNativeCoroutinesAsync
let result = await asyncResult ( for : randomLettersGenerator . getRandomLetters ( ) )
if case let . success ( letters ) = result {
print ( " Got random letters: ( letters ) " )
} Unit 반환 함수의 경우 asyncError(for:) 함수도 있습니다.
import KMPNativeCoroutinesAsync
if let error = await asyncError ( for : integrationTests . returnUnit ( ) ) {
print ( " Failed with error: ( error ) " )
} Flow 의 경우 비동기 AsyncSequence asyncSequence(for:) 기능이 있습니다.
import KMPNativeCoroutinesAsync
let handle = Task {
do {
let sequence = asyncSequence ( for : randomLettersGenerator . getRandomLettersFlow ( ) )
for try await letters in sequence {
print ( " Got random letters: ( letters ) " )
}
} catch {
print ( " Failed with error: ( error ) " )
}
}
// To cancel the flow (collection) just cancel the async task
handle . cancel ( ) Combine 구현은 몇 가지 기능을 제공하여 Corootines 코드의 AnyPublisher 얻습니다.
메모
이러한 기능은 연기 된 AnyPublisher 를 만듭니다.
즉, 모든 구독은 Flow 의 수집 또는 중단 함수의 실행을 유발합니다.
메모
반환 된 Cancellable S에 대한 참조를 유지 해야합니다 . 그렇지 않으면 컬렉션이 즉시 취소됩니다.
Flow 의 경우 createPublisher(for:) 함수를 사용하십시오.
import KMPNativeCoroutinesCombine
// Create an AnyPublisher for your flow
let publisher = createPublisher ( for : clock . time )
// Now use this publisher as you would any other
let cancellable = publisher . sink { completion in
print ( " Received completion: ( completion ) " )
} receiveValue : { value in
print ( " Received value: ( value ) " )
}
// To cancel the flow (collection) just cancel the publisher
cancellable . cancel ( ) Flow 반환하는 삭제 함수에 createPublisher(for:) 함수를 사용할 수도 있습니다.
let publisher = createPublisher ( for : randomLettersGenerator . getRandomLettersFlow ( ) ) 삭제 함수의 경우 createFuture(for:) 함수를 사용해야합니다.
import KMPNativeCoroutinesCombine
// Create a Future/AnyPublisher for the suspend function
let future = createFuture ( for : randomLettersGenerator . getRandomLetters ( ) )
// Now use this future as you would any other
let cancellable = future . sink { completion in
print ( " Received completion: ( completion ) " )
} receiveValue : { value in
print ( " Received value: ( value ) " )
}
// To cancel the suspend function just cancel the future
cancellable . cancel ( ) RXSwift 구현은 코 루틴 코드에 대해 Observable 또는 Single 얻기 위해 몇 가지 기능을 제공합니다.
메모
이러한 기능은 지연된 Observable S 및 Single S를 만듭니다.
즉, 모든 구독은 Flow 의 수집 또는 중단 함수의 실행을 유발합니다.
당신의 Flow 의 경우 createObservable(for:) 함수를 사용하십시오.
import KMPNativeCoroutinesRxSwift
// Create an observable for your flow
let observable = createObservable ( for : clock . time )
// Now use this observable as you would any other
let disposable = observable . subscribe ( onNext : { value in
print ( " Received value: ( value ) " )
} , onError : { error in
print ( " Received error: ( error ) " )
} , onCompleted : {
print ( " Observable completed " )
} , onDisposed : {
print ( " Observable disposed " )
} )
// To cancel the flow (collection) just dispose the subscription
disposable . dispose ( ) Flow 반환하는 일시 중단 함수의 경우 createObservable(for:) 함수를 사용할 수도 있습니다.
let observable = createObservable ( for : randomLettersGenerator . getRandomLettersFlow ( ) ) 삭제 함수의 경우 createSingle(for:) 함수를 사용해야합니다.
import KMPNativeCoroutinesRxSwift
// Create a single for the suspend function
let single = createSingle ( for : randomLettersGenerator . getRandomLetters ( ) )
// Now use this single as you would any other
let disposable = single . subscribe ( onSuccess : { value in
print ( " Received value: ( value ) " )
} , onFailure : { error in
print ( " Received error: ( error ) " )
} , onDisposed : {
print ( " Single disposed " )
} )
// To cancel the suspend function just dispose the subscription
disposable . dispose ( ) 생성 된 Kotlin 코드를 사용자 정의 할 수있는 여러 가지 방법이 있습니다.
생성 된 속성/함수의 이름 지정이 마음에 들지 않습니까?
build.gradle.kts 파일에서 자신의 사용자 정의 접미사를 지정하십시오.
nativeCoroutines {
// The suffix used to generate the native coroutine function and property names.
suffix = " Native "
// The suffix used to generate the native coroutine file names.
// Note: defaults to the suffix value when `null`.
fileSuffix = null
// The suffix used to generate the StateFlow value property names,
// or `null` to remove the value properties.
flowValueSuffix = " Value "
// The suffix used to generate the SharedFlow replayCache property names,
// or `null` to remove the replayCache properties.
flowReplayCacheSuffix = " ReplayCache "
// The suffix used to generate the native state property names.
stateSuffix = " Value "
// The suffix used to generate the `StateFlow` flow property names,
// or `null` to remove the flow properties.
stateFlowSuffix = " Flow "
} 자세한 내용은 NativeCoroutineScope 주석으로 사용자 정의 CoroutineScope 제공 할 수 있습니다.
import com.rickclephas.kmp.nativecoroutines.NativeCoroutineScope
class Clock {
@NativeCoroutineScope
internal val coroutineScope = CoroutineScope (job + Dispatchers . Default )
}메모
사용자 정의 코 루틴 범위는 internal 또는 public 여야합니다.
CoroutineScope 제공하지 않으면 기본 범위가 사용됩니다.
internal val defaultCoroutineScope = CoroutineScope ( SupervisorJob () + Dispatchers . Default )메모
KMP-NativeCoroutines는 KMP-ObservableViewModel을 지원합니다.
ViewModel 내부의 코 루틴 (기본적으로)은 ViewModelScope 의 CoroutineScope 사용합니다.
NativeCoroutinesIgnore 주석을 사용하여 플러그인에 속성 또는 기능을 무시하도록 지시하십시오.
import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesIgnore
@NativeCoroutinesIgnore
val ignoredFlowProperty : Flow < Int >
@NativeCoroutinesIgnore
suspend fun ignoredSuspendFunction () { } 어떤 이유로 든 SWIFT에서 Kotlin 선언을 더 세분화하려면 NativeCoroutinesRefined 및 NativeCoroutinesRefinedState 주석을 사용할 수 있습니다.
이들은 플러그인에 생성 된 특성/기능에 ShouldRefineInSwift 주석을 추가하도록 지시합니다.
메모
이를 위해서는 현재 kotlin.experimental.ExperimentalObjCRefinement 에 대한 모듈 전체 옵트 인이 필요합니다.
예를 들어 Flow 속성을 AnyPublisher 속성으로 개선 할 수 있습니다.
import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesRefined
class Clock {
@NativeCoroutinesRefined
val time : StateFlow < Long >
}import KMPNativeCoroutinesCombine
extension Clock {
var time : AnyPublisher < KotlinLong , Error > {
createPublisher ( for : __time )
}
}