iT邦幫忙

2021 iThome 鐵人賽

DAY 21
1

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

https://github.com/officeyuli/itHome2021/raw/main/day21/kotlin%20tool2.png

在裡面可以選擇使用的Kotlin版本,這邊我們換成1.5版本的Early Access Preview 1.5.x 版本的Kotlin

https://github.com/officeyuli/itHome2021/raw/main/day21/kotlin%20version.png

然後讓他下載新版本的Kotlin就可以啦

此外官方討論區也有人提到必須要升級Gradle版本到7.2版之後,我也有遇到同樣的情況.那調整Gradle版本的位置就在工具列中,

https://github.com/officeyuli/itHome2021/raw/main/day21/tool%20bar.jpg

其中的

https://github.com/officeyuli/itHome2021/raw/main/day21/1632667723624.jpg

點開後把下面的gradle版本調整成7.2 之後同步即可.

使用multiplatformSettings

雖然標題這麼說,但是Koin是給Kotlin專用的,實際上是不能運行在swift或是Object-C版本的.好在我們前幾天已經把ViewModel的部分下放到了iosMain之中,也就是說,現在iOS專案內除了負責顯示的swiftUI,其他部分都是由KMM的Kotlin部分代勞,而這部分,就能使用Koin注入所需要的物件.

所以:雖然Koin不能運行在顯示層,但是其他部分,商業邏輯與資料層都能夠進行依賴注入.畫面層則是直接呼叫這些Koin所管理的物件,也能進行一定程度的解耦.

首先,我們會用到一個為KMM特製的第三方庫進行資料的儲存庫,會根據平台不同而使用不同的實作方式,來源是:

GitHub - russhwolf/multiplatform-settings: A Kotlin Multiplatform library for saving simple key-value data

同樣的,我們在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)
}

建立一個iOS使用的Koin物件

在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也能夠看懂的物件以供使用.

撰寫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轉換過來的.

建立AppDelegate

接下來我們要在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來儲存資料.


上一篇
Day 20:讓我來為您服務.由Koin管理的Android App
下一篇
Day 22:開心SQL,SQLDelight
系列文
挑戰 Kotlin Multiplatform Mobile 跨平台開發,透過共同的Kotlin模組同時打造iOS與Android應用!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言