【译】Hello World —— 使用 Kotlin 开发跨平台应用

简介: 【译】Hello World —— 使用 Kotlin 开发跨平台应用

image.png

在移动开发领域,Android 和 iOS 版本的应用程序通常会有很多共同点,背后的业务逻辑基本也是一致的。文件下载,读写数据库,从远程服务器获取数据,解析远程数据等等。所以我们为什么不只写一次业务逻辑代码,在不同的平台上共享呢?

有了这个想法之后,Jetbrains 带来了 Kotlin Multiplatform Project


➡️ 什么是 Kotlin Multiplatform Mobile?


Kotlin Multiplatform Mobile (KMM) 是由 Jetbrains 提供的跨平台移动开发 SDK 。借助 Kotlin 的 跨平台能力,你可以使用一个工程为多个平台编译。

image.png

使用 KMM,具备灵活性的同时也保留了原生编程的优势。为 Android/iOS 应用程序的业务逻辑代码使用单一的代码库,仅在需要的时候编写平台特定代码,例如实现原生的 UI,使用平台特定 API 等等。


KMM 可以和你的工程无缝集成。共享代码,使用 Kotlin 编写,使用 Kotlin/JVM 编译成 JVM 字节码,使用 Kotlin/Native 编译成二进制,所以你可以和使用其他一般类库一样使用 KMM 业务逻辑模块。


在写这篇博客的同时,KMM 仍然处于 Alpha,你可以开始尝试在你的应用中共享业务逻辑代码。


在移动开发领域,KMM 目前没有为大众所熟知。Jetbrains 开发了 Android Studio 的 KMM 插件 来帮助你快速设置 KMM 工程。插件还可以帮助你编写,运行,测试共享代码。


➡️ 一步一步构建 HELLO WORLD KMM 应用



  1. 在 Android Studio 上安装 Kotlin Multiplatform Mobile 插件。打开 Android Studio -> 点击 Configure -> 选择 Plugins

image.png

  1. 在 plugins 部分选择 Marketplace ,搜索 KMM,安装并重启 Android Studio。

image.png

  1. 在 Android Studio 首页选择 “Start a new Android Studio project” 。

image.png

  1. 在 “Select a project Template” 页面,选择 “KMM Application” 。

image.png

  1. 设置工程名称,最低 SDK,文件目录,包名等。

image.png

现在,你需要等待工程的第一次构建,需要花费一些时间去下载和设置必要的组件。

译者注:KMM 插件要求你的 Kotlin 插件版本至少为 4.0 版本以上


➡️ 运行你的程序



在菜单栏选择你要运行的平台,选择设备,点击 Run

image.png

image.png

image.png


要运行 iOS 应用,你需要安装 Xcode 和模拟器。


➡️ 瞅一眼代码



image.png

Android 开发者? 看起来很熟悉? 😎

IOS 开发者? 看起来就像外星人? 👽


➡️ 模块


  • shared 模块 —— 存放 Android/iOS 通用业务逻辑代码的 Kotlin 模块,会被编译为 Android library 和 iOS framework。使用 Gradle 进行构建。
  • androidApp 模块 —— Android 应用的 Kotlin 模块。使用 Gradle 构建。
  • iosApp 模块 —— 构建 iOS 应用的 Xcode 工程。

Project 的 build.gradle.kts 文件:

buildscript {
    repositories {
        gradlePluginPortal()
        jcenter()
        google()
        mavenCentral()
    }
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.10")
        classpath("com.android.tools.build:gradle:4.0.1")
    }
}
group = "com.aman.helloworldkmm"
version = "1.0-SNAPSHOT"
repositories {
    mavenCentral()
}
复制代码


➡️ Shared module


shared 模块包含了Android 和 iOS 的公用代码。但是,为了在 Android/iOS 上实现同样的逻辑,有时候你不得不写两份版本特定代码,例如蓝牙,Wifi 等等。为了处理这种情况,Kotlin 提供了 expect/actual 机制。shared 模块的源代码按三个源集进行分类:

image.png

  • commonMain 下存储为所有平台工作的代码,包括 expect 声明
  • androidMain 下存储 Android 的特定代码,包括 actual 实现
  • iosMain 下存储 iOS 的特定代码,包括 actual 实现


每一个源集都有自己的依赖,Kotlin 标准库依赖会自动添加到所有源集,你不需要在编译脚本中声明。

build.gradle.kts

这份 build.gradle.kts 文件包含了 shared 模块对于 Android/iOS 的配置。


