- 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.