javascript as target in kotlin multiplatform library - kotlin

I'm building a Kotlin multiplatform library. One of the targets in this project is javascript. In the source set I have added a dependency like this:
val jsMain by getting {
dependencies {
implementation(npm("libphonenumber-js", "1.10.13"))
}
}
The gradle sync was successful, now I want to import the files in jsMain directory. How can I achieve this?

Add npm dependency with generateExternals as you already did
implementation(npm("libphonenumber-js", "1.10.13", generateExternals = true))
generateExternals = true triggers a tool called Dukat that generates Kotlin external declarations from the Typescript definition file of that npm module.
Once your project syncs, it would have externals folder under your shared module's build folder like shown below,
(Ignore kmp-lib-1621 in above image. That would be your module/library name instead)`
Now copy and paste these files in your project (jsMain source set) and remove generateExternal = true from your dependency otherwise it would generate this files everytime. (1) you would lose any manual change (2) if you update the library version then it can potentially break your project
You should be able to call generated external code from Kotlin code, whether you keep it in build folder or you pasted it in your project code.
Important Note: Dukat tool is experiemental and known to create externals that may not work 100% times. So remove all unnecessary code from external generated code so you only end up having few references of classes you want to use from the npm library. Do some trial and error and you would be fine.
Hope this helps!

You have to use js(IR) backend and generate externals
implementation(npm("libphonenumber-js", "1.10.13", generateExternals = true)).

Related

How to add a dependency on a Pod library in KMM (Kotlin Multiplatform)?

So, I followed the Kotlin guideline and added the dependency from a remote repo like below:
pod("JSONModel") {
source = git("https://gitlab.com/jsonmodel/jsonmodel.git") {
branch = "key-mapper-class"
}
It does add the dependency, however instead of referring to the branch I point at gitlab, it points to the main branch. Any ideas why this might be happening?
Having a deeper look at the generated files, it feels as if this is a bug with native.cocoapods plugin within KMM. KMM adds the dependency as instructed on the shared library but it also adds the latest published version from cocoapods.

Skeleton for Kotlin/native multiproject with dll library for backend and frontend app using it

I'm trying to create a multiproject using Kotlin/native and gradle in IDEA that consists of:
A backend subproject library. I want to use this library in frontend Kotlin app and also produce a native DLL that can be later used in other software. I doubt I'll need any platform specific behavior -- the most I'll interact with the system is read, write and watch a file for changes.
A frontend jvm app in Kotlin using this library as required dependency. To be more precise I'm going to write a glfw app in Kotlin that will use this lib, but that's a detail you don't have to bother with.
I want to be able to:
build DLL on it's own
build an app that depends on library and rebuilds if needed when the lib changed.
I made a hyperlink trip over gradle docs, JetBrains examples and repos but I don't quite understand how to make a multiproject like that. Can someone provide a minimal working example of such a Hello World project?
Right now this works for me in the initial stage of the project:
Use gradle init with basic type and kotlin DSL to generate a wrapper project
Add 2 modules with New > Module > Gradle > Kotlin/Multiplatform and Kotlin/JVM. That should add include("...") entries to root settings.gradle.kts At this point those modules will be empty with a single build.gradle.kts scripts
Root build.gradle.kts can be deleted - both library and app use their own
In the Multiplatform library setup at least one target for example like that:
// rootProject/library/build.gradle.kts
// ...
kotlin {
jvm() // used by jvm app
sourceSets { /*...*/ }
}
Now there should be no gradle errors and IDEA will detect the project properly - refresh gradle configuration (CTRL+SHIFT+O)
Create source directories for each module (because the modules rn): IDEA should hint the names of corresponding source sets (src/<target>/<kotlin|resources> etc.)
So now just to link the app and library together in the the app's buildscript add the implementation(project(":library")) dependency
Of course don't forget to configure the library target for example using linuxX64("native") { binaries { sharedLib {/*...*/ } } } block in kotlin plugin when trying to generate a DLL
Now it should mostly work. The structure of a project I'm working on rn looks like that:

How to add dependencies to a kotlin library?

I am trying to build a kotlin library for discord bots, which can be found at https://github.com/TheDrone7/discord-kt , published to jcenter (bintray link - https://bintray.com/thedrone7/discordKt/discord-kt). The library has a few dependencies of it's own as well.
When I add my own library to my test app, the library's dependencies were not installed and I started getting some errors. Is there a way to specify the library's dependencies so that they get automatically installed when a user uses my library?
EDIT: -
So basically my test app's build.gradle.kts file's dependencies section is given below
dependencies {
// Use the Kotlin JDK 8 standard library.
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.theDrone:discordKt:0.0.1a")
// Use the Kotlin test library.
testImplementation("org.jetbrains.kotlin:kotlin-test")
// Use the Kotlin JUnit integration.
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
}
And my library is dependent on the following packages: -
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.0
org.java-websocket:Java-WebSocket:1.4.0
com.beust:klaxon:5.0.5
org.slf4j:slf4j-jdk14:1.7.26
now when I run my test app, it shows gives error that there is no class named WebSocketClient which is a part of the org.java-websocket:Java-WebSocket:1.4.0 package and is also the base of my entire library.
When I add the listed packages to my test app's dependencies, it works perfectly fine. So is there a way that I could define in my library that the apps using it will also automatically depend on the packages my library depends on?
You declared the Java-WebSocket library as a dependency of your library using the implementation configuration.
This configuration means: I need that for my code to work, but it's an implementation detail and it's thus not part of my public API, so users of my library won't have access to it in their compile classpath.
So Gradle, when it generates the pom.xml file for your library, adds Java-WebSocket as a runtime dependency, and not as a compile dependency.
Read the java-library plugin documentation, which explains all of that in details. Once you have understood it, use api instead of implementation in your library's build.gradle.kts file for the dependencies that are part of your API, and should thus be compile dependencies and not runtime dependencies:
api("org.java-websocket:Java-WebSocket:1.4.0")

Is There A Way To Create A Joint Intellij Project Spanning Multiple Gradle Projects As Modules

So it actually seems to mostly work, with both projects as sub-modules of the overall project. But the major annoyance is that when I debug in one of the modules, if code calls something in the other module it picks up the dependency from the Gradle cache instead of the other project/module's code and steps into a decompiled .class file from its cache instead of the actual source code.
I'd like to find a way so Intellij recognizes one module is using the other and uses the source code from the module itself which is of course checked out and available in the local filesystem.
See gradle documentation here about setting up multiple projects as "sub-modules", though gradle lingo usually refers to them as sub-projects.
Basically, if you have some projects that are sub projects of a root project, you would setup the folder structure like this:
root
├───build.gradle
├───settings.gradle
│
├───subA
│ └───build.gradle
├───subB
│ └───build.gradle
└───subC
└───build.gradle
In your root settings.gradle, you include your sub projects by adding:
include 'subA', 'subB', 'subC'
From this point on, you can refer to any project in your setup from any other project by its name: project(':subB')
so If you want to add subC as a compile time dependency of subA, in subA's build.gradle, you would have:
dependencies{
compile project(':subC')
}
Declared this way, the dependency is on the current files of subC instead of the last built/installed binaries from the repository. You could also have root project just a holder project with no code of its own.
I've had some success using dependency substitution in a development mode kinda like this:
if (project.has("devMode")) {
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute module("foo.group:bar") with project(":bar")
}
}
}
Hopefully something like that may work for you, too.
EDIT: note that you'll also have to conditionally add the :bar project in settings.gradle as well

Android Gradle Dependency

I am using local aar files for one of our projects and have below Query.
I have 2 libraries and 1 application.
2 libraries are:
1. TestLib2
2. TestLib1
1 Application is:
1. Test
I use a aar file created for TestLib2 and refer it using flatDir in TestLib1. I can access the functions present in TestLib2 without any problems.
Now I use a aar file created for TestLib1 and refer it using flatDir in Test. I can access only the functions present in TestLib1. For accessing TestLib2 i have to add it to Test application as one more Library.
So the dependency is like below:
Test
|_ TestLib1
|_ TestLib2
Is the above possible in case of aar files?
Also in settings.gradle file for TestLib1 i mention to include
include ':app', ':testlib2-debug'
Where app refers to the TestLib1
The build.gradle file doesnt really have any flavors as such and i dont even have any restriction of using them as jar's since its containing only the java piece of code.
Any help on the same is much appreciated.
BR,
Jayshil
Update 1:
I tried below as well in build.gradle of TestLib1 and Test.
Still no luck.
dependencies {
compile (name:'testlib2-debug', ext:'aar') {
transitive = true;
}
}
And for Test App
compile (name:'testlib1-debug', ext:'aar') {
transitive = true;
}
So i finally figured out a solution for this.
It works for 2 level dependency mentioned above.
Create a jar file for Test Lib 2.
task clearJar(type: Delete) {
delete 'build/outputs/loggingSDK.jar'
}
task makeJar(type: Copy) {
from('build/intermediates/bundles/release/')
into('build/outputs/')
include('classes.jar')
rename ('classes.jar', 'testlib2.jar')
}
makeJar.dependsOn(clearJar, build)
By using a the command
gradle makeJar
You would have got a testlib2.jar
Copy this into your TestLib1
Use command
gradle assemble
This would create debug and release version
Take the debug version and copy it in Test you would be able to call functions of TestLib1 which in turn calls function of TestLib2
Hope this may help someone looking for such solution