import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
    kotlin("multiplatform")
    id("com.android.library")
    id("kotlin-android-extensions")
}
group = "com.aman.helloworldkmm"
version = "1.0-SNAPSHOT"
repositories {
    gradlePluginPortal()
    google()
    jcenter()
    mavenCentral()
}
kotlin {
    android()
    ios {
        binaries {
            framework {
                baseName = "shared"
            }
        }
    }
    sourceSets {
        val commonMain by getting
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("com.google.android.material:material:1.2.0")
            }
        }
        val androidTest by getting {
            dependencies {
                implementation(kotlin("test-junit"))
                implementation("junit:junit:4.12")
            }
        }
        val iosMain by getting
        val iosTest by getting
    }
}
android {
    compileSdkVersion(29)
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdkVersion(24)
        targetSdkVersion(29)
        versionCode = 1
        versionName = "1.0"
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
        }
    }
}
val packForXcode by tasks.creating(Sync::class) {
    group = "build"
    val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
    val sdkName = System.getenv("SDK_NAME") ?: "iphonesimulator"
    val targetName = "ios" + if (sdkName.startsWith("iphoneos")) "Arm64" else "X64"
    val framework = kotlin.targets.getByName<KotlinNativeTarget>(targetName).binaries.getFramework(mode)
    inputs.property("mode", mode)
    dependsOn(framework.linkTask)
    val targetDir = File(buildDir, "xcode-frameworks")
    from({ framework.outputDirectory })
    into(targetDir)
}
tasks.getByName("build").dependsOn(packForXcode)
复制代码


androidApp 模块的 build.gradle.kts 文件

plugins {
    id("com.android.application")
    kotlin("android")
    id("kotlin-android-extensions")
}
group = "com.aman.helloworldkmm"
version = "1.0-SNAPSHOT"
repositories {
    gradlePluginPortal()
    google()
    jcenter()
    mavenCentral()
}
dependencies {
    implementation(project(":shared"))
    implementation("com.google.android.material:material:1.2.0")
    implementation("androidx.appcompat:appcompat:1.2.0")
    implementation("androidx.constraintlayout:constraintlayout:1.1.3")
}
android {
    compileSdkVersion(29)
    defaultConfig {
        applicationId = "com.aman.helloworldkmm.androidApp"
        minSdkVersion(24)
        targetSdkVersion(29)
        versionCode = 1
        versionName = "1.0"
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
        }
    }
}
复制代码


➡️ 使用  Expect/Actual 关键字



对于跨平台应用来说,版本特定代码是很常见的。例如你可能想知道你的应用是运行在 Android 还是 iOS 设备,并且得到设备的具体型号。为了完成这个功能,你需要使用 expect/actual 关键字。


首先,在 common 模块中使用 expect 关键字声明一个空的类或函数,就像创建接口或者抽象类一样。然后,在所有的其他模块中编写平台特定代码来实现对应的类或函数,并用 actual 修饰。

image.png

注意,如果你使用了 expect,你必须提供对应名称的 actual 实现。

否则,你会得到如下错误:

image.png

➡️ Expect/Actual 的使用



commonMain

expect class Platform() {
    val platform: String
}
复制代码


androidMain

actual class Platform actual constructor() {
    actual val platform: String = "Android ${android.os.Build.VERSION.SDK_INT}"
}
复制代码


iosMain

import platform.UIKit.UIDevice
actual class Platform {
    actual val platform: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
}
复制代码


MainActivity.kt (Android)

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val tv: TextView = findViewById(R.id.text_view)
        tv.text = "Hello World, ${Platform().platform}!"
    }
}
复制代码


ContentView.swift (iOS)

