Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Swift-friendly api generator for Kotlin/Native frameworks

License

NotificationsYou must be signed in to change notification settings

icerockdev/moko-kswift

Repository files navigation

moko-kswift
GitHub licenseDownloadkotlin-version

MOKO KSwift

KSwift it's gradle plugin for generation Swift-friendly API for Kotlin/Native framework.

Kotlin sealed interface/class to Swift enum

sealed classes compare

Kotlin extensions for K/N platform classes

extensions compare

Your own case

KSwift give you API for adding your own generator based on KLib metadata information.

Posts

Table of Contents

Features

  • API for extend logic for own cases - just implement your ownProcessorFeature
  • Reading of all exported klibs - you can generate swift additions to the api of externallibraries
  • Kotlin sealed class/interface to Swift enum
  • Kotlin extensions for platform classes to correct extensions instead of additional class withstatic methods
  • Flexible filtration - select what you want to generate and what not

Requirements

  • Gradle version 6.0+
  • Kotlin 1.6.10

Installation

Plugin

Using legacy plugin application

rootbuild.gradle

buildscript {    repositories {        mavenCentral()        google()        gradlePluginPortal()    }    dependencies {        classpath("dev.icerock.moko:kswift-gradle-plugin:0.7.0")    }}

project where framework compilesbuild.gradle

plugins {    id("dev.icerock.moko.kswift")}

Using the plugins DSL

settings.gradle

pluginManagement {    repositories {        google()        gradlePluginPortal()        mavenCentral()    }}

project where framework compilesbuild.gradle

plugins {    id("dev.icerock.moko.kswift") version"0.7.0"}

Runtime library

rootbuild.gradle

allprojects {    repositories {        mavenCentral()    }}

projectbuild.gradle

