国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
iOS跨平臺(tái)開(kāi)發(fā):Kotlin Multiplatform入門(mén)

本文要點(diǎn)

  • Kotlin Multiplatform 讓開(kāi)發(fā)者在開(kāi)發(fā)跨平臺(tái)應(yīng)用時(shí)省去很多重復(fù)編寫(xiě)代碼邏輯的麻煩。

  • 用 KMP 并不能做出在各個(gè)平臺(tái)完全共享的代碼,因?yàn)楹芏鄷r(shí)候 UI 邏輯需要原生編程,各平臺(tái)的邏輯很難通用。

  • Swift 和 Kotlin 語(yǔ)法有很高的相似度,這極大降低了學(xué)習(xí)使用 KMP 業(yè)務(wù)邏輯的難度。

  • 可以使用 Android Studio 創(chuàng)建可復(fù)用的 KMP 組件,然后將其作為框架導(dǎo)入 Xcode 項(xiàng)目。

iOS 開(kāi)發(fā)者的福音:Kotlin Multiplatform

DRY(避免重復(fù)勞動(dòng))是編程的基本原則之一,但開(kāi)發(fā)跨平臺(tái)應(yīng)用時(shí)經(jīng)常需要重復(fù)編寫(xiě)許多代碼邏輯。出色的編程工作就是要盡量減少重復(fù)勞動(dòng),而應(yīng)用使用的跨平臺(tái)共享代碼越多,重復(fù)勞動(dòng)越少,代碼質(zhì)量也就越高。

想想你正在開(kāi)發(fā)的 iOS 項(xiàng)目:它是否支持 Android 或 web 等平臺(tái)?如果答案是肯定的,那么你的 iOS 應(yīng)用與其它平臺(tái)的版本共享了多少代碼邏輯? 如果答案是否定的,但你準(zhǔn)備開(kāi)發(fā)支持其它平臺(tái)的版本,那么跨平臺(tái)開(kāi)發(fā)會(huì)帶來(lái)多少重復(fù)勞動(dòng)?不管是哪個(gè)問(wèn)題,答案都很可能是”很多“。

了解一下 Kotlin Multiplatform (KMP)吧。Kotlin 是一種靜態(tài)類(lèi)型的編程語(yǔ)言,與 Swift 有著驚人的相似度,并可與 Java 完全互操作。從某些角度來(lái)看,你可以把它當(dāng)作是 Android 上的 Swift。KMP 是 Kotlin 的一項(xiàng)功能組件,用它可以在應(yīng)用的各平臺(tái)版本之間共享代碼,這樣各個(gè)平臺(tái)的原生 UI 就可以調(diào)用公共的底層代碼了。KMP 并不能實(shí)現(xiàn)跨平臺(tái)版本之間完全共享代碼,但它也向這一目標(biāo)邁出了重要的一步。

KMP 使用 Kotlin 來(lái)編寫(xiě)跨平臺(tái)應(yīng)用中通用的業(yè)務(wù)邏輯。接下來(lái)各個(gè)平臺(tái)的原生 UI 會(huì)調(diào)用這些公共邏輯。很多時(shí)候 UI 邏輯還是要原生開(kāi)發(fā)的,因?yàn)楦鱾€(gè)平臺(tái)的差異太大了。在 iOS 中,這意味著要將用 KMP 編寫(xiě)的.frameworkfile 像其它外部庫(kù)一樣導(dǎo)入到 Xcode 項(xiàng)目中。在 iOS 上使用 KMP 也要用到 Swift 語(yǔ)言,所以 KMP沒(méi)法取代 Swift

KMP 也可以迭代式引入項(xiàng)目,所以實(shí)現(xiàn) KMP 不需要中斷當(dāng)前項(xiàng)目,不需要替換現(xiàn)有的 Swift 代碼。你只要在下次為跨平臺(tái)應(yīng)用加入新功能的時(shí)候使用 KMP 編寫(xiě)業(yè)務(wù)邏輯,然后將其部署到各個(gè)平臺(tái),并開(kāi)發(fā)原生 UI 就行了。在 iOS 這邊,就是用 Kotlin 開(kāi)發(fā)業(yè)務(wù)邏輯并用 Swift 開(kāi)發(fā) UI 邏輯。

Swift 和 Kotlin 的語(yǔ)法高度相似,所以學(xué)習(xí)用 KMP 編寫(xiě)業(yè)務(wù)邏輯會(huì)非常容易。需要下功夫?qū)W習(xí)的就只有一個(gè) IDE 了:那就是 Android Studio。

