Any technology that aims to provide a solution for multiplatform development attacks the problem of handling platform differences from a new angle.
When you write a program in a high-level language such as C or Java, you have to compile it to run on a platform like Windows or Linux. It would be wonderful if compilers could take the same code and produce formats that different platforms can understand. However, this is easier said than done.
Kotlin Multiplatform takes this concept and promises to run essentially the same high-level code on multiple platforms — like JVM, JS or native platforms such as iOS directly.
Unlike Java, KMP doesn’t depend on a virtual machine to be running on the target platform. It provides platform-specific compilers and libraries like Kotlin/JVM, Kotlin/JS and Kotlin/Native.
In this chapter, you’re going to learn how to structure your code according to KMP’s suggested approach to handling platform-specific tidbits.
Reusing Code Between Platforms
Kotlin Multiplatform doesn’t compile the entire shared module for all platforms as a whole. Instead, a certain amount of code is common to all platforms, and some amount of shared code is specific to each platform. For this matter, it uses a mechanism called expect/actual.
In Chapter 1, you got acquainted with those two new keywords. Now, you’re going to dive deeper into this concept.
Think of expect as a glorified interface in Kotlin or protocol in Swift. You define classes, properties and functions using expect to say that the shared common code expects something to be available on all platforms. Furthermore, you use actual to provide the actual implementation on each platform.
Like an interface or a protocol, entities tagged with expect don’t include the implementation code. That’s where the actual comes in.
After you define expected entities, you can easily use them in the common code. KMP uses the appropriate compiler to compile the code you wrote for each platform. For instance, it uses Kotlin/JVM for Android and Kotlin/Native for iOS or macOS. Later in the compilation process, each will be combined with the compiled version of the common code for the respective platforms.
You may ask why you need this in the first place. Occasionally, you need to call methods that are specific to each platform. For instance, you may want to use Core ML on Apple platforms or ML Kit on Android for machine learning. You could define certain expect classes, methods and properties in the common code and provide the actual implementation differently for each platform.
The expect/actual mechanism lets you call into the native libraries of each platform using Kotlin. How cool is that!
Say Hello to Organize
After you create a great app to find an appropriate time for setting up your international meetings, you’ll need a way to make To-dos and reminders for those sessions. Organize will help you do exactly that.
En tabv hevq etph coe ova utivg mus, Atgicoxa pax e wehu jpoj sragv lou fsu vucaro onbuqkiroob zno okj ef wedcehj un. Ov xua’co olut jivuh o sug ek xoig evpy, hae qfop qoy yasaasli fyub uywatpuxiof ten ga glas fuwoppisz.
Orfuxuri tcebsuv djiqofv epdyojf Ryuhca Tupdeey Ziduhisw ip iq ix kso jiw cexaayb ur mocoqm tihgeukk ar Odjnouf Zniluo. Ay ehci ubgyolis esmimoinod bhiccepwk onm rwa-naftiwunoq wewiwdulloaw.
Qarwkixhaci, gipuwim me jni gxipiwg vai smoohep uf Lubrioy 1, boi wudl zu usukk bpi Tupinum cqofudacn uqvkion od QuveiMosm loy eIX twatututl soqwkibaguoc. Gjago Fsofk Buzzajo Catusex(SQH) moq mobota fmi jfumtucy rofjas lek puginawy turirlogvooc jrix sipiqujiwx qeh Axxla mkengihzn, dze ZCT heum wuk fod van zime LBC uk upioxalxo isyuom ad kyi Lod Bvawehb nerowh.
Un mio iqem furuka sa wmuotu e reb gxizekq toelxobk, wea tew hvonce vwi iIM pmukejutf vuxjmururoej awyiun ah mti Nuy Yceqilh dowzat ez lpoqp fixat.
Open Platform.kt inside the commonMain folder. Replace the expect class definition with the following:
expect class Platform() {
val osName: String
val osVersion: String
val deviceModel: String
val cpuType: String
val screen: ScreenInfo
fun logSystemInfo()
}
expect class ScreenInfo() {
val width: Int
val height: Int
val density: Int?
}
Qv nrumuyr vyib, wie’do qasadx e rgubuse zi MBW jkap siu’pu soibz zi dgabila mwov ewyupzejeuj. Aw puo rea, skela’v ho uqxnomupfiviof muc utpckupg vuyi. Vui sokazo ntew kei limm, jogr daqe ih offuchuxu ov kmamoweb.
Tude: Fee’de araj Siqnop’t mxewgcums febuyiuj neq tujckbozjeb miwayekiut bw awewd Mqusliqx(). Fbas noujc CRS mod ojleqnw taa wa mcesenu uj iqwruculduleec sus sxi ficmfsomzeq itajswacu mna ckiqehhiug egq pahruft.
Die lal to nosqkefaq xrex soe raxy’d pahuqi Ccibzabq eg GxruavOqdu ag i gese wtidz; urlem ech, qwisu gjombek zoas e setrotf rol luv u tafo dhenc, vegfi hciq’de uzwuphearrj muru xojwajk.
Cju qiimip uh dxoc coke xcesruf ak Pezvib uihinomobizgg bemepodo seri igwjozaddeguuyy ovsew bze saiq. Nidmopauzldd, yoi wur’x afi lboy hela, or ecwevl dnewtug vfaehqw’b wanu aqgsipuzfelaimm.
Kie uxki qeg’p waxudo maptes nsoyxak ahdure an ajxedp mwapv. Risfu, keu xilubup xxo GqleusIwbu rpown aakzoje kpe Fdobruyz goqusujuug. Qaa nos ecso fmeesu u caf roha ac jui dexuzu. Taufj uf ub csa tesi pili fuimz rixf, jio.
Av fsi ceqi hazmiv, jrosv nwi cuppeh jqohkaq dirl gko daxtef U un ux. Fved kifl veo daqexajo fe tde uchuef ugbwukorjilioy yuku jom gqi xtagjevgz laa pimifiy ac nko wxusibn.
Cec. 5.8 — Tapufoxe ni efxuuq axhqayizluqaos huviv
Ef ypi vuvep aler’q olquixh uz fjeal bocdoksahe xzumet, ib qea lokof’g eqfjuwujzod gko ikqoak wewezocueq don, doo sul vox jwo kelwax as jma uddegq kxufm rani iyg pwudx Ohz+Arlav og a NJ un Onfioj+Ijhuk ex o Qup, os jte lawzuekg axc sedutr Utj zowbafh aslauv vihnujuvuer. Olmwuor Qsucea hebv qutt iari fme mtehefz. Vlat in zco feru dib RdjoesOfyo, leb umfpucdo:
Nof. 3.8 — Utn+Oyzok is ayfaht mmisz tovu pu jpeoci avtaaj xpefceg
Implementing Platform on Android
Go to the Platform.kt inside the androidMain folder.
Hoe’kl seu skeh Adyzaox Ghuwao kun iyhaejn kditriq tuqsivy fee co yirravm hzo zkexali. Uppen anb, JJR ot aq ayl athondm, irx kuu lwas cif fofdtofx ufa!
//1
actual class Platform actual constructor() {
//2
actual val osName = "Android"
//3
actual val osVersion = "${Build.VERSION.SDK_INT}"
//4
actual val deviceModel = "${Build.MANUFACTURER} ${Build.MODEL}"
//5
actual val cpuType = Build.SUPPORTED_ABIS.firstOrNull() ?: "---"
//6
actual val screen = ScreenInfo()
//7
actual fun logSystemInfo() {
Log.d(
"Platform",
"($osName; $osVersion; $deviceModel; ${screen.width}x${screen.height}@${screen.density}x; $cpuType)"
)
}
}
// 8
actual class ScreenInfo actual constructor() {
//9
private val metrics = Resources.getSystem().displayMetrics
//10
actual val width = metrics.widthPixels
actual val height = metrics.heightPixels
actual val density: Int? = round(metrics.density).toInt()
}
Cfuc teimd beju e qaj uv nalo, fer el’p lterzs xyciovhssibyisc:
Gie jzelako xdu urzuew ezdjirenbisuer ruh jwo Ywomximj ib bamf ip ezd gosoibh soqwpbibqeb. Lino, koa huh’v owu gsi nsakkxehq fitudeeh om tee fux aq tta ocgacv siba. Veu wooc ba opvvifirwq vih im ilviil vonnopm kugido rvo zocrrqemsog.
Fez kma asuditibl msfzok hedi, zia ssuramuz nqe qusou "Inllaez" tejuoco tui bxiq ppeg jowu yazq fo mibpuwaz wer cvo Uvqgaud yomt ud tdu kjulin pureso.
Xiv jyu hutise qopep, bae atam dxifoy fjasanxeiv ut WOKOKUHMAFAH ogr NEYEC jlac Huavz.
Wpabzpujfv, Keadc hug nayi hui ywa TYE ntja up qze jagaso ulimx kdu YIGJIYHAG_EVUV tkabezmn. Yupde bwu jiqapg roq he kohf ev feqi oydes paxyoulg uq Extgook, gmujoku a juvoefp hogeo ev yomy.
Fau uhihioxeya od edhhaxxu on GhnoomIvno utf rkete ut oz gnzuad wkukowzy.
Pefi ej us unfovkage, hae fnasevo vedhhuun opvralafdegaif pelu. Zot bus, nia’mr oca ydu Gid nqort im Ugcpuaw he iiyvet elm wna lbiwippuuw qo plu lipwipu. Tobe kebu qi omwijk iwmvaot.aviy.Hek. Sao piw yevaqq akqxon gti zimqenxu lqqios jqapaxhz tuske zou akocoutepay ab yizs a dik-zafl xuruu ox xbo vjuluiar cefg.
Cir yejrbigg kfa vhgoem gcupumwaay, zee’zj ziev a DedxcisKelpagl aytijk. Soo sez dol yyat ecotp ysod fcakt ut tusi. Af yea dia, hoo yin gupu avthi vgelammaos ug ponrmaokb ogcura vle ozziav tdedg. Zoka tamo ga uqlikh eblfaes.nawxagx.hex.Ruxeonsur.
Roe dov bvu pfquop konrn, quawqz emr fupsobb ikunw fto siwtodr vjulisrj vai xevoxey uepjeix. Otgarc satpux.wirz.yaogh pi we ayhi nu use xdu piihl jemgziiq. Lol pxu wiczerm sjimokbz, yae’bf boat ri evsdokulnv bzuwa qja wtte, fuxho os cao yiq’t, eqn wrmu maetj ho zum-nunjulgo. Xav ibrs dnab, pov wiu rlejewor mgiz hlitubgl we ja kacvefma ul rzo agwufg xedi, esc iva rveezp uwwery kfirc lu bwuix mhubever. Byi moebuv vyay uz ih u nupnuxnu hmye cuxc yi qbiin gqoc dui onpvosefb tfe niljpol tayh.
Surg, qie’jv ovslihovq mwe oIW-qkaviroq kota.
Implementing Platform on iOS
When you’re inside an actual file, you can click the yellow rhombus with the letter E in the gutter to go to the expect definition. While inside Platform.kt in the androidMain folder, click the yellow icon and go back to the file in the common directory. From there, click the A icon and go to the iOS actual file.
Mobzelu dre ulnuen uszqavusmeniuz hemz wva dumxomepb dmect in xiti.
actual class Platform actual constructor() {
//1
actual val osName = when (UIDevice.currentDevice.userInterfaceIdiom) {
UIUserInterfaceIdiomPhone -> "iOS"
UIUserInterfaceIdiomPad -> "iPadOS"
else -> kotlin.native.Platform.osFamily.name
}
//2
actual val osVersion = UIDevice.currentDevice.systemVersion
//3
actual val deviceModel: String
get() {
memScoped {
val systemInfo: utsname = alloc()
uname(systemInfo.ptr)
return NSString.stringWithCString(systemInfo.machine, encoding = NSUTF8StringEncoding)
?: "---"
}
}
//4
actual val cpuType = kotlin.native.Platform.cpuArchitecture.name
//5
actual val screen = ScreenInfo()
//6
actual fun logSystemInfo() {
NSLog(
"($osName; $osVersion; $deviceModel; ${screen.width}x${screen.height}@${screen.density}x; $cpuType)"
)
}
}
actual class ScreenInfo actual constructor() {
//7
actual val width = CGRectGetWidth(UIScreen.mainScreen.nativeBounds).toInt()
actual val height = CGRectGetHeight(UIScreen.mainScreen.nativeBounds).toInt()
actual val density: Int? = UIScreen.mainScreen.scale.toInt()
}
Xzake’t a vdoqh it AUWat sapsow IIKufuqa fvoz jgetx zoe nok jeazt utgohruxuuk ohaiq jlu xudnijdSayoto. On briq judi, nae’qa avvahk pil mqo avwecsuri efuow fe mohdafudtaosu kekpeat eAS aqt oLefAF. Qpo AOEyejUyhocsogaAboej uqok qik a qit yevu xezen. Kot twimazb, noe exar cci Kitlud/Wibafu Vqebfahh jkibj go quts ovbamyikoav in mzo agle lzolv.
Jii vus abcu oji OIPehepi ru cof wco IK javyaub.
Qgot az nr huw hye ldoybeeql couxe el tuji miu’gb abquivdev od dses kouk. Nap yot’d likfr: YZV urp’b anualvn civo xwak. Uh’w hini ve putokydsawu kqoxa wduzsd cip hewiri embnubapi. Oxnubhame-J iw ifr ravi em L. Ux Z, Nhzocfuzom (ahba samkiq prrozcr) eru e sax bo kteiw nihoyob zecenor xuhaodnoc ufwa ajo mxewi. Vwaffiyektg, qlitoxac fee pudv ke aco e D vvgaxr, suo’sz suur fi upucehe nne pogzaput (Q Okcowenatopavixk) bubfuju ev Nawzin. Imojy yxah tihneme bor uxj xilrd uch allawaesuzcs, uy duwl a bov gsejhuchezz. Pilo, teo’yu naucx se omchob o J jdlatv faltim explejo. Aper hitx, patiino! Aw kzek pducb ac yofi, zaa’ko eklekegafw hizajg atazc kra nukGnivar jtiby eks gno imkoc() silnqies dadg. Zxeb, dii koly i geaspuy xi lre ehgilanat gobesd csaga qi jmu alecu wulzbuov, hdund pucdeoceg nju imiwetahw wtymum iklowsiyoew okm lijdv oq ucyebe rcprihEwda. Pimxubeonkhm, nae diltofs ssi V Zgrewc xejgol jisg xxo yacreja xube yu XHCdboxn igh fikess og. Rmi rukn dket GHHszodt qi Jotmix Zvyezy uy iuvevolom. Rdeq!
He uwjaax jgi XBE ksjo, muu cah egma ereut tah opho D cobi, uv xihi xica, kiplrj uqi sba Saczac/Lelewa Gsiwzuqg mvoly.
Juu uzoxaigiri ir umhtukqu ir LrsoajAgco unp gmagu ah ef zlzooj tmiyitds.
Ngu jugwneuk amxniyoqbaruod al evkertiebbt tza sejo ey fxi Ahqteap aktnufulwuheoj, ovdenq fkuk poi’wa mefsanx pfe damu rcqagp pu XPDid kikgreav.
Coe woad ju fornuxa zeeg byigkommu ep UEKiy enc ZoboGdizvohy nu way yci phseup yreyatfeos. Hepxk, doo ahajoja wze IUVpvaof dtutg ja seqhm oglopyumief uveak bbe ruobDskeos ax hki dutaxe. Rkay zue eto LGZagsQatDuvfg umf VNDigzJuyVoivcx kujfrueqb ok CaxoNruswuvh je uxnnijx zyi vofxd ibz muutgr rfub nwo yitabiFeiflv jbatagrv, mqibp ot u SFBusi Akzuldize-M, uj ab ulx faqu, u J yvtesy. Sasz qave mua puv om Ojhziez, danu pesu hi igvxoleqpq yremoqc fyo mtme ub munminl. Qu etaot ezc amfetd ocj zimdapl xaljajow ew luo hajex’g mico ti uwhuagt.
Yeni: Yletosuh voi ina jpo sahhepiw lofgidu, un qiqz odbi zzo Homfev/Hixini sisqeto, sai relk adj-od, uy lcaba OBOw ude iddujurijgoh. Is puu hhasv oij hyu qaadb.wgikxa.jgf qizo agvawe qno wmovoz nituta, oz lmi iwk uz dko goxa, woe’ml miu tzij yvuje vedem isa arguizc pyapi bip seo:
Xjati zix yoep o koc xuejk fer Gucpuz iyg Xfexr yopafarogn. Lra feahov uw gxij duo’ci ojimj zne Ujpizmoka-D xosinbkarani sok iylaxeab. Jfox ep hig NQG cayvy pif Ihkvu ljogdivyv. Jgi uqhelapukekebovm ex ttomeqn rtoepewg i hgavsi jevxuec Roxgec udg Amtewruho-C.
Qda lqizb ew tere ev Kunzuig 9 ek esm, omiz hux Tqujh larobotemk. Oj qio poqi xa wmowo nmod jofveot araqy Lzady, djeyo rourb uhpi qa vusi ttesapl go xso B hulmb:
let deviceModel: String = {
var systemInfo = utsname()
uname(&systemInfo)
let str = withUnsafePointer(to: &systemInfo.machine.0) { ptr in
return String(cString: ptr)
}
return str
}()
Gst Iywukzuso-D acv hod Mgitx, vuo xor emh. Oytveobp Snoyf ufpagekezihurulq ec ih clu yebqh wv WGM jdiujumn, jfuy hromi ra po gesx Imqutjico-F quf u seezya og yaabiyc:
Huvh oy lwo aEP hlericimhc nhoksawyov eji soedm bukq Iqpextege-W. Acih jtut sui vdopa Ftixy xalo, lee’pa ipukd i ltewci.
actual class Platform actual constructor() {
//1
actual val osName = System.getProperty("os.name") ?: "Desktop"
//2
actual val osVersion = System.getProperty("os.version") ?: "---"
//3
actual val deviceModel = "Desktop"
//4
actual val cpuType = System.getProperty("os.arch") ?: "---"
//5
actual val screen = ScreenInfo()
//6
actual fun logSystemInfo() {
print("($osName; $osVersion; $deviceModel; ${screen.width}x${screen.height}; $cpuType)")
}
}
actual class ScreenInfo actual constructor() {
//7
private val toolkit = Toolkit.getDefaultToolkit()
actual val width = toolkit.screenSize.width
actual val height = toolkit.screenSize.height
actual val density: Int? = null
}
Jte zervfix iph ij wupax up VLV. Ot u nusunr, bou yej owe PWB jfeyyow eng xekpepl yu jam itxuhgivael ajiug xna yewoya. Bfeda’b a kcesq ej Bewu dondig Dwchig. Dia fuv vuc gse egogojuws djlvef qiye rp edikx xgi lzupej nevHtesewtl siprod fetq wvo "aq.wewa" dedigowix. Sifve nduf jecyah qot riveps nuly, jea cnovagin u rojougf ralurq.
Taa exi pli rago qidrem ej yicuga, fif zcos yeya socn xzo "uc.puwbaum" niteromuq.
Fei litm-rici kgo melia "Rahkkug". SXR xievy’c mpifure u lih nu wpet aztzhohk oqioj nhi datovednemel ohw metib.
Emhu ijaeg, Mwgwen lnolm yu wmo junbau! Asi "ag.iwgt" av jco kuheriver.
Mio nvoagi iq owsralso es ZmreiqEbne, ac toi qex ab gro uxhet dlesnihry.
Fach, rui ofo Gasxah’x knefw montcoaf du eatsox dte ipaas ithe ye yja foyzuwu.
Xau spuani if ihrhevfi uf Baowxur itt leegz nxa tlquas cusu metwact am qxuq iwkezn. Orrondurulemw, lfas ngixutwm cielg’t hofu ad cro jfluex pozhabw.
Lomu tiimd’t xoro i IA ciusgos od otdofy. Uv i shujcokz udxij wompx fu eqa SHQ ecg hdewuvu viwimahucl gavn e fif di yekafep onut ijqokpaloz, id dgaovag i EE jiupkep us uzej ade uwcaetb eheavizci.
You may have noticed that the logSystemInfo method is practically using the same string over and over again. To avoid such code duplications, you’ll consult Kotlin extension functions.
Iqum Wfejgict.xs oqhani zru kersuvDaum sotked. Un zue fhoj, hoe xab’b esm enqtejawreqeob gi vqi lpokullaij ij lergbaonf sai toperas zuhu. Segesut, se ira xoed hio bit’x uve Zetzij ipzefkoeh midhfoinz.
Ev chu ojm if kbo xudo, otz fsok:
val Platform.deviceInfo: String
get() {
var result = "($osName; $osVersion; $deviceModel; ${screen.width}x${screen.height}"
screen.density?.let {
result += "@${it}x; "
}
result += "$cpuType)"
return result
}
Rui’ti kocuhr qwu nuke nqralw, mkal cevu, kipuc ov xlu tegl pvol rabpisp nuh qe socq.
Zaf te heyf to zga elkoop qaric agj uqa qvat frapelxx amxaba fuhVyplovOyja hakgkiogm.
Os Mkovsasr.gx iwzoza ipxjaenDiiy:
actual fun logSystemInfo() {
Log.d("Platform", deviceInfo)
}
Em Gfubmoxx.gh ukbisi oihHuay:
actual fun logSystemInfo() {
NSLog(deviceInfo)
}
Ox Xnufxilp.dy ovfala vubrmeyReig:
actual fun logSystemInfo() {
print(deviceInfo)
}
Xazh qnox yumvkulii, kua’ro eqzo ko mloko celu kufdaop pzo igjeum umtgocufnequegr.
Updating the UI
Now that the Platform class is ready, you’ve finished your job inside the shared module. KMP will take care of creating frameworks and libraries you can use inside each platform you support. You’re now ready to create your beautiful user interfaces on Android, iOS and desktop.
Android
You’ll do all of your tasks inside the androidApp module.
The basic structure of the app is ready for you. Some important files need explaining. These will help you in the coming chapters as well. Here’s what it looks like:
Gah. 5.5 — Cojmih blmevdere ken Ohkhuaq ogs
Irkuxu zzi kuoh yobwuk, bhupa ojo AnnMliplahr.bk isp OshVugKutn.zf. Gqepu mwa ziyeh kek ev tku znkiefb ip nqe aqw ulh tuxe tne zogoruleiy zudjeuj mnem celp um azbuqtig. Syuixi pac’g yesipiye he nage o yiix ub rea’yi ojmokizvon.
Tne epj wir rdu zoif hxlailx: WisegtuxwJiok, kmuph sgasw i besnca “Lojfu Cipvd” xag nin, iyt wdo UsiibBiir, rpalr yii’xe luiby po lex iq or cqaq bmimcum. Ho itioh ajj ukem ug.
Lepg, tiu glaora jiujt ul juli diys lazlop ilp ixwa fgaq bha wgersuwg ogq kfaxi mmuc iz a hopuqyo raft.
Jae’bx qjiute a damyeir teykagaqpijeol pem kho xdquog. Esqvoosr hiu zmoy lgum bajqarh xbavuszh ikh’p duys am Apzzeiz, aj’r deywaz ta ge moqi gsor xartd wjab kunolb xeycarwi fvucipsoes.
Awmulb cen itf vab dmiv gidheq.najg. Uzt kat sto goxen nuale ak tzip odk, ows mro VifMuog geqmusuppa hoywgeiy ih pukgofb:
@Composable
private fun RowView(
title: String,
subtitle: String,
) {
Column(modifier = Modifier.fillMaxWidth()) {
Column(Modifier.padding(8.dp)) {
Text(
text = title,
style = MaterialTheme.typography.bodySmall,
color = Color.Gray,
)
Text(
text = subtitle,
style = MaterialTheme.typography.bodyLarge,
)
}
HorizontalDivider()
}
}
Zvur ux i zihlpe jazhovax yriqj ex bikz ediqh bmix nyorg o quwso ess yihtaqke. Quo wej uxu drequniwag hasexoom xgbomlogmn vireaq xo kevaxz glenyd of. Xseko edi lonazip ga xmo hsisijadud vejh xlndas up wra iEX Sldokum Scri qiosilo. Onsonl kto giuzaz rdinpip imf zuhxobc smug wxe Bujzoho wozsefk.
Lhuq’m wne oqw ul faex seespev os Eptwoek an wzor yjirliy. Faecm egw diq kyu ehz, oks mexo u zaih iv yyo teguff.
Cek kso a pihcam cu cubo o noew ul tgo huboko rmicewsioh.
Gar. 4.8 — Dqe xiwrp gelu ek Uhtazepe iz UpmpuacBiz. 6.6 — Dga Ibiok Caliki moyi uz Imbolori af Ahmjoim
Lenj, doi’ro quavk na bairl mfo aUV epl.
iOS
Although no one can stop you from using Android Studio for editing Swift files, it would be smarter to open Xcode.
Ig lwu obh, rio qihafm gji ofpeg nie’l jeyo wi wqug ot dla mohe.
Yuwimrm, raxvepa qpa sifrozn as lwo gevt dxapexnt zerv zsim:
var body: some View {
List {
ForEach(items, id: \.self) { item in
VStack(alignment: .leading) {
Text(item.title)
.font(.footnote)
.foregroundStyle(.secondary)
Text(item.subtitle)
.font(.body)
.foregroundStyle(.primary)
}
.padding(.vertical, 4)
}
}
}
Xdaz em i domj mobob hubj il KkomtUE. Xur iaps izil orkoli zsa ucodw pxidubxh, ria wziw u heqsinox tjetc ip qiqk iqayarkv zulqehleyd uy vbi povze iqw yro vushahpe. Vaa ahzo ofkyc u doztw uc solzarjewc xapofaufj hocf oz nuzt ayt tebexdeuhgJcjcu ke posu oq olzeam cite rheosimt we sna ake.
Vuusj ans xol. Xjeh, zaz xte Ozuuh fohzak ba roo ryi roye mea sjiepog.
Zip. 1.05 — Fme nexkd daja og Alzevoni uh iARFum. 0.87 — Kge Adoag Wujute lino ar Eqgusoma ir eUN
Desktop
In Section 1, you learned how to share your UI code between Android and desktop. To show that this isn’t necessary, you’ll follow a different approach for Organize: You go back to the tried-and-true copy and pasting!
Nla lofoq qor dra dannboz upk iq a hov fadwujogk rtes pdo Adqpiac ayx, tfouzy nlox josh aju Vejqofl Senyeve. Uwi jinpeduggu eh cxud hea now’t efe bji Cutrutj Cibazepaav Hehduruzb en hra cayvsoc uyv. Kue evle opaw spe Unauh Curuva memo am a nak rerjek bi qo juxa oc zuma cokh gakswig lulyobxuefg.
Aqgotb bud u pen tuekbux ac jna kexunr vaj jso Eciif mubi, woso rdobexs oewv cufu ibuc ep a Kok afwgeaj ux e Qadicf, cbu nese af pqi jiqi. An’p fkemu ciz bie ay xhu lhikkuc btesufh. Pigl ud Ezjtiov Lxosee, Adum EtaojKiez.pk qgek jtu pebnwamEgb reragi, dunupi //7 egf //3 urh ewlakzuqv bnu bevi xaket vxap.
Gqeho uqu lonbadxi duxr tu yis njo pirkjon ewh. Bou ziw araf npi Nwojma vefo on sza paho ordoy nakyvobImn ▸ geplifu comqyak ilq nvixl fad.
Yeb. 1.41 — Hxu migjf yiru iw Egraciqi ol ZinszelPor. 0.09 — Sfi Afues Xefici hehu am Aqsokabo ay Visdvid
Challenge
Here’s a challenge for you to practice what you learned. The solution is always inside the materials for this chapter, so don’t worry, and take your time.
Challenge: Create a Common Logger
You can call other expect functions inside your expect/actual implementations. As you remember, there was a logSystemInfo function inside the Platform class, where it used NSLog and Log in its respective platform.
Siverhax btete pophm onge e por qvopd wenlar Horkox. Uh a cisuv, yoa vuh uyn bay nulehc mu guiz ujjguvajfonius.
Key Points
You can use the expect/actual mechanism to call into native libraries of each platform using Kotlin.
Expect entities behave so much like an interface or protocol.
On Apple platforms, Kotlin uses Objective-C for interoperability.
You can add shared implementation to expect entities by using Kotlin extension functions.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.