dependencies {    commonMainApi("dev.icerock.moko:kswift-runtime:0.7.0")// if you want use annotations}

Usage

Xcode configuration

The Swift code generated from this plugin is not automatically included in the shared framework you might have.

You have 2 options to use it in your iOS project:

  • Xcode direct file integration
  • CocoaPods integration

Xcode direct file integration

You can directly import the generated file in your Xcode project like it's a file you have written on your own.

To do so:

  • open the Xcode project
  • right click on "iosApp"
  • choose "Add files to iOSApp"
  • add the file from the generated folder (you might need to read the FAQ to know where the generated folder is)
  • you are now good to go!

CocoaPods integration

After you have added the moko-kswift plugin to your shared module and synced your project, a new Gradle task should appear with namekSwiftXXXXXPodspec whereXXXXX is the name of your shared module (so your task might be namedkSwiftsharedPodspec).

  • Run the task doing./gradlew kSwiftsharedPodspec from the root of your project.This will generate a new podspec file,XXXXXSwift.podspec, whereXXXXX is still the name of your shared module (so e.g.sharedSwift.podspec)

  • Now edit thePodfile inside the iOS project adding this linepod 'sharedSwift', :path => '../shared'just after the one already there for the already available shared modulepod 'shared', :path => '../shared'

  • Now runpod install from theiosApp folder so the new framework is linked to your project.

  • Whenever you need a Swift file generated from moko-kswift just import the generated module (e.g.import sharedSwift) and you are good to go!

Sealed classes/interfaces to Swift enum

Enable feature in projectbuild.gradle:

kotlin:

kswift {    install(dev.icerock.moko.kswift.plugin.feature.SealedToSwiftEnumFeature)}

groovy:

kswift {    install(dev.icerock.moko.kswift.plugin.feature.SealedToSwiftEnumFeature.factory)}

That's all - after this setup all sealed classes and sealed interfaces will be parsed by plugin andplugin will generate Swift enums for this classes.

For example if you have in your kotlin code:

sealedinterfaceUIState<outT> {object Loading : UIState<Nothing>object Empty : UIState<Nothing>data classData<T>(valvalue:T) : UIState<T>data classError(valthrowable:Throwable) : UIState<Nothing>}

Then plugin will generate source code:

/** * selector: ClassContext/moko-kswift.sample:mpp-library-pods/com/icerockdev/library/UIState */publicenumUIStateKs<T:AnyObject>{case loadingcase emptycase data(UIStateData<T>)case error(UIStateError)publicinit(_ obj:UIState){if obj isshared.UIStateLoading{self=.loading}elseif obj isshared.UIStateEmpty{self=.empty}elseiflet obj= objas?shared.UIStateData<T>{self=.data(obj)}elseiflet obj= objas?shared.UIStateError{self=.error(obj)}else{fatalError("UIStateKs not syncronized with UIState class")}}}

For each generated entry in comment generatedselector - value of this selector can be used forfilter. By default all entries generated. But if generated code invalid (please report issue in thiscase) you can disable generation of this particular entry:

kotlin:

kswift {    install(dev.icerock.moko.kswift.plugin.feature.SealedToSwiftEnumFeature) {        filter= excludeFilter("ClassContext/moko-kswift.sample:mpp-library-pods/com/icerockdev/library/UIState")    }}

groovy:

kswift {    install(dev.icerock.moko.kswift.plugin.feature.SealedToSwiftEnumFeature.factory) {        it.filter= it.excludeFilter("ClassContext/moko-kswift.sample:mpp-library-pods/com/icerockdev/library/UIState")    }}

As alternative you can useincludeFilter to explicit setup each required for generation entries:

kotlin:

kswift {    install(dev.icerock.moko.kswift.plugin.feature.SealedToSwiftEnumFeature) {        filter= includeFilter("ClassContext/moko-kswift.sample:mpp-library-pods/com/icerockdev/library/UIState")    }}

groovy:

kswift {    install(dev.icerock.moko.kswift.plugin.feature.SealedToSwiftEnumFeature.factory) {        it.filter= it.includeFilter("ClassContext/moko-kswift.sample:mpp-library-pods/com/icerockdev/library/UIState")    }}

Extensions from platform classes

Enable feature in projectbuild.gradle:

kotlin:

kswift {    install(dev.icerock.moko.kswift.plugin.feature.PlatformExtensionFunctionsFeature)}

groovy:

kswift {    install(dev.icerock.moko.kswift.plugin.feature.PlatformExtensionFunctionsFeature.factory)}

That's all - after this setup all extension functions for classes fromplatform.* package will becorrect swift code.

For example if you have in your kotlin code:

classCFlow<T>(privatevalstateFlow:StateFlow<T>) : StateFlow<T> by stateFlowfun UILabel.bindText(coroutineScope:CoroutineScope,flow:CFlow<String>) {val label=this    coroutineScope.launch {        label.text= flow.value        flow.collect { label.text= it }    }}

Then plugin will generate source code:

publicextensionUIKit.UILabel{  /**   * selector: PackageFunctionContext/moko-kswift.sample:mpp-library/com.icerockdev.library/Class(name=platform/UIKit/UILabel)/bindText/coroutineScope:Class(name=kotlinx/coroutines/CoroutineScope),flow:Class(name=com/icerockdev/library/CFlow)<Class(name=kotlin/String)> */publicfunc bindText(coroutineScope:CoroutineScope, flow:CFlow<NSString>){returnUILabelExtKt.bindText(self, coroutineScope: coroutineScope, flow: flow)}}

Selector from comment can be used for filters as in first example.

Generation of Swift copy method for data classes

Enable feature in projectbuild.gradle:

kotlin:

kswift {    install(dev.icerock.moko.kswift.plugin.feature.DataClassCopyFeature)}

groovy:

kswift {    install(dev.icerock.moko.kswift.plugin.feature.DataClassCopyFeature.factory)}

With this feature for data class like this:

data classDataClass(valstringValue:String,valoptionalStringValue:String?,valintValue:Int,valoptionalIntValue:Int?,valbooleanValue:Boolean,valoptionalBooleanValue:Boolean?)

Will be generated swift code that can be used like this:

letnewObj= dataClass.copy(    stringValue:{"aNewValue"},     intValue:{1},     booleanValue:{true})

Implementation of own generator

First createbuildSrc, if you don't.build.gradle will contains:

plugins {    id("org.jetbrains.kotlin.jvm") version"1.6.10"}repositories {    mavenCentral()    google()    gradlePluginPortal()    maven("https://jitpack.io")}dependencies {    implementation("com.android.tools.build:gradle:7.0.0")    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21")    implementation("dev.icerock.moko:kswift-gradle-plugin:0.7.0")}

Then inbuildSrc/src/main/kotlin createMyKSwiftGenerator:

importdev.icerock.moko.kswift.plugin.context.ClassContextimportdev.icerock.moko.kswift.plugin.feature.ProcessorContextimportdev.icerock.moko.kswift.plugin.feature.ProcessorFeatureimportdev.icerock.moko.kswift.plugin.feature.BaseConfigimportdev.icerock.moko.kswift.plugin.feature.Filterimportio.outfoxx.swiftpoet.DeclaredTypeNameimportio.outfoxx.swiftpoet.ExtensionSpecimportio.outfoxx.swiftpoet.FileSpecimportkotlin.reflect.KClassclassMyKSwiftGenerator(overridevalfeatureContext:KClass<ClassContext>,overridevalfilter:Filter<ClassContext>) : ProcessorFeature<ClassContext>() {overridefundoProcess(featureContext:ClassContext,processorContext:ProcessorContext) {val fileSpec:FileSpec.Builder= processorContext.fileSpecBuilderval frameworkName:String= processorContext.framework.baseNameval classSimpleName= featureContext.clazz.name.substringAfterLast('/')        fileSpec.addExtension(ExtensionSpec                .builder(DeclaredTypeName.typeName("$frameworkName.$classSimpleName")                )                .build()        )    }classConfig :BaseConfig<ClassContext> {overridevar filter:Filter<ClassContext>=Filter.Exclude(emptySet())    }companionobject:Factory<ClassContext,MyKSwiftGenerator,Config> {overridefuncreate(block:Config.()->Unit):MyKSwiftGenerator {val config=Config().apply(block)returnMyKSwiftGenerator(featureContext, config.filter)        }overrideval featureContext:KClass<ClassContext>=ClassContext::class        @JvmStaticoverrideval factory=Companion    }}

in this example will be generated swift extension for each class in kotlin module. You can selectrequiredContext to got required info from klib metadata.

last step - enable feature in gradle:

kotlin:

kswift {    install(MyKSwiftGenerator)}

groovy:

kswift {    install(MyKSwiftGenerator.factory)}

Set iOS deployment target for podspec

kotlin:

kswift {    iosDeploymentTarget.set("11.0")}

groovy:

kswift {    iosDeploymentTarget="11.0"}

Samples

FAQ

Where destination directory for all generated sources?

Swift source code generates in same directory where compiles Kotlin/Native framework. In common caseit directorybuild/bin/{iosArm64 || iosX64}/{debugFramework || releaseFramework}/{frameworkName}Swift.

Kotlin/Native cocoapods plugin (and also mobile-multiplatform cocoapods plugin by IceRock) will movethis sources into fixed directory -build/cocoapods/framework/{frameworkName}Swift.

How to exclude generation of entries from some libraries?

kswift {    excludeLibrary("{libraryName}")}

How to generate entries only from specific libraries?

kswift {    includeLibrary("{libraryName1}")    includeLibrary("{libraryName2}")}

Samples

More examples can be found in thesample directory.

Set Up Locally

Clone project and just open it. Gradle plugin attached to sample by gradle composite build, so youwill see changes at each gradle build.

# clone repogit clone git@github.com:icerockdev/moko-kswift.gitcd moko-kswift# generate podspec files for cocopods intergration. with integration will be generated swift files for cocoapod./gradlew kSwiftmpp_library_podsPodspec./gradlew kSwiftMultiPlatformLibraryPodspec# go to ios dircd sample/ios-app# install podspod install# now we can open xcworkspace and build ios projectopen ios-app.xcworkspace# or run xcodebuildxcodebuild -scheme ios-app -workspace ios-app.xcworkspacetest -destination"platform=iOS Simulator,name=iPhone 12 mini"xcodebuild -scheme pods-test -workspace ios-app.xcworkspacetest -destination"platform=iOS Simulator,name=iPhone 12 mini"

Contributing

All development (both new features and bug fixes) is performed indevelop branch. Thiswaymaster sources always contain sources of the most recently released version. Please send PRswith bug fixes todevelop branch. Fixes to documentation in markdown files are an exception tothis rule. They are updated directly inmaster.

Thedevelop branch is pushed tomaster during release.

More detailed guide for contributers see incontributing guide.

License

Copyright 2021 IceRock MAG IncLicensed under the Apache License, Version 2.0 (the "License");you may not use this file except in compliance with the License.You may obtain a copy of the License at   http://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed under the License is distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions andlimitations under the License.

[8]ページ先頭

©2009-2025 Movatter.jp