Kotlin cross platform development

Keywords: Maven jvm Gradle iOS

  • Today, let's briefly introduce the use of kotlin for cross platform development, so that one code, multiple runs.

I. Introduction

First of all, I extracted some basic information from official documents.

At the beginning of design, kotlin language has a clear goal, that is, it can be used on all platforms, and can use kotlin to develop applications of any platform. At the same time, another important goal of kotlin is to share code among different platforms.

Kotlin can not only be compiled into the bytecode file of the JVM platform, but also directly into binary files and js files. With support for JVM, Android, JavaScript, iOS, Linux, Windows, Mac and even embedded systems like STM32, kotlin can handle any and all components of modern applications. This brings valuable benefits to the reuse of code and expertise, saving effort to accomplish more challenging tasks rather than implementing everything twice or more.

How it works

In general, multi platform does not compile all the code for all platforms. This model has its obvious limitations. We know that modern applications need to access the unique features of the platform on which they run. Kotlin doesn't limit you to a common subset of all of its APIs. Each component can share as much code as possible with other components as needed, and the platform API can be accessed at any time through the expect/actual mechanism provided by the language.

expect/actual

In some cases, we may need to write different code for different platforms. At this time, we need to define the classes or methods that need to be implemented in different platforms in the common code part through the expect keyword, and then implement the corresponding classes or methods through the actual keyword in the corresponding directory of each platform. As shown in the figure, in the common code section, the writeLogMessage method is defined by the expect keyword.

Then we need to implement this method in different platforms, such as js platform

Implementation of jvm platform:

Multi platform library depends on other multi platform Libraries

2, Project construction

(1) Project creation

It is recommended to use the latest idea here. Although in theory, the project is built with gradle, and it should be OK to use Android studio, the idea has its own project skeleton, which is quite convenient.

1. Use idea to create a new project, and select Multiplatform Library in the kotlin project

Tips:

  • The default project construction depends on a version of gradle that is not available locally and needs to be downloaded. In this case, you can terminate the task and modify the newer version of gradle that exists locally.
  • By default, the project will build the Mac OS platform and download the related dependency library. If you do not need the Mac OS platform, you can remove the Mac OS related configuration in build.gradle after terminating the task

(2) Project structure

The following directories are generated automatically after the project is created

commonMain directory is the directory where the public code is located

Catalog introduce
commonMain Common code
commonTest Public test code
jsMain Js platform code
jsTest Js platform test code
jvmMain jvm platform code (Android)
jvmTest jvm platform test code
macosMain Mac OS platform code
macosTest Mac OS platform test code
iosMain ios platform code
iosTest ios platform test code

Note: there is no iOS directory by default. If you need iOS platform, you need to create it manually

The structure in commonMain is similar to that of common projects

(3) Project build.gradle

Default file:

plugins {
    id 'org.jetbrains.kotlin.multiplatform' version '1.3.61'//Configure kotlin multiplatform plug-ins and versions
}
repositories {
    mavenCentral()//Configure maven central warehouse
}
group 'com.example'//Define package group
version '0.0.1'//Edition

apply plugin: 'maven-publish'//Reference maven upload plug-in

kotlin {//Used to configure platform information to be built
    jvm()//Build jvm platform and output jar package
    js {//Build js platform and output js module
        browser {//Build js module for browser environment
        }
        nodejs {//Build js module for node environment
        }
        //Because the API s provided by nodejs and browser environments are different, they need to be distinguished.
    }
    // For ARM, should be changed to iosArm32 or iosArm64
    // For Linux, should be changed to e.g. linuxX64
    // For MacOS, should be changed to e.g. macosX64
    // For Windows, should be changed to e.g. mingwX64
    macosX64("macos")//Build Mac OS platform and output framework
    sourceSets {//Source settings
        commonMain {//Public code directory
            dependencies {//Dependencies required by common code
                implementation kotlin('stdlib-common')
            }
        }
        commonTest {//Common code test
            dependencies {
                implementation kotlin('test-common')
                implementation kotlin('test-annotations-common')
            }
        }
        jvmMain {//jvm code directory
            dependencies {
                implementation kotlin('stdlib-jdk8')
            }
        }
        jvmTest {
            dependencies {
                implementation kotlin('test')
                implementation kotlin('test-junit')
            }
        }
        jsMain {
            dependencies {
                implementation kotlin('stdlib-js')
            }
        }
        jsTest {
            dependencies {
                implementation kotlin('test-js')
            }
        }
        macosMain {
        }
        macosTest {
        }
    }
}

Revised documents as required

