Skip to content

Commit

Permalink
Merge branch 'master' into feature/GH-42-swift-to-kotlin-wrappers
Browse files Browse the repository at this point in the history
  • Loading branch information
rickclephas committed Nov 18, 2023
2 parents 6384253 + 22d8245 commit 30f28cf
Show file tree
Hide file tree
Showing 59 changed files with 1,153 additions and 477 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/release-kotlin-preview.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ on:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-Beta'
- 'v[0-9]+.[0-9]+.[0-9]+-ALPHA-[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-Beta'
- 'v[0-9]+.[0-9]+.[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-Beta[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-ALPHA-[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-Beta[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-RC'
- 'v[0-9]+.[0-9]+.[0-9]+-ALPHA-[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-RC'
- 'v[0-9]+.[0-9]+.[0-9]+-kotlin-[0-9]+.[0-9]+.[0-9]+-RC[0-9]+'
Expand Down Expand Up @@ -33,3 +35,10 @@ jobs:
SIGNING_SECRET_KEY: ${{ secrets.SIGNING_SECRET_KEY }}
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
- name: Publish IDEA plugin
run: ./gradlew publishPlugin
env:
IDEA_CERTIFICATE_CHAIN: ${{ secrets.IDEA_CERTIFICATE_CHAIN }}
IDEA_PRIVATE_KEY: ${{ secrets.IDEA_PRIVATE_KEY }}
IDEA_PRIVATE_KEY_PASSWORD: ${{ secrets.IDEA_PRIVATE_KEY_PASSWORD }}
IDEA_PUBLISH_TOKEN: ${{ secrets.IDEA_PUBLISH_TOKEN }}
14 changes: 7 additions & 7 deletions .github/workflows/release-kotlin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ jobs:
SIGNING_SECRET_KEY: ${{ secrets.SIGNING_SECRET_KEY }}
GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }}
GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }}
# - name: Publish IDEA plugin
# run: ./gradlew publishPlugin
# env:
# IDEA_CERTIFICATE_CHAIN: ${{ secrets.IDEA_CERTIFICATE_CHAIN }}
# IDEA_PRIVATE_KEY: ${{ secrets.IDEA_PRIVATE_KEY }}
# IDEA_PRIVATE_KEY_PASSWORD: ${{ secrets.IDEA_PRIVATE_KEY_PASSWORD }}
# IDEA_PUBLISH_TOKEN: ${{ secrets.IDEA_PUBLISH_TOKEN }}
- name: Publish IDEA plugin
run: ./gradlew publishPlugin
env:
IDEA_CERTIFICATE_CHAIN: ${{ secrets.IDEA_CERTIFICATE_CHAIN }}
IDEA_PRIVATE_KEY: ${{ secrets.IDEA_PRIVATE_KEY }}
IDEA_PRIVATE_KEY_PASSWORD: ${{ secrets.IDEA_PRIVATE_KEY_PASSWORD }}
IDEA_PUBLISH_TOKEN: ${{ secrets.IDEA_PUBLISH_TOKEN }}
2 changes: 1 addition & 1 deletion .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion KMPNativeCoroutinesAsync.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'KMPNativeCoroutinesAsync'
s.version = '1.0.0-ALPHA-17'
s.version = '1.0.0-ALPHA-21'
s.summary = 'Swift library for Kotlin Coroutines with Swift Async/Await'

s.homepage = 'https://github.com/rickclephas/KMP-NativeCoroutines'
Expand Down
2 changes: 1 addition & 1 deletion KMPNativeCoroutinesCombine.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'KMPNativeCoroutinesCombine'
s.version = '1.0.0-ALPHA-17'
s.version = '1.0.0-ALPHA-21'
s.summary = 'Swift library for Kotlin Coroutines with Combine'

s.homepage = 'https://github.com/rickclephas/KMP-NativeCoroutines'
Expand Down
2 changes: 1 addition & 1 deletion KMPNativeCoroutinesCore.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'KMPNativeCoroutinesCore'
s.version = '1.0.0-ALPHA-17'
s.version = '1.0.0-ALPHA-21'
s.summary = 'Swift library for Kotlin Coroutines'

s.homepage = 'https://github.com/rickclephas/KMP-NativeCoroutines'
Expand Down
2 changes: 1 addition & 1 deletion KMPNativeCoroutinesRxSwift.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'KMPNativeCoroutinesRxSwift'
s.version = '1.0.0-ALPHA-17'
s.version = '1.0.0-ALPHA-21'
s.summary = 'Swift library for Kotlin Coroutines with RxSwift'