Kotlin Multiplatform 項(xiàng)目仍然是 Kotlin 的實(shí)驗(yàn)性功能組件,所以每次更新后其 API 都可能有改動(dòng)。

入門(mén)

本教程適用于幾乎沒(méi)接觸過(guò) Android Studio 或 Kotlin 的 iOS 開(kāi)發(fā)者。如果你還沒(méi)有安裝 Android Studio,請(qǐng)按照安裝指南操作。

把我們制作的入門(mén)項(xiàng)目克隆下來(lái)。它帶有一個(gè) KMP 樣板項(xiàng)目,其中有一個(gè)空的 KMP 庫(kù)。這個(gè)入門(mén)項(xiàng)目還有一個(gè) iOS 應(yīng)用和一個(gè) Android 應(yīng)用,兩個(gè)應(yīng)用都是用來(lái)顯示一個(gè) URL 列表的 GIF 圖片的,列表中有 25 個(gè)硬編碼的“meh”URL。

這兩個(gè)應(yīng)用是為你準(zhǔn)備的,但那個(gè)庫(kù)不是,因?yàn)楸疚牡闹攸c(diǎn)就是如何制作一個(gè) KMP 庫(kù),不是教你應(yīng)用該如何使用 KMP 庫(kù)。但請(qǐng)放心,如果你想深入了解 Android 開(kāi)發(fā)的話(huà),這篇文章教你的知識(shí)也會(huì)很有用。

你要用 KMP 編寫(xiě)網(wǎng)絡(luò)邏輯,在 Giphy 的公共 API 中搜索短語(yǔ)“whoa”,獲取 25 個(gè) URL,替換掉兩個(gè)平臺(tái)中原來(lái)的硬編碼地址。

現(xiàn)在打開(kāi) Android Studio,選擇Open an existing Android Studio project。在彈出的Finder窗口中選擇之前克隆來(lái)的啟動(dòng)項(xiàng)目的頂級(jí)GifGetter/目錄。

如果彈出這個(gè)對(duì)話(huà)框,請(qǐng)按“Update”。

Android Studio

如果你之前沒(méi)有深入研究過(guò) Android Studio,可能就要花些時(shí)間先來(lái)熟悉它了。這一章會(huì)講解本教程用到的 Android Studio 的一些功能。如果你想深入了解這個(gè) IDE,請(qǐng)點(diǎn)擊此處。

首先是基礎(chǔ)操作:左邊是項(xiàng)目導(dǎo)航器,應(yīng)該會(huì)顯示項(xiàng)目的文件結(jié)構(gòu)。如果沒(méi)看到文件結(jié)構(gòu),請(qǐng)點(diǎn)擊左上角的“Projcet”選項(xiàng)卡,彈出項(xiàng)目導(dǎo)航器。在項(xiàng)目導(dǎo)航器頂部,你很可能會(huì)看到標(biāo)有Android的下拉菜單。點(diǎn)一下,然后在下拉菜單中選擇“Project”選項(xiàng)。

  1. Android Studio 頂部的按鈕行是工具欄。這一欄有許多功能,如構(gòu)建、運(yùn)行、調(diào)試運(yùn)行、應(yīng)用新更改以及啟動(dòng) Android 虛擬設(shè)備(AVD)管理器。在它下面是導(dǎo)航欄,顯示項(xiàng)目文件夾結(jié)構(gòu)中當(dāng)前打開(kāi)文件的位置,在本例中為:

/GifGetter/GifLibrary/commonMain/kotlin/platform/common.kt

  • 以下是工具欄中的一些工具介紹:

  • 錘子圖形是 Build 按鈕

  • 旁邊的下拉列表是 configurations

  • 它旁邊是 Run 按鈕,就像在 Xcode 中一樣

  1. Android 的官方文檔把它叫做工具窗口之一,但人們一般叫它項(xiàng)目結(jié)構(gòu)、文件結(jié)構(gòu)、文件夾結(jié)構(gòu)或類(lèi)似術(shù)語(yǔ)。它和 Xcode 中的項(xiàng)目導(dǎo)航器是一個(gè)用途。
  • 請(qǐng)注意頂部的Project下拉菜單。這里它應(yīng)該指的是本教程使用的Project。如果它顯示的是Android或別的什么內(nèi)容,請(qǐng)重新選擇Project,否則你的文件和文件夾可能會(huì)在下面的結(jié)構(gòu)視圖里顯示不全。
  1. 這里是編輯器窗口,寫(xiě)代碼用的。注意頂部的文件:android.kt、common.kt、ios.ktGifLibrary,這些都是當(dāng)前打開(kāi)的后臺(tái)選項(xiàng)卡。右鍵單擊其中一個(gè)選項(xiàng)卡就有選項(xiàng)可以在右側(cè)、左側(cè)、頂部或底部打開(kāi)更多的編輯器窗口。

  2. 包在外面一圈的叫工具窗口欄,這里只用到黃圈中的選項(xiàng)卡,尤其是TerminalBuild這倆。