struct ContentView: View {
    var body: some View {
        Text("Hello World, "+ Platform().platform)
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
复制代码


恭喜!! 你已经完成了你的第一个 KMM app 。


➡️开源 KMM 应用



➡️ 可用的 KMM 类库


AAkira/Kotlin-Multiplatform-Libraries


译者说


在已经一片红海的移动端跨平台开发领域,Kotlin 另辟蹊径,让你可以继续使用平台原生方式开发 UI,在业务逻辑上做到 “Write once,run everywhere”。甚至放飞一下自我,未来的某一天是不是可以用 Flutter 做 UI 上的通用,用 Kotlin 做业务逻辑上的通用?

不管怎样,最终还是得开发者买账才行。不知道你怎么看 KMM,在评论区留下的你的看法吧!



相关文章
|
23天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。
|
24天前
|
数据库 Android开发 开发者
构建高效Android应用:Kotlin协程的实践指南
【4月更文挑战第2天】随着移动应用开发的不断进步,开发者们寻求更流畅、高效的用户体验。在Android平台上,Kotlin语言凭借其简洁性和功能性赢得了开发社区的广泛支持。特别是Kotlin协程,作为一种轻量级的并发处理方案,使得异步编程变得更加简单和直观。本文将深入探讨Kotlin协程的核心概念、使用场景以及如何将其应用于Android开发中,以提高应用性能和响应能力。通过实际案例分析,我们将展示协程如何简化复杂任务,优化资源管理,并为最终用户提供更加流畅的体验。
|
1月前
|
调度 数据库 Android开发
构建高效Android应用:Kotlin协程的实践与优化
在Android开发领域,Kotlin以其简洁的语法和平台友好性成为了开发的首选语言。其中,Kotlin协程作为处理异步任务的强大工具,它通过提供轻量级的线程管理机制,使得开发者能够在不阻塞主线程的情况下执行后台任务,从而提升应用性能和用户体验。本文将深入探讨Kotlin协程的核心概念,并通过实例演示如何在实际的Android应用中有效地使用协程进行网络请求、数据库操作以及UI的流畅更新。同时,我们还将讨论协程的调试技巧和常见问题的解决方法,以帮助开发者避免常见的陷阱,构建更加健壮和高效的Android应用。
36 4
|
1月前
|
移动开发 Java Android开发
构建高效Android应用:Kotlin协程的实践之路
【2月更文挑战第31天】 在移动开发领域,性能优化和流畅的用户体验一直是开发者追求的目标。随着Kotlin语言的流行,其异步编程解决方案——协程(Coroutines),为Android应用带来了革命性的并发处理能力。本文将深入探讨Kotlin协程的核心概念、设计原理以及在Android应用中的实际应用案例,旨在帮助开发者掌握这一强大的工具,从而提升应用的性能和响应能力。
|
1月前
|
安全 Android开发 开发者
构建高效Android应用:Kotlin与协程的完美结合
【2月更文挑战第30天】在移动开发领域,性能优化和流畅的用户体验是关键。本文深入探讨了如何通过结合Kotlin语言和协程技术来提升Android应用的性能和响应能力。我们将分析Kotlin的优势,介绍协程的基本概念,并通过实际案例展示如何在应用中实现协程以简化异步编程,从而提供更加高效的解决方案。
|
1月前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【2月更文挑战第30天】 随着Kotlin成为开发Android应用的首选语言,开发者社区对于其性能表现持续关注。本文通过深入分析与基准测试,探讨Kotlin与Java在Android平台上的性能差异,揭示两种语言在编译效率、运行时性能和内存消耗方面的具体表现,并提供优化建议。我们的目标是为Android开发者提供科学依据,帮助他们在项目实践中做出明智的编程语言选择。
|
1月前
|
移动开发 调度 Android开发
构建高效Android应用:探究Kotlin协程的优势与实践
【2月更文挑战第30天】 在移动开发领域,尤其是针对Android平台,性能优化和应用流畅度始终是开发者关注的重点。近年来,Kotlin语言凭借其简洁性和功能性成为Android开发的热门选择。其中,Kotlin协程作为一种轻量级的线程管理解决方案,为异步编程提供了强大支持,使得编写非阻塞性代码变得更加容易。本文将深入分析Kotlin协程的核心优势,并通过实际案例展示如何有效利用协程提升Android应用的性能和响应速度。
|
1月前
|
数据库 Android开发 开发者
构建高效Android应用:采用Kotlin协程优化网络请求处理
【2月更文挑战第30天】 在移动应用开发领域,网络请求的处理是影响用户体验的关键环节。针对Android平台,利用Kotlin协程能够极大提升异步任务处理的效率和简洁性。本文将探讨如何通过Kotlin协程优化Android应用中的网络请求处理流程,包括协程的基本概念、网络请求的异步执行以及错误处理等方面,旨在帮助开发者构建更加流畅和响应迅速的Android应用。
|
25天前
|
Java Android开发 开发者
构建高效Android应用:Kotlin协程的实践与优化
在响应式编程范式日益盛行的今天,Kotlin协程作为一种轻量级的线程管理解决方案,为Android开发带来了性能和效率的双重提升。本文旨在探讨Kotlin协程的核心概念、实践方法及其在Android应用中的优化策略,帮助开发者构建更加流畅和高效的应用程序。通过深入分析协程的原理与应用场景,结合实际案例,本文将指导读者如何优雅地解决异步任务处理,避免阻塞UI线程,从而优化用户体验。
|
30天前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
在开发高性能的Android应用时,选择合适的编程语言至关重要。近年来,Kotlin因其简洁性和功能性受到开发者的青睐,但其性能是否与传统的Java相比有所不足?本文通过对比分析Kotlin与Java在Android平台上的运行效率,揭示二者在编译速度、运行时性能及资源消耗方面的具体差异,并探讨在实际项目中如何做出最佳选择。
18 4