s.homepage = 'https://github.com/rickclephas/KMP-NativeCoroutines'
Expand Down
9 changes: 6 additions & 3 deletions MIGRATING_TO_V1.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

The 1.0 release will bring some improvements that require some changes in your code 😅.

> **Note**: make sure to use the same library versions for your Kotlin and Swift code!
> [!NOTE]
> Make sure to use the same library versions for your Kotlin and Swift code!
## KSP

Expand All @@ -26,7 +27,8 @@ To tell the plugin what declarations should be refined for ObjC/Swift you'll nee
suspend fun getRandomLetters(): String = ""
```

> **Note**: error messages and IDE support are currently limited.
> [!NOTE]
> Error messages and IDE support are currently limited.
> Please track [#81](https://github.com/rickclephas/KMP-NativeCoroutines/issues/81) and
> [#82](https://github.com/rickclephas/KMP-NativeCoroutines/issues/82) for improved error messages.
Expand Down Expand Up @@ -62,7 +64,8 @@ The value and replay cache property names also drop the `Native` suffix:
+ let replayCache = clock.timeReplayCache
```

> **Note**: you can now customize the value and replay cache suffixes,
> [!NOTE]
> You can now customize the value and replay cache suffixes,
> or if desired completely remove those properties from the generated code.
> Checkout the [README](README.md#name-suffix) for more info.
Expand Down
77 changes: 51 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

A library to use Kotlin Coroutines from Swift code in KMP apps.

> [!IMPORTANT]
> Looking to upgrade from the 0.x releases? Checkout the [migration steps](MIGRATING_TO_V1.md).
## Why this library?
Expand All @@ -12,7 +13,8 @@ The most important limitation is cancellation support.
Kotlin suspend functions are exposed to Swift as functions with a completion handler.
This allows you to easily use them from your Swift code, but it doesn't support cancellation.

> **Note**: while Swift 5.5 brings async functions to Swift, it doesn't solve this issue.
> [!NOTE]
> While Swift 5.5 brings async functions to Swift, it doesn't solve this issue.
> For interoperability with ObjC all functions with a completion handler can be called like an async function.
> This means starting with Swift 5.5 your Kotlin suspend functions will look like Swift async functions.
> But that's just syntactic sugar, so there's still no cancellation support.
Expand All @@ -24,19 +26,21 @@ This library solves both of these limitations 😄.

## Compatibility

The latest version of the library uses Kotlin version `1.9.0`.
The latest version of the library uses Kotlin version `1.9.20`.
Compatibility versions for older and/or preview Kotlin versions are also available:

| Version | Version suffix | Kotlin | KSP | Coroutines |
|----------------|--------------------|:---------:|:----------:|:----------:|
| **_latest_** | **_no suffix_** | **1.9.0** | **1.0.12** | **1.7.3** |
| 1.0.0-ALPHA-13 | _no suffix_ | 1.9.0 | 1.0.11 | 1.7.2 |
| 1.0.0-ALPHA-12 | _no suffix_ | 1.8.22 | 1.0.11 | 1.7.2 |
| 1.0.0-ALPHA-10 | _no suffix_ | 1.8.21 | 1.0.11 | 1.7.1 |
| 1.0.0-ALPHA-8 | _no suffix_ | 1.8.21 | 1.0.11 | 1.6.4 |
| 1.0.0-ALPHA-7 | _no suffix_ | 1.8.20 | 1.0.10 | 1.6.4 |
| 1.0.0-ALPHA-5 | _no suffix_ | 1.8.10 | 1.0.9 | 1.6.4 |
| 1.0.0-ALPHA-4 | _no suffix_ | 1.8.0 | 1.0.8 | 1.6.4 |
| Version | Version suffix | Kotlin | KSP | Coroutines |
|----------------|---------------------|:-----------:|:----------:|:----------:|
| _latest_ | -kotlin-2.0.0-Beta1 | 2.0.0-Beta1 | 1.0.14 | 1.7.3 |
| **_latest_** | **_no suffix_** | **1.9.20** | **1.0.14** | **1.7.3** |
| 1.0.0-ALPHA-19 | _no suffix_ | 1.9.20 | 1.0.13 | 1.7.3 |
| 1.0.0-ALPHA-18 | _no suffix_ | 1.9.10 | 1.0.13 | 1.7.3 |
| 1.0.0-ALPHA-17 | _no suffix_ | 1.9.0 | 1.0.12 | 1.7.3 |
| 1.0.0-ALPHA-13 | _no suffix_ | 1.9.0 | 1.0.11 | 1.7.2 |
| 1.0.0-ALPHA-12 | _no suffix_ | 1.8.22 | 1.0.11 | 1.7.2 |
| 1.0.0-ALPHA-10 | _no suffix_ | 1.8.21 | 1.0.11 | 1.7.1 |
| 1.0.0-ALPHA-8 | _no suffix_ | 1.8.21 | 1.0.11 | 1.6.4 |
| 1.0.0-ALPHA-7 | _no suffix_ | 1.8.20 | 1.0.10 | 1.6.4 |

You can choose from a couple of Swift implementations.
Depending on the implementation you can support as low as iOS 9, macOS 10.9, tvOS 9 and watchOS 3:
Expand All @@ -60,8 +64,8 @@ Make sure to always use the same versions for all the libraries!
For Kotlin just add the plugin to your `build.gradle.kts`:
```kotlin
plugins {
id("com.google.devtools.ksp") version "1.9.0-1.0.12"
id("com.rickclephas.kmp.nativecoroutines") version "1.0.0-ALPHA-17"
id("com.google.devtools.ksp") version "1.9.20-1.0.14"
id("com.rickclephas.kmp.nativecoroutines") version "1.0.0-ALPHA-21"
}
```
and make sure to opt in to the experimental `@ObjCName` annotation:
Expand All @@ -77,28 +81,44 @@ The Swift implementations are available via the Swift Package Manager.
Just add it to your `Package.swift` file:
```swift
dependencies: [
.package(url: "https://github.com/rickclephas/KMP-NativeCoroutines.git", from: "1.0.0-ALPHA-17")
.package(url: "https://github.com/rickclephas/KMP-NativeCoroutines.git", exact: "1.0.0-ALPHA-21")
],
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")
]
)
]
```

Or add it in Xcode by going to `File` > `Add Packages...` and providing the URL:
`https://github.com/rickclephas/KMP-NativeCoroutines.git`.

> **Note**: the version for the Swift package should not contain the Kotlin version suffix
> [!NOTE]
> The version for the Swift package should not contain the Kotlin version suffix
> (e.g. `-new-mm` or `-kotlin-1.6.0`).
> **Note**: if you only need a single implementation you can also use the SPM specific versions with suffixes
> [!NOTE]
> If you only need a single implementation you can also use the SPM specific versions with suffixes
> `-spm-async`, `-spm-combine` and `-spm-rxswift`.
### Swift (CocoaPods)

If you use CocoaPods add one or more of the following libraries to your `Podfile`:
```ruby
pod 'KMPNativeCoroutinesAsync', '1.0.0-ALPHA-17' # Swift Concurrency implementation
pod 'KMPNativeCoroutinesCombine', '1.0.0-ALPHA-17' # Combine implementation
pod 'KMPNativeCoroutinesRxSwift', '1.0.0-ALPHA-17' # RxSwift implementation
pod 'KMPNativeCoroutinesAsync', '1.0.0-ALPHA-21' # Swift Concurrency implementation
pod 'KMPNativeCoroutinesCombine', '1.0.0-ALPHA-21' # Combine implementation
pod 'KMPNativeCoroutinesRxSwift', '1.0.0-ALPHA-21' # RxSwift implementation
```
> **Note**: the version for CocoaPods should not contain the Kotlin version suffix (e.g. `-new-mm` or `-kotlin-1.6.0`).
> [!NOTE]
> The version for CocoaPods should not contain the Kotlin version suffix (e.g. `-new-mm` or `-kotlin-1.6.0`).
### IntelliJ / Android Studio

Expand Down Expand Up @@ -317,7 +337,8 @@ handle.cancel()

The Combine implementation provides a couple functions to get an `AnyPublisher` for your Coroutines code.

> **Note**: these functions create deferred `AnyPublisher`s.
> [!NOTE]
> These functions create deferred `AnyPublisher`s.
> Meaning every subscription will trigger the collection of the `Flow` or execution of the suspend function.
#### Publisher
Expand Down Expand Up @@ -369,7 +390,8 @@ cancellable.cancel()

The RxSwift implementation provides a couple functions to get an `Observable` or `Single` for your Coroutines code.

> **Note**: these functions create deferred `Observable`s and `Single`s.
> [!NOTE]
> These functions create deferred `Observable`s and `Single`s.
> Meaning every subscription will trigger the collection of the `Flow` or execution of the suspend function.
#### Observable
Expand Down Expand Up @@ -464,14 +486,16 @@ class Clock {
}
```

> **Note**: your custom coroutine scope must be either `internal` or `public`.
> [!NOTE]
> Your custom coroutine scope must be either `internal` or `public`.
If you don't provide a `CoroutineScope` the default scope will be used which is defined as:
```kotlin
internal val defaultCoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
```

> **Note**: KMP-NativeCoroutines has built-in support for [KMM-ViewModel](https://github.com/rickclephas/KMM-ViewModel).
> [!NOTE]
> KMP-NativeCoroutines has built-in support for [KMM-ViewModel](https://github.com/rickclephas/KMM-ViewModel).
> Coroutines inside your `KMMViewModel` will (by default) use the `CoroutineScope` from the `ViewModelScope`.
### Ignoring declarations
Expand All @@ -494,7 +518,8 @@ If for some reason you would like to further refine your Kotlin declarations in
These will tell the plugin to add the [`ShouldRefineInSwift`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native/-should-refine-in-swift/)
annotation to the generated properties/function.

> **Note**: this currently requires a module-wide opt-in to `kotlin.experimental.ExperimentalObjCRefinement`.
> [!NOTE]
> This currently requires a module-wide opt-in to `kotlin.experimental.ExperimentalObjCRefinement`.
You could for example refine your `Flow` property to an `AnyPublisher` property:
```kotlin
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ buildscript {

allprojects {
group = "com.rickclephas.kmp"
version = "1.0.0-ALPHA-17"
version = "1.0.0-ALPHA-21"

repositories {
mavenCentral()
Expand Down
6 changes: 3 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[versions]
kotlin = "1.9.0"
kotlin = "1.9.20"
kotlinx-coroutines = "1.7.3"
ksp = "1.9.0-1.0.12"
ksp = "1.9.20-1.0.14"
kotlinpoet = "1.14.2"
junit = "5.9.1"

Expand All @@ -20,7 +20,7 @@ kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotl
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
kotlin-compiler-internalTestFramework = { module = "org.jetbrains.kotlin:kotlin-compiler-internal-test-framework", version.ref = "kotlin" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
kotlinCompileTesting-ksp = { module = "com.github.tschuchortdev:kotlin-compile-testing-ksp", version = "1.5.0" }
kotlinCompileTesting-ksp = { module = "dev.zacsweers.kctfork:ksp", version = "0.3.2" }
junit = { module = "junit:junit", version = "4.13.2" }
junit-bom = { module = "org.junit:junit-bom", version.ref = "junit" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter" }
Expand Down
9 changes: 8 additions & 1 deletion kmp-nativecoroutines-compiler/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader

plugins {
alias(libs.plugins.kotlin.jvm)
`kmp-nativecoroutines-publish`
Expand Down Expand Up @@ -38,12 +40,17 @@ tasks.compileKotlin.configure {
}

tasks.test {
systemProperty("kotlin.internal.native.test.nativeHome", NativeCompilerDownloader(project).compilerDirectory.absolutePath)
inputs.dir("src/testData")
useJUnitPlatform()
}

val deleteGeneratedTests by tasks.registering(Delete::class) {
delete("src/test/generated")
}

val generateTests by tasks.registering(JavaExec::class) {
doFirst { delete("src/test/generated") }
dependsOn(deleteGeneratedTests)
classpath = sourceSets.test.get().runtimeClasspath
mainClass.set("com.rickclephas.kmp.nativecoroutines.compiler.GenerateTestsKt")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package com.rickclephas.kmp.nativecoroutines.compiler

import com.rickclephas.kmp.nativecoroutines.compiler.extensions.KmpNativeCoroutinesStorageComponentContainerContributor
import com.rickclephas.kmp.nativecoroutines.compiler.classic.extensions.KmpNativeCoroutinesStorageComponentContainerContributor
import com.rickclephas.kmp.nativecoroutines.compiler.fir.extensions.KmpNativeCoroutinesFirExtensionRegistrar
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter

@OptIn(ExperimentalCompilerApi::class)
public class KmpNativeCoroutinesCompilerPluginRegistrar: CompilerPluginRegistrar() {

override val supportsK2: Boolean = false // TODO: Add K2 support
override val supportsK2: Boolean = true

override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) {
FirExtensionRegistrarAdapter.registerExtension(KmpNativeCoroutinesFirExtensionRegistrar(configuration))
StorageComponentContainerContributor.registerExtension(
KmpNativeCoroutinesStorageComponentContainerContributor(configuration)
)
Expand Down
Loading

0 comments on commit 30f28cf

Please sign in to comment.