Keyword: Koin,AppDelegate
今天完成的內容,在iOS上使用Koin 放在這邊
KMMDay21
有個好消息,原來KMM編譯過程中有用到一個物件,在新版本的Xcode後也換成另外版本了,因此KMM的編譯過程中找不到.不過在Kotlin的新版本中已經改用另外一版本了,只是目前這個版本的Kotlin還沒到Stable版本,所以需要使用early-access版本的.(官方表示在1.5.31版本修正了這個問題)
如何更換Kotlin成為early-access版本呢?就在上方的Tools ⇒ Kotlin ⇒Configure Kotlin Plugin Updates
在裡面可以選擇使用的Kotlin版本,這邊我們換成1.5版本的Early Access Preview 1.5.x 版本的Kotlin
然後讓他下載新版本的Kotlin就可以啦
此外官方討論區也有人提到必須要升級Gradle版本到7.2版之後,我也有遇到同樣的情況.那調整Gradle版本的位置就在工具列中,
其中的
點開後把下面的gradle版本調整成7.2 之後同步即可.
雖然標題這麼說,但是Koin是給Kotlin專用的,實際上是不能運行在swift或是Object-C版本的.好在我們前幾天已經把ViewModel的部分下放到了iosMain之中,也就是說,現在iOS專案內除了負責顯示的swiftUI,其他部分都是由KMM的Kotlin部分代勞,而這部分,就能使用Koin注入所需要的物件.
所以:雖然Koin不能運行在顯示層,但是其他部分,商業邏輯與資料層都能夠進行依賴注入.畫面層則是直接呼叫這些Koin所管理的物件,也能進行一定程度的解耦.
首先,我們會用到一個為KMM特製的第三方庫進行資料的儲存庫,會根據平台不同而使用不同的實作方式,來源是:
同樣的,我們在BuildSrc的依賴管理區域,加入這個第三方庫.來管理他的版本
object Version{
...
val multiplatformSettings = "0.7.7"
}
object Develop{
val multiplatformSettings = "com.russhwolf:multiplatform-settings:${Versions.multiplatformSettings}"
val multiplatformSettingsTest = "com.russhwolf:multiplatform-settings-test:${Versions.multiplatformSettings}"
}
然後在gradle(shared)中加入使用,記得同步Gradle讓其加入專案之中.
sourceSets["commonMain"].dependencies {
implementation(Develop.multiplatformSettings)
}
sourceSets["commonTest"].dependencies {
implementation(Develop.multiplatformSettingsTest)
}
在shared內的iosMain建立起一個檔案KoinForIOS.kt,這個檔案會給iOS的App呼叫,裡面寫一個Koin啟動時所必要的Function,前幾天Android的版本可以直接呼叫我們放在commonMain內的Koin.kt,但是iOS需要過經過一層處理
//這邊是Kotlin
fun initKoinIos(
userDefaults: NSUserDefaults,//iOS獨有的使用者資訊檔案,
doOnStartup: () ->Unit): KoinApplication //初始化結束時會呼叫
= initKoin(//藉由這行,呼叫Koin.kt內的Koin初始化流程
module{//同樣建立iOS使用的Module
single<Settings>{AppleSettings(userDefaults)}
single { doOnStartup }
}
)
這樣,只要iOS呼叫了這個Function,就能初始化Koin.那這個物件會由KMM包裝成iOS也能夠看懂的物件以供使用.
(之後都是在Xcode內撰寫swift)
那我們接下來寫呼叫initKoinIos的swift方法.
建立一個swift檔案在iOS專案中,我的叫做iOSKoinFunctions,在裡面寫下Koin初始化的流程
//這是swift
import Foundation
import shared
func startKoin(){
let _userDefaults = UserDefaults(suiteName: "KMMItExample")!
let _doONStartup = {NSLog("Hello from iOS/Swift")}
let koinApplication = KoinForIOSKt.doInitKoinIos(userDefaults: _userDefaults,doOnStartup: _doONStartup)
_koin = koinApplication.koin
}
private var _koin: Koin_coreKoin? = nil
var koin: Koin_coreKoin {
return _koin!
}
這邊我們UserDefaults放入了專案的名稱,這邊可以存放各種資料,如果有其他想放的使用者資訊也能放在這邊.
然後讓傳入一個doOnStartUp讓iOS在完成時執行作為Log用途,這邊就簡單呼叫NSLog印出來吧.
最後就是重點,koinApplication 就是初始化的流程.可以注意到KMM把剛剛的KoinForIOS.kt變成了KoinForIOSKT物件(這個其實是Kotlin裡面在檔案裡撰寫方法時的特性),然後initKoinIos變成了doInitKoinIos,經過這層轉換,就能夠在swift之中使用Kotlin的方法.當然swift還是認swift語法,只是這個swift語法是從Kotlin轉換過來的.
接下來我們要在iOS App啟動的時候一並啟動Koin,而KMM預設範例中的swiftUI目前沒有辦法做到開始時順帶啟動Koin,所以我們要寫一個AppDelegate,告訴iOS系統,在App啟動時要幫我做這些事.
首先,跟之前建立新的swift檔案一樣,我們建立一個名為AppDelegate的swift檔案,然後照iOS的開發流程,讓這個檔案繼承UIResponder, UIApplicationDelegate,就會變成iOS的入口.
//這邊是swift
import Foundation
import UIKit
import SwiftUI
@UIApplicationMain //這個註解代表這是App入口
class AppDelegate: UIResponder, UIApplicationDelegate{
}
建立了之後就能夠把原本的iosAPP這個檔案砍掉了,我們有了新的入口.
然後我們這邊有一個application初始化的流程,我們在其中加入初始化Koin的流程
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate{
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
startKoin()//剛剛寫的startKoin()方法
return true
}
}
最後指定一開始時要顯示的畫面,完整如下
import Foundation
import UIKit
import SwiftUI
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate{
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
startKoin()
let viewController = UIHostingController(rootView: ContentView())
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
return true
}
}
按下執行,發現....什麼都沒變,跟原本一樣.但是其實商業邏輯與資料層已經成為了Koin管理的物件
明天,會進入使用SqlDelight DB來儲存資料.