項(xiàng)目結(jié)構(gòu)

下面介紹 KMP 的項(xiàng)目結(jié)構(gòu):

  1. **.gradle/.idea/** 文件夾:這里存放的是本地文件,不要把它們提交到多數(shù) Android Studio 項(xiàng)目會(huì)使用的源碼管理平臺(tái)里。它們包括 IDE、項(xiàng)目和依賴(lài)項(xiàng)的本地設(shè)置,因此與本教程無(wú)關(guān)。
  2. androidApp/文件夾:這是整個(gè) KMP 項(xiàng)目中 Android 應(yīng)用項(xiàng)目的根目錄,其中有 Android 端的所有 UI 邏輯。
  3. build/文件夾:存放 KMP 構(gòu)建的輸出。它也不要提交到源代碼管理平臺(tái)上。
  4. iosApp/文件夾:整個(gè) KMP 項(xiàng)目中 Xcode 項(xiàng)目的根目錄。

GifLibrary/文件夾:KMP 邏輯的主目錄。它將作為 Android 項(xiàng)目的業(yè)務(wù)邏輯,然后 KMP 將它生成為 iOS 項(xiàng)目使用的GifLibrary.framework。其中src/文件夾包含以下內(nèi)容:

  • androidLibMain:Android 平臺(tái)專(zhuān)用的 KMP 邏輯

  • commonMain:不需要任何平臺(tái)專(zhuān)屬代碼的 KMP 業(yè)務(wù)邏輯

  • iosMain:iOS 平臺(tái)專(zhuān)用的 KMP 邏輯,能夠與 Apple API 交互(如 UIKit、GCD 等)

  • main:包含一個(gè)AndroidManifest.xml文件,該文件將GifLibrary/定義為 Android 庫(kù)。很大程度上它就像一個(gè) Xcode.plist。

  1. build.gradle:這可能是一個(gè)新概念,因?yàn)?iOS 開(kāi)發(fā)中沒(méi)有直接對(duì)應(yīng)的概念。某種層次上它是一個(gè)構(gòu)建腳本或 makefile,用于定義項(xiàng)目的依賴(lài)項(xiàng)、腳本和其它設(shè)置。這樣來(lái)看,它也有點(diǎn)像.xcodeproj 文件。
  2. External Libraries:項(xiàng)目的所有依賴(lài)項(xiàng)。Android 和 KMP 項(xiàng)目與 iOS 項(xiàng)目的不同之處在于前者需要的外部依賴(lài)項(xiàng)要多很多。

項(xiàng)目頂層的其它文件(如local.properties和所有.iml 文件)由 Android Studio 生成,與我們?cè)?KMP 中的操作無(wú)關(guān)。另外,settings.gradle是應(yīng)提交到源代碼控制中的配置文件。與build.gradle文件不同,settings.gradle不是構(gòu)建腳本,而是 gradle 的配置文件。

現(xiàn)在你已經(jīng)了解了 Android Studio 的基礎(chǔ)知識(shí),該來(lái)研究 KMP 項(xiàng)目了!

為 KMP 配置 Gradle

  • 注意:如前所述,KMP 仍然是實(shí)驗(yàn)性組件,因此這些 gradle 配置很容易發(fā)生變化。

打開(kāi)GifLibrary/build.gradle,然后看 kotlin {}塊:

復(fù)制代碼
kotlin {
targets {
fromPreset(presets.android, 'androidLib')
def buildForDevice = project.findProperty("device")?.toBoolean() ?: false
def iosPreset = (buildForDevice) ? presets.iosArm64 : presets.iosX64
def iOSTarget = System.getenv('SDK_NAME')?.startsWith('iphoneos') \
? presets.iosArm64 : presets.iosX64
fromPreset(iosPreset, 'ios') {
binaries {
framework {
// Disable bitcode embedding for the simulator build.
if (!buildForDevice) {
embedBitcode("disable")
}
}
}
}
fromPreset(iOSTarget, 'ios') {
compilations.main.outputKinds('FRAMEWORK')
}
}
sourceSets {
commonMain {
dependencies {
implementation "io.ktor:ktor-client-json:$ktor_version"
}
}
}

這是新建項(xiàng)目常見(jiàn)的 KMP gradle 配置。首先看一下 kotlin {}塊內(nèi)的 targets {}塊。簡(jiǎn)單來(lái)說(shuō),fromPreset() {}為 gradle 提供了 KMP 的預(yù)設(shè)配置。iOS 的預(yù)設(shè)需要額外的代碼,因?yàn)樵O(shè)備和模擬器構(gòu)建所需的預(yù)設(shè)不一樣。

然后看一下 sourceSets {}塊?,F(xiàn)在只有 commonMain 是有其它依賴(lài)項(xiàng)的 sourceSet,但另外兩個(gè) sourceSet 也需要其它依賴(lài)項(xiàng)。在 commonMain {}之后將以下內(nèi)容添加到 sourceSets {}:

復(fù)制代碼
androidLibMain {
dependencies {
implementation "io.ktor:ktor-client-json-jvm:$ktor_version"
}
}
iosMain {
dependencies {
implementation "io.ktor:ktor-client-ios:$ktor_version"
implementation "io.ktor:ktor-client-json-native:$ktor_version"
}
}

添加成功后應(yīng)該會(huì)彈出一個(gè)消息框說(shuō):Gradle files have changed since the last project sync. A project sync may be necessary for the IDE to work properly(自上次項(xiàng)目同步以來(lái) Gradle 文件已更改。IDE 可能需要項(xiàng)目同步才能正常工作)。暫時(shí)忽略此消息,因?yàn)檫@個(gè) gradle 文件還要做很多改動(dòng)。

現(xiàn)在三個(gè)必需的依賴(lài)項(xiàng)都已包含在 sourceSets 中了,但還需要最后一次更改才能讓這個(gè) gradle 準(zhǔn)備就緒。在 kotlin {}塊下面有一個(gè)名為 copyFramework {}的 task,它負(fù)責(zé)將 KMP 項(xiàng)目作為 iOS 框架復(fù)制到相應(yīng)的文件夾中,這樣iosApp/ project 就能找到它了。

為了確保在項(xiàng)目構(gòu)建時(shí)執(zhí)行這些 task,請(qǐng)?jiān)?copyFramework {}之后插入下面這行:

復(fù)制代碼
tasks.build.dependsOn copyFramework

現(xiàn)在點(diǎn)擊Sync Now以更新 gradle 文件。需要下載新的依賴(lài)項(xiàng)時(shí)可能要花些時(shí)間。你可以在 Android Studio 底部的標(biāo)簽欄中查看 Gradle 同步的進(jìn)度。

探索 Giphy 的 API

先去查閱 Giphy 的 API 并創(chuàng)建一個(gè) Giphy 開(kāi)發(fā)者帳戶(hù)。如果你已經(jīng)有帳戶(hù)就登錄進(jìn)去。然后點(diǎn)擊“Create an App”并在出現(xiàn)提示時(shí)輸入“GifGetter”和描述信息。然后復(fù)制新生成的 Api 密鑰。

現(xiàn)在返回 Android Studio 并打開(kāi)GifLibrary/src/commonMain/kotlin/GiphyAPI并找到以下類(lèi):

復(fù)制代碼
class GiphyAPI {
val apiKey:String =“”
}

將你的 Giphy API 密鑰粘貼到這個(gè) val 語(yǔ)句的值中。這就是在 Kotlin 中聲明類(lèi)和字符串常量的方式。注意到目前為止,所有這些代碼都可以用在 Swift 里,只有 val 關(guān)鍵字是例外,在 Kotlin 中它等同于 Swift 的 let。

平臺(tái)專(zhuān)屬代碼

針對(duì) iOS 和 Android 平臺(tái)的差異部分,KMP 會(huì)告訴公共代碼在各個(gè)平臺(tái)會(huì)得到怎樣的反饋。先轉(zhuǎn)到GifLibrary/src/commonMain/kotlin/platform/。點(diǎn)擊FileNewKotlin File/Class,然后創(chuàng)建一個(gè)新的 Kotlin 文件 / 類(lèi)并將其命名為common。然后在下面的 Kinddropdown 菜單中點(diǎn)擊 File。

這些 iOS 和 Android 應(yīng)用需要做網(wǎng)絡(luò)調(diào)用,因此他們需要運(yùn)行異步代碼。iOS 使用 Grand Central Dispatch(GCD)處理此類(lèi)并發(fā)操作,但由于 Android 不使用 GCD 所以這部分代碼不能進(jìn)入公共部分。相對(duì)應(yīng)的,你要告訴公共代碼它們能從各個(gè)平臺(tái)得到的期望expect。本例中,公共代碼需要期望獲得以下調(diào)度器 dispatcher:

復(fù)制代碼
import kotlinx.coroutines.CoroutineDispatcher
internal expect val dispatcher: CoroutineDispatcher

這里將出現(xiàn)錯(cuò)誤,因?yàn)?strong>iosMan/androidLibMain/組件現(xiàn)在期望聲明一個(gè)類(lèi)型為 CoroutineDispatcher 的常量命名 dispatcher。在 iOS 這邊,轉(zhuǎn)到 GifLibrary/src/iosMain/platform/ 并創(chuàng)建一個(gè)名為 iOS 的新文件粘貼到下面的代碼里:

復(fù)制代碼
internal actual val dispatcher: CoroutineDispatcher = NsQueueDispatcher(dispatch_get_main_queue())
internal class NsQueueDispatcher(private val dispatchQueue: dispatch_queue_t) : CoroutineDispatcher() {
override fun dispatch(context: CoroutineContext, block: Runnable) {
dispatch_async(dispatchQueue.freeze()) {
block.run()
}
}
}

這個(gè)邏輯是說(shuō),對(duì)于 iOS 平臺(tái),KMP 將使用 GCD 獲取主隊(duì)列來(lái)運(yùn)行異步代碼。Android 這邊,轉(zhuǎn)到 Android 模塊中的對(duì)應(yīng)文件夾:GifLibrary/src/androidLibMain/platform/。創(chuàng)建另一個(gè) Kotlin 文件并將其命名為Android。所幸 Android 平臺(tái)上可以輕松獲取主調(diào)度器:

復(fù)制代碼
internal actual val dispatcher: CoroutineDispatcher = Dispatchers.Main

這樣應(yīng)該就不會(huì)出現(xiàn)編譯錯(cuò)誤了,因?yàn)?commonMain 對(duì)兩個(gè)平臺(tái)各自期望的調(diào)度器都已經(jīng)獲得了對(duì)應(yīng)的實(shí)現(xiàn)。

準(zhǔn)備數(shù)據(jù)

現(xiàn)在我們需要能夠代表我們從 Giphy API 獲得的 JSON 數(shù)據(jù)的類(lèi)。去GifLibrary/src/commonMain/kotlin/中創(chuàng)建一個(gè)新的 Kotlin 文件,將其命名為Data。將以下代碼粘貼到新文件中:

復(fù)制代碼
import kotlinx.serialization.Serializable
@Serializable
data class GifResult(
val `data`: List
<
Data
>
)
@Serializable
data class Data(
val images: Images
)
@Serializable
data class Images(
val original: Original
)
@Serializable
data class Original(
val url: Stri

在這個(gè)文件頂部必須導(dǎo)入Serializable 以識(shí)別數(shù)據(jù)類(lèi)前面的 @Serializable 語(yǔ)句。數(shù)據(jù)類(lèi)可以視為 Swift 中的結(jié)構(gòu)。它們不是值類(lèi)型對(duì)象,但它們的行為很像后者。從 Giphy API 獲得的 JSON 將映射到這些數(shù)據(jù)類(lèi)上?,F(xiàn)在,commonMain 已經(jīng)為大部分業(yè)務(wù)邏輯做好了準(zhǔn)備。

編寫(xiě) KMP 業(yè)務(wù)邏輯

現(xiàn)在回到GiphyAPI文件并將以下代碼粘貼到 apiKey 下面:

復(fù)制代碼
private val client: HttpClient = HttpClient { // 1
install(JsonFeature) { // 2
serializer = KotlinxSerializer(Json.nonstrict).apply { // 3
setMapper(GifResult::class, GifResult.serializer()) // 4
}
}
}
private fun HttpRequestBuilder.apiUrl(path: String) { // 5
url { // 6
takeFrom("https://api.giphy.com/") // 7
encodedPath = path // 8
}
}

下面逐條解釋這段代碼的效果:

  1. 聲明一個(gè)類(lèi)型為 HttpClient 的常量。這一行代碼與 Swift 中寫(xiě)法的唯一區(qū)別還是關(guān)鍵字 val,不是 Swift 中的 let。
  2. 將 JsonFeature 安裝到 client 對(duì)象中,使其能夠序列化和反序列化 JSON。
  3. 實(shí)例化并配置 serializer,這是 HttpClient 對(duì)象的一個(gè)屬性,默認(rèn)值為 null。Json.nonstrict 格式表示響應(yīng)的 JSON 將包含與下一行設(shè)置的數(shù)據(jù)類(lèi)無(wú)關(guān)的字段。
  4. 為 serializer 提供頂級(jí)數(shù)據(jù)類(lèi),然后它會(huì)將響應(yīng)的 JSON 序列化為 GifResult 對(duì)象。JSON 中的“data”字段將填充對(duì)應(yīng)的 GifResult.data 屬性。這些字段將繼續(xù)填充嵌套數(shù)據(jù)類(lèi)的層次結(jié)構(gòu)。
  5. 將函數(shù) apiUrl(path:String) 添加到 HttpRequestBuilder 類(lèi)。
  6. 構(gòu)造一個(gè) URL。
  7. 提供基礎(chǔ) URL。
  8. 使用指定的路徑擴(kuò)展 URL。

現(xiàn)在有了網(wǎng)絡(luò)邏輯模版,就該對(duì) Giphy 的端點(diǎn)做聯(lián)網(wǎng)調(diào)用以獲取“whoa”的搜索結(jié)果了。在你剛粘貼的網(wǎng)絡(luò)代碼下面添加以下代碼:

復(fù)制代碼
suspend fun callGiphyAPI(): GifResult = client.get {
apiUrl(path = "v1/gifs/trending?api_key=$apiKey&limit=25&rating=G")
}

等一下,suspend 關(guān)鍵字是哪里來(lái)的?有什么用?其實(shí)這是通過(guò)協(xié)程在 Kotlin 中執(zhí)行異步代碼的一種方法。現(xiàn)在你只要知道這里只能從一個(gè)協(xié)程或其它掛起函數(shù)調(diào)用該函數(shù)就行了,例如 HttpClient 上的 get {}函數(shù)。

下一步是設(shè)置可用于 iOS 和 Android 應(yīng)用的函數(shù)。這里的語(yǔ)法又很接近 Swift:

復(fù)制代碼
fun getGifUrls(callback: (List
<
String
>
) -> Unit) { // 1
GlobalScope.apply { // 2
launch(dispatcher) { // 3
val result: GifResult = callGiphyAPI() // 4
val urls = result.data.map { // 5
it.images.original.url // 6
}
callback(urls) // 7
}
}
}
  • 聲明函數(shù) getGifUrls(callback: (List) → Unit)。Android 和 iOS 代碼將會(huì)調(diào)用這個(gè)函數(shù)。返回的 Unit 類(lèi)型相當(dāng)于 Swift 里的 void。
  • 在 GlobalScope 的上下文中運(yùn)行后面的代碼,其中包括它自己的調(diào)度器和作業(yè)取消邏輯。
  • 啟動(dòng)我們自己的 dispatcher,這里不用默認(rèn)的調(diào)度器。記住,調(diào)度器的實(shí)現(xiàn)在各個(gè)平臺(tái)是不一樣的。
  • 聲明一個(gè)值,等于 callGiphyApi() 函數(shù)返回的值。
  • 映射 GifResult 對(duì)象的數(shù)據(jù)列表;
  • 映射完畢后就能獲得每個(gè) url 的屬性了。url 是一個(gè)字符串,因此它將映射到 List對(duì)象。Kotlin 中的 it 關(guān)鍵字表示 lambda 的參數(shù),這里只有一個(gè)參數(shù)。
  • 將這個(gè) URL 列表傳遞給作為函數(shù)參數(shù)提供的回調(diào)。

在 Android 平臺(tái)上實(shí)現(xiàn) KMP

Android 應(yīng)用的最后一步是使用從 Giphy API 獲取的 URL 替換原來(lái)的硬編碼 URL 列表。其實(shí)這也沒(méi)那么難啦。

首先打開(kāi)androidApp/src/main/kotlin/MainActivity文件。Android 的 Activity 與 ViewController 密切相關(guān),這里 MainActivity 中實(shí)現(xiàn)的第一個(gè)函數(shù)是 onCreate(savedInstanceState:Bundle?),這與 viewDidLoad() 有點(diǎn)相似:

復(fù)制代碼
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val gifList: RecyclerView = findViewById(R.id.gif_list)
val layoutManager = LinearLayoutManager(this)
gifList.layoutManager = layoutManager
adapter = GifAdapter(this)
gifList.adapter = adapter
adapter.setResults(urls)

刪掉這個(gè)函數(shù)的最后一行(原來(lái)這行是用 fakedata 設(shè)定輸出的),換成:

復(fù)制代碼
getGifUrls {
adapter.setResults(it)
}

setResults(results: List) 這個(gè)函數(shù)會(huì)將獲取的 gif URL 設(shè)置為新的數(shù)據(jù)源并重新加載 RecyclerView,后者實(shí)際上是 UITableView 和 UICollectionView 的 Android 版本,不過(guò)它們還是有一些關(guān)鍵區(qū)別的?,F(xiàn)在 Android 這邊的所有邏輯就完成了!

如果它沒(méi)能自動(dòng)導(dǎo)入,你還遇到了未解決的引用錯(cuò)誤,則可能需要將以下內(nèi)容添加到文件頂部的導(dǎo)入列表中:

復(fù)制代碼
import org.gifLibrary.GiphyAPI

在 Android 模擬器上運(yùn)行

點(diǎn)擊 Android Studio 頂部工具欄中的“Run”按鈕。它的圖標(biāo)與 Xcode 的“運(yùn)行”按鈕很像。之后 Android 虛擬設(shè)備(AVD)管理器將顯示一個(gè)窗口,類(lèi)似 Xcode 管理模擬器的那個(gè)窗口。不同之處在于 Xcode 里的模擬器是現(xiàn)成的,無(wú)需再下載。

在新窗口中,如果你在列表中看到有什么可用的 Android 設(shè)備就選擇它運(yùn)行應(yīng)用。否則就點(diǎn)擊“Create New Virtual Device”。在設(shè)備列表中選擇Phone類(lèi)別和Pixel 2 XL,然后點(diǎn)擊右下方的Next。

接下來(lái)選擇 Android 最新版本旁邊的Download,這樣會(huì)下載 API 級(jí)別最高的系統(tǒng)版本。然后會(huì)出現(xiàn)另一個(gè)窗口來(lái)安裝所選的 Android 版本。要是沒(méi)看到下載按鈕說(shuō)明你已經(jīng)下好了,那就選擇該版本,然后再點(diǎn)擊Next。等系統(tǒng)下載完以后點(diǎn)擊Finish就行了。

Android 這邊就搞定了!好好慶祝一下,體驗(yàn)自己的成果吧。接下來(lái)回到熟悉的領(lǐng)域。

Xcode 設(shè)置

打開(kāi) Xcode 項(xiàng)目并轉(zhuǎn)到iosApp目標(biāo)的Build Phases并點(diǎn)擊 **+**,就是下圖的紅圈部分:

從彈出的列表中選擇“New Run Script Phase”選項(xiàng)。你會(huì)在主窗口的列表末尾看到一個(gè)新的Run Script。將其向上拖動(dòng)到列表中,使其位于Compile Sources之上。單擊它旁邊的箭頭并粘貼以下腳本:

復(fù)制代碼
cd "$SRCROOT/../"
./gradlew GifLibrary:copyFramework \
-Pconfiguration.build.dir="$CONFIGURATION_BUILD_DIR" \
-Pkotlin.build.type="$KOTLIN_BUILD_TYPE" \
-Pdevice="$KOTLIN_DEVICE"

這個(gè)運(yùn)行腳本會(huì)讀取 Xcode 項(xiàng)目的Build Settings中的定義,以便在 copyFramework gradle 任務(wù)中使用,回到GifGetter/GifLibrary/build.gradle中就能看到這個(gè)任務(wù)。但 Xcode 項(xiàng)目還沒(méi)有這些設(shè)置。為了創(chuàng)建這些設(shè)置,請(qǐng)轉(zhuǎn)到目標(biāo)的Build Settings選項(xiàng)卡,然后點(diǎn)擊 **+** 按鈕,如下所示:

在彈出的小下拉菜單中選擇Add User-Defined Setting。將新設(shè)置命名為“KOTLIN_BUILD_TYPE”。單擊它旁邊的箭頭以顯示DebugRelease環(huán)境。為Debug賦值“DEBUG”,為Release賦值“RELEASE”。

添加另一個(gè)用戶(hù)定義的設(shè)置,并將其命名為“KOTLIN_DEVICE”。然后單擊Debug右側(cè)的 **+按鈕。這將在Debug下創(chuàng)建一個(gè)字段,表示Any Architecture** | Any SDK。單擊它以查看架構(gòu)選項(xiàng)列表,然后選擇Any iOS Simulator SDK。為該字段賦值false。對(duì)Debug 做相同操作,但這次添加的是Any iOS SDK并將其賦值為true。

在“KOTLIN_DEVICE”下的Release中重復(fù)這些步驟。最后,你的User-Defined Settings應(yīng)該變成這樣:

然后在右上角的搜索欄中搜索“Framework Search Paths”:

將以下內(nèi)容添加到DebugReleaseFramework Search Paths

復(fù)制代碼
"$(SRCROOT)/../GifLibrary/build"

KMP 會(huì)把 **.framework文件輸出到這里,這個(gè)文件包含 iOS 應(yīng)用所需的業(yè)務(wù)邏輯。在 Finder 中訪(fǎng)問(wèn)GifGetter/GifLibrary/build/,你會(huì)看到GifLibrary.framework** 文件已準(zhǔn)備好供 Xcode 使用了。

然后轉(zhuǎn)到iOSApp目標(biāo)的“General”選項(xiàng)卡,滾動(dòng)到底部,然后 Embedded 點(diǎn)擊Embedded Binaries下的 **+按鈕。在彈出的窗口中點(diǎn)擊底部的“Add Other”;在彈出的 Finder 窗口中選擇GifGetter/GifLibrary/build/并選中GifLibrary.framework文件,然后按點(diǎn)擊“Open”。這樣就會(huì)把框架添加到Linked Binaries and Frameworks** 了。

打開(kāi)GifRetriever.swift,你會(huì)看到一個(gè)包含 25 個(gè) URL 字符串的硬編碼數(shù)組。在它下面是 requestGifs(_closure: @escaping StringsClosure) 函數(shù),負(fù)責(zé)傳回硬編碼 URL。在文件頂部的 import Foundation 語(yǔ)句下添加 import GifLibrary。

現(xiàn)在替換 requestGifs(_closure: @escaping StringsClosure) 函數(shù)的主體,像這樣:

復(fù)制代碼
func requestGifs(_ closure: @escaping StringsClosure) {
GiphyAPI().getGifUrls { gifs -> KotlinUnit in
closure(gifs)
return KotlinUnit()
}
}

iOS 應(yīng)用也可以進(jìn)模擬器運(yùn)行了! 現(xiàn)在你已經(jīng)在兩個(gè)平臺(tái)上部署了同一個(gè)應(yīng)用,兩個(gè)版本通過(guò) KMP 共享網(wǎng)絡(luò)邏輯!

結(jié)語(yǔ)

可以在 GitHub 上訪(fǎng)問(wèn)已完成的項(xiàng)目以供參考。請(qǐng)記住,KMP 仍然是實(shí)驗(yàn)性組件,很容易發(fā)生變化,而且它在迅速發(fā)展和進(jìn)化。不僅如此,已經(jīng)有 App Store 中的現(xiàn)實(shí)應(yīng)用成功應(yīng)用 KMP 了。對(duì)于想要做跨平臺(tái)開(kāi)發(fā)的 iOS 開(kāi)發(fā)者來(lái)說(shuō) KMP 是首選。

KMP 不僅是 iOS 工程師成為跨平臺(tái)移動(dòng)開(kāi)發(fā)者的捷徑,你還可以用它創(chuàng)建業(yè)務(wù)邏輯庫(kù),然后將其部署到其它平臺(tái)。如果你希望將應(yīng)用部署到 Javascript 環(huán)境,這個(gè)業(yè)務(wù)邏輯庫(kù)就能派上用場(chǎng)了。

如果你想深入了解 KMP 或 Kotlin,請(qǐng)查看這些資源,其中包括 Kotlin reddit 版塊和 Slack 頻道的鏈接。美國(guó)東部時(shí)間 2019 年 6 月 4 日下午 1 點(diǎn)到 2 點(diǎn),Touchlab 將舉辦一次網(wǎng)絡(luò)研討會(huì),主題與本文相同。最后,下面是一些關(guān)于 KMP 的文章介紹以供查閱:

作者介紹

Ben Whitley是紐約的一名 iOS 開(kāi)發(fā)者,擁有 4 年的 Xcode、Swift 和 Objective-C 工作經(jīng)驗(yàn)。在過(guò)去的一年半中,他一直是 Touchlab 的主力 iOS 開(kāi)發(fā)人員,在此期間他與多家知名客戶(hù)密切合作過(guò)。他目前致力于將 Kotlin Multiplatform 發(fā)展為 iOS 開(kāi)發(fā)者的原生平臺(tái),并幫助 Android 開(kāi)發(fā)者將他們的 iOS 和 Xcode 相關(guān)問(wèn)題轉(zhuǎn)化到 KMP 上解決。

查看英文原文 Kotlin Multiplatform for iOS Developers 

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
使用Kotlin開(kāi)發(fā)Android應(yīng)用(I):簡(jiǎn)介
淺談Android Studio3.0更新之路(遇坑必入)
Android Studio 3.0新功能介紹
Java 程序員最?lèi)?ài) Kotlin?
分享我學(xué)習(xí) Androd 開(kāi)發(fā)過(guò)程中寫(xiě)的小項(xiàng)目
干貨貼:像大牛一樣寫(xiě)代碼:31 個(gè) Android 開(kāi)發(fā)者工具
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服