ttypic / swift-klib-plugin Goto Github PK
View Code? Open in Web Editor NEWGradle Plugin for injecting Swift code into Kotlin Multiplatform Mobile shared module
License: MIT License
Gradle Plugin for injecting Swift code into Kotlin Multiplatform Mobile shared module
License: MIT License
It will be nice to extract swift tools version to swiftklib
extension config.
For now it always hardcoded to 5.5
Hello, I am trying to create a Kotlin class based on the swift library facebook-sdk-ios
to be able to use one of the native functions of the Facebook SDK.
I installed the package on XCode using the SwiftPackageManager following this instructions.
I followed the steps on the Readme of your plugin and I create inside native/Facebook
a file Facebook.swift
that looks like:
import FacebookCore
import Foundation
@objc public class FacebookSdk : NSObject {
@objc public class func getAccessToken() -> String {
return AccessToken.current
}
}
However, when I try to build, it appears an error in the console saying:
error: no such module 'FacebookCore'
import FacebookCore
^
Is there a way to make the libraries to be imported correctly? Is it even possible to get what I need using your plugin? I don't actually know if this is in the scope of the plugin or I need to find another solution.
Thank you in advance!
Hi there! Firstly thanks for sharing this concept. It may be very useful and much more convenient than exporting framework from xcode. ๐
I have an issue though with passing CVPixelBuffer parameter to function. A minimal example:
import Foundation
import CoreVideo
import CoreImage
@objc(HelloWorld)
public class HelloWorld : NSObject {
@objc(helloWorldWithPixelBuffer:)
public class func helloWorld(pixelBuffer: CVPixelBuffer) -> String {
return "HeLLo WorLd!"
}
}
During sync with gradle I get:
Task :shared:cinteropSwiftIosArm64
Warning: Failed to generate cinterop for :shared:cinteropSwiftIosArm64: Process 'command '/Applications/Android Studio Preview 3.app/Contents/jbr/Contents/Home/bin/java'' finished with non-zero exit value 1
org.gradle.process.internal.ExecException: Process 'command '/Applications/Android Studio Preview 3.app/Contents/jbr/Contents/Home/bin/java'' finished with non-zero exit value 1
at org.gradle.process.internal.DefaultExecHandle$ExecResultImpl.assertNormalExitValue(DefaultExecHandle.java:415)
at org.gradle.process.internal.DefaultJavaExecAction.execute(DefaultJavaExecAction.java:52)
at org.gradle.process.internal.DefaultExecActionFactory.javaexec(DefaultExecActionFactory.java:195)
at org.gradle.process.internal.DefaultExecOperations.javaexec(DefaultExecOperations.java:42)
...
Exception in thread "main" java.lang.Error: /Users/......./shared/build/swiftklib/swift/iosArm64/swiftBuild/.build/arm64-apple-macosx/release/swift.build/swift-Swift.h:287:51: error: expected a type
at org.jetbrains.kotlin.native.interop.indexer.UtilsKt.ensureNoCompileErrors(Utils.kt:275)
at org.jetbrains.kotlin.native.interop.indexer.IndexerKt.indexDeclarations(Indexer.kt:1244)
at org.jetbrains.kotlin.native.interop.indexer.IndexerKt.buildNativeIndexImpl(Indexer.kt:1227)
at org.jetbrains.kotlin.native.interop.indexer.IndexerKt.buildNativeIndexImpl(Indexer.kt:1223)
at org.jetbrains.kotlin.native.interop.gen.jvm.DefaultPlugin.buildNativeIndex(Plugins.kt:33)
at org.jetbrains.kotlin.native.interop.gen.jvm.MainKt.processCLib(main.kt:321)
at org.jetbrains.kotlin.native.interop.gen.jvm.MainKt.processCLibSafe(main.kt:242)
at org.jetbrains.kotlin.native.interop.gen.jvm.MainKt.access$processCLibSafe(main.kt:1)
at org.jetbrains.kotlin.native.interop.gen.jvm.Interop.interop(main.kt:100)
at org.jetbrains.kotlin.cli.utilities.InteropCompilerKt.invokeInterop(InteropCompiler.kt:45)
at org.jetbrains.kotlin.cli.utilities.MainKt.mainImpl(main.kt:23)
at org.jetbrains.kotlin.cli.utilities.MainKt.main(main.kt:45)
generated header is:
SWIFT_CLASS_NAMED("HelloWorld")
@interface HelloWorld : NSObject
+ (NSString * _Nonnull)helloWorldWithPixelBuffer:(**[ERROR POINTS HERE]**CVPixelBufferRef _Nonnull)pixelBuffer SWIFT_WARN_UNUSED_RESULT;
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end
When I change CVPixelBuffer to String it works fine.
Appears the incorrect build target is used.
When attempting to import a iOS dependency such as:
import UIKit
The following output occurs:
<unknown>:0: warning: using sysroot for 'iPhoneSimulator' but targeting 'MacOSX'
<unknown>:0: error: unable to load standard library for target 'arm64-apple-macosx12.0'
error: Process 'command 'xcrun'' finished with non-zero exit value 1
The target should be an iOS target such as arm64-apple-ios11.0-simulator
I followed the post here to get crypto working in an Kotlin multiplatform app (iOS side) using this plugin.
However, the compilation fails (in xCode) with the error:
> Task :shared:swiftklibKCryptoIosArm64
error: 'swiftbuild': Invalid manifest (compiled with: ["/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc", "-vfsoverlay", "/var/folders/l6/dvt5060j6qlb9_cr_551vdpw0000gn/T/TemporaryDirectory.OySw0O/vfs.yaml", "-L", "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/pm/ManifestAPI", "-lPackageDescription", "-Xlinker", "-rpath", "-Xlinker", "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/pm/ManifestAPI", "-target", "arm64-apple-macosx13.0", "-sdk", "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.0.sdk", "-F", "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks", "-I", "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib", "-L", "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib", "-swift-version", "5", "-I", "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/pm/ManifestAPI", "-sdk", "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.0.sdk", "-package-description-version", "5.5.0", "/Users/dusiema/projects/ti-mobile/shared/build/swiftklib/KCrypto/iosArm64/swiftBuild/Package.swift", "-Xfrontend", "-disable-implicit-concurrency-module-import", "-Xfrontend", "-disable-implicit-string-processing-module-import", "-o", "/var/folders/l6/dvt5060j6qlb9_cr_551vdpw0000gn/T/TemporaryDirectory.iiJUpf/swiftbuild-manifest"])
error: fatalError
<unknown>:0: warning: using sysroot for 'iPhoneOS' but targeting 'MacOSX'
<unknown>:0: error: unable to load standard library for target 'arm64-apple-macosx13.0'
> Task :shared:swiftklibKCryptoIosArm64 FAILED
error: Process 'command 'xcrun'' finished with non-zero exit value 1
Is this supposed to work with xCode 15 as well?
It is actually compiling my KCrypto
code. (Gradle builds in Android Studio).
But building the app in xCode runs into this problem.
Any hints are greatly appreciated. I'd love to get crypto running in my multiplatform app.
I'm encountering an issue while building my Swift file AudioRecorderImpl.swift
, which requires AVFoundation
. The error message I'm getting is:
could not build Objective-C module 'AVFoundation' error: fatalError
// AudioRecorderImpl.swift
import Foundation
import AVFoundation
@objc class AudioRecorderImpl: NSObject, AVAudioRecorderDelegate {
private var audioRecorder: AVAudioRecorder?
private var audioFileURL: URL?
@objc func startRecording() {
// ... (your existing code)
}
@objc func stopRecording() -> NSData {
// ... (your existing code)
}
}
##My directory structure
Mirror (root package)
|-- Compose App
| |-- native
| | |-- AudioRecorderImpl.swift
| |-- src
| |-- androidmain
| |-- commonmain
| |-- iosmain
##inside gradle.kts
import org.jetbrains.compose.ExperimentalComposeLibrary
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidApplication)
alias(libs.plugins.jetbrainsCompose)
alias(libs.plugins.kotlinxSerialization)
alias(libs.plugins.sqlDelight)
alias(libs.plugins.swiftklib)
}
sqldelight {
databases {
create("MirrorLocalDatabase") {
packageName.set("org.example.mirror.database")
}
}
}
kotlin {
androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = "1.8"
}
}
}
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "ComposeApp"
isStatic = true
}
iosTarget.compilations {
val main by getting {
cinterops {
create("AudioRecorderImpl")
}
}
}
}
sourceSets {
androidMain.dependencies {
//android specific dependencies
}
iosMain.dependencies {
//ios specific dependencies
}
commonMain.dependencies {
//common dependencies
}
}
}
android {
//android section
}
swiftklib {
create("AudioRecorderImpl") {
path = file("native")
packageName("org.example.mirror")
}
}
I'm trying to build a multiplatform library that uses CryptoKit. I've implemented code similar to the KCrypto example. When building a framework for iOS or when running a test on the iOS simulator, everything works fine. However, since I'm building a library, I want to publish it. I've added the maven-publish
plugin to my build.gradle.kts
file.
Now when I run publishIosSimulatorArm64PublicationToMavenLocal
(or any other iOS publish task) it fail because it cannot find the types from the swift file.
In my build.gradle.kt
:
swiftklib {
create("KCrypto") {
path = file("native/KCrypto")
packageName("com.mylib.objclibs.kcrypto")
}
}
native/KCrypto/PublicKeyEncoder.swift
:
import CryptoKit
import Foundation
@objc public protocol PublicKeyEncoder {
@objc func encodePublicKey(decompressedKeyData: Data) -> Data
}
In a iOS specific Kotlin (located in src/iosMain/kotlin
:
import com.mylib.objclibs.kcrypto.*
Generates the following error:
e: file:///Users/[path]/src/iosMain/kotlin/com/mylib/ObjcDataCipher.kt:7:26 Unresolved reference: objclibs
As mentioned, this error only occurs when publishing. The same code runs fine in other scenarios.
I tried the steps for CryptoKit was working fine; but when I tried to use apis which made me import CryptoSwift it gave me error as
error: no such module 'CryptoSwift'
import CryptoSwift
In an attempt to debug a problem I'm having using Swift Klib, and upload a pull request to fix it, I'd like to test the plugin locally. Do you have a procedure to do that ?
While having public code with some types from native frameworks other than foundation , I'm getting an error:
/iosArm64/swiftBuild/.build/arm64-apple-macosx/release/BleCommunication.build/BleCommunication-Swift.h:366:33: error: unknown type name 'CBManagerState'
The code which I have is very simple
import CoreBluetooth
public static var state: CBManagerState { .unknown }
Currently I've wrapped my enum, but it's not a best trick.
Can we specify headers or other options?
When I open a project that uses this gradle plugin on my Linux machine, the project fails to sync with Execution failed for task ':foo:swiftklibAttributesIosSimulatorArm64'
. I am using version 0.4.0.
Expected:
The project should sync, but skip building for ios, like the KMM plugin does
Actual:
I see the following Exception on sync
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':foo:swiftklibAttributesIosX64'.
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:148)
at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:282)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:146)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:134)
at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:74)
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:78)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:42)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:331)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:318)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.lambda$execute$0(DefaultTaskExecutionGraph.java:314)
at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:80)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:314)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:303)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:463)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:380)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: org.gradle.process.internal.ExecException: A problem occurred starting process 'command 'xcrun''
at org.gradle.process.internal.DefaultExecHandle.execExceptionFor(DefaultExecHandle.java:241)
at org.gradle.process.internal.DefaultExecHandle.setEndStateInfo(DefaultExecHandle.java:218)
at org.gradle.process.internal.DefaultExecHandle.failed(DefaultExecHandle.java:386)
at org.gradle.process.internal.ExecHandleRunner.lambda$run$3(ExecHandleRunner.java:102)
at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:80)
at org.gradle.process.internal.ExecHandleRunner.run(ExecHandleRunner.java:101)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: net.rubygrapefruit.platform.NativeException: Could not start 'xcrun'
at net.rubygrapefruit.platform.internal.DefaultProcessLauncher.start(DefaultProcessLauncher.java:27)
at net.rubygrapefruit.platform.internal.WrapperProcessLauncher.start(WrapperProcessLauncher.java:36)
at org.gradle.process.internal.ExecHandleRunner.startProcess(ExecHandleRunner.java:122)
at org.gradle.process.internal.ExecHandleRunner.lambda$run$0(ExecHandleRunner.java:80)
at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:80)
at org.gradle.process.internal.ExecHandleRunner.run(ExecHandleRunner.java:79)
... 5 more
Caused by: java.io.IOException: Cannot run program "xcrun" (in directory "/home/user/IdeaProjects/foo"): error=2, No such file or directory
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1143)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1073)
at net.rubygrapefruit.platform.internal.DefaultProcessLauncher.start(DefaultProcessLauncher.java:25)
... 10 more
Caused by: java.io.IOException: error=2, No such file or directory
at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)
at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:314)
at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:244)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1110)
... 12 more
What went wrong:
A problem was found with the configuration of task ':core:swiftklibNetworkUtilsImplIosArm64' (type 'CompileSwiftTask'). In plugin 'io.github.ttypic.swiftklib' type 'io.github.ttypic.swiftklib.gradle.task.CompileSwiftTask' property 'pathProperty' specifies directory 'xxxxx' which doesn't exist.
If the path of the KMM project has any folder with spaces, like ~/XYZ ABC/path
the space of the path isn't skipped and it fails to build because can't read the folder containing the swift file..
Also, consider filing an issue with full Gradle log here: https://kotl.in/issue
The /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld command returned non-zero exit code: 1.
output:
-iphoneos_version_min has been renamed to -ios_version_min
ld: warning: passed two min versions (9.0, 13.0) for platform iOS. Using 13.0.
ld: unknown options: -sdk_version
FAILURE: Build failed with an exception.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.