用 KMM(kotlin)创建Android和iOS跨平台应用 下
Kotlin
25490 人阅读
|
0 人回复
|
2020-09-27
|
*本帖最后由 LazyGirl 于 2020-10-19 08:27 编辑*
由于篇幅限制,请看上部分:[https://www.harm-os.com/thread-6-1-1.html](https://www.harm-os.com/thread-6-1-1.html) 用 KMM(kotlin)创建Android和iOS跨平台应用 上
## 共享模块
共享模块包含 Android 和 iOS 应用程序通用的代码。然而,为了在 Android 和 iOS 上实现同样的逻辑,有时候你需要编写两个平台特定的版本,比如蓝牙、 Wifi。为了处理这种情况,Kotlin 提供了预期/实际机制。共享模块的源代码相应地组织成三个源集:
- commonMain stores the code that works on both platforms, including the 存储在两个平台上工作的代码,包括expect declarations 声明
- androidMain stores Android-specific parts, including 存储特定于 android 的部件,包括actual implementations 实现
- iosMain stores iOS-specific parts, including 存储特定于 ios 的部件,包括actual implementations 实现
每个源都有自己的依赖项。Kotlin 标准库自动添加到所有源代码集中,您不需要在构建脚本中声明它。
**build.gradle.kts**
build.gradle.kts 拥有 Android 和 IOS 的共享模块配置:
```java
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
```kotlin
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**的关键字。
首先,使用 expect 关键字在通用模块中声明类、方法或函数,并像创建接口或抽象类时经常做的那样保持主体为空。然后,使用签名中的实际关键字在所有其他模块中编写类、方法或函数的特定于平台的实现。
注意: 如果您在包中使用 expect,那么您还需要在具有相同名称的包中使用相应的实际命令。
否则就会出现这个错误:
```kotlin
expect class Platform() {
val platform: String
}
```
```kotlin
actual class Platform actual constructor() {
actual val platform: String = "Android ${android.os.Build.VERSION.SDK_INT}"
}
```
```kotlin
import platform.UIKit.UIDevice
actual class Platform {
actual val platform: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
}
```
MainActivity.kt (Android):
```kotlin
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)
```kotlin
struct ContentView: View {
var body: some View {
Text("Hello World, "+ Platform().platform)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
```
恭喜你! ! 你已经开发了你的第一个 KMM 应用。
|
|
|
|
|
|