buildscript {//Configuration of build scripts
    repositories {//Warehouse configuration
        mavenLocal()//Use local maven warehouse
        mavenCentral()
        maven {//The warehouse needed by kotlinx
            url 'https://dl.bintray.com/kotlin/kotlinx/'
        }
        maven {//Alibaba domestic image warehouse
            url 'http://maven.aliyun.com/nexus/content/groups/public/'
        }
        maven {
            url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'
        }
        maven { url 'https://plugins.gradle.org/m2/' }
        maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
        jcenter()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
    }
}
plugins {
    id 'org.jetbrains.kotlin.multiplatform' version '1.3.61'//Configure kotlin multiplatform plug-ins and versions
}
apply plugin: 'kotlinx-serialization'//Reference cross platform serialization plug-ins

repositories {//Project dependent warehouse
    mavenLocal()
    mavenCentral()
    maven {//Configure private maven warehouse
        url QT_RELEASE_URL
        credentials {//Configure private maven warehouse user name and password
            username QT_NAME
            password QT_PASSWORD
        }
        content {//The maven warehouse is configured to be used only when querying the module whose group conforms to "im.qingtui. *"
            // this repository *only* contains artifacts with group "my.company"
            includeGroupByRegex "im\\.qingtui.*"
        }
        mavenContent {//Configure the maven repository to use only when querying the release module
            releasesOnly()
        }
    }

    maven {
        url QT_SNAPSHOT_URL
        credentials {
            username QT_NAME
            password QT_PASSWORD
        }
        content {
            // this repository *only* contains artifacts with group "my.company"
            includeGroupByRegex "im\\.qingtui.*"
        }
        mavenContent {//Configure the maven repository to use only when querying the snapshot module
            snapshotsOnly()
        }
    }
    maven {
        url 'https://dl.bintray.com/kotlin/kotlinx/'
    }
}
group 'im.qingtui.sns'
version '0.0.1-SNAPSHOT'

kotlin {
    jvm()
    js {
        browser {
        }
        nodejs {
        }
    }
    iosArm64("ios") {//Building iOS Library
        binaries {
            framework()
        }
    }
    sourceSets {
        commonMain {...}
        commonTest {...}
        jvmMain {...}
        jvmTest {...}
        jsMain {...}
        jsTest {...}
        iosMain {...}
    }
}


apply plugin: 'maven-publish'//Reference the maven upload plug-in. If it is only packaged locally, it can not be used
publishing {//Configure the information used when maven uploads
    publications {
        maven(MavenPublication) {
            //Specify group/artifact/version information, which can be left blank. By default, the item group/name/version is used as groupId/artifactId/version
            groupId project.group
            artifactId project.name
            version project.version
        }
    }
    repositories {
        maven {
            def VERSION = project.version.toString()
            //Specify the address of maven private server warehouse to upload
            url = VERSION.contains("SNAPSHOT") ? QT_SNAPSHOT_URL : QT_RELEASE_URL
            //Authenticated users and passwords
            credentials {
                username QT_NAME
                password QT_PASSWORD
            }
        }
    }
}

Tips:

The versions of Kotlin, Gradle, Xcode and system all have dependencies,

There are also dependencies on the third-party libraries they depend on

The latest version is recommended

You can view the latest version through maven warehouse search

4, Package and publish

(1) Perform packaging tasks

Open the right gradle panel

Perform the assembly task

Then you can see the build directory in the project directory

(2) Local dependency package

In the build directory, we can find the library files needed by each platform

You can find the framework file required by iOS platform in bin directory. Under the js directory, module s can be used for the js platform. The JVM and Android platform can directly use the xxx-jvm-version.jar file under the libs directory

(3) Upload maven warehouse

We can also use the maven publish plug-in to upload the library to the maven warehouse. The build script will generate jar packages of multiple platforms in different platforms, and then upload them to maven.

apply plugin: 'maven-publish'

After the Maven publish plug-in is referenced in the build.grade file and configured, you can see the corresponding publish task in the panel of gradle on the right

1. Upload to local maven warehouse

Execute the publish to maven local task to package the platform libraries into jars and publish them to the local maven warehouse. We can also selectively publish the jar of a platform to the local maven repository.

2. Remote maven upload

Execute the publish task to package and publish each platform library to the local maven warehouse.

(3) npm warehouse upload

For the upload of npm warehouse, you can directly modify the configuration of package.json under the build/js directory, and then execute the npm publish command to upload

5, Use of Libraries

In fact, kotlin cross platform technology has generated libraries corresponding to each platform for us, and there is no difference in the use of libraries from the past. Android and jvm platform can use the jar package of jvm platform in local or maven warehouse iOS platform can use the framework library file generated under build directory js platform can use build/js directory as module, or upload module to npm

In the next chapter, we will continue to introduce the network library and serialization library that can be used in multiple platforms at the same time, so that the code related to network request can be run in multiple platforms with only one copy.

Published 2 original articles, won praise 0, visited 158
Private letter follow

Posted by koencalliauw on Mon, 02 Mar 2020 00:40:13 -0800