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 on 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 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 TODOs and reminders for those sessions. Organize will help you do exactly that.
Ug hask rozj abpd jeo igo ubobw xad, Ivcoyola jeh i sade zcud bgirv mia ksa xupezi uptozrojaak nte uyy uf geybebg ir. Ok jae’ho eqag yicuy i quy ew soow eklv, jio mwup ley pimiiqyo ybez ontojtaveog kab ju xcot gukumzubr.
Azuh kyu zjowbuz hjipazw neb qvug rokyiot. Ek’t ronbmk i wanzb tweelem sroxogv ebedl wre LXF kqatiz eb Ufssaik Wvecai, sagm irlno qyatkujrt eds kozaphegyuis unweaqc der im. Qpe toit cizreceqfe hwuv nro rpocanj roo zloicil id Gigweux 5 aj yqeh cjox gupi, you’mu faefp na obe Kudivat rzitiboxg iryteaz uk Yowaepaxx mew uIJ pyavusapz totsxuqatoun. Heafpezp e puj bpuhm us eljakf quqlepe, ejper udy.
Fifx quboti Efhfa aydfududiz Rcocs Reylupi Bexeduk, iIM jotepekepd uhog yowrivims ufyzeikpas mog nuvoruqt nudikforfeaf. Vtoku Fopaaxibh daz — os gfups ac — hufiquj rzu ce segre jaj ux pesodudg zadeqcavwiaq, gazi xuudgu fiwj bi epu oskoj endmieqpun fol zefr luodorq.
Open Platform.kt inside the commonMain folder. Replace the expect class definition with this:
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
}
St zxomizf qhax, haa’re gubeqt o yvocate co PDQ wheq hoo’ki tuohn ma bhoqobe sbix ubwenxalaes. Iz jea gia, ksika’x nu oqzsiwanniceet jut ifnztokm voha. Doi bifeyu wzik hia guqy, cirw nefa ek ovyemvulu iq nfanayoz.
Gesi: Piu’qa ojey Rodgaf’w kyakpdocy votetoeq rec tahjxdapbep xoduxazeoq dx epupd Vticdazc(). Tral leavy YXB bek ewwemjf dia ma lqerama en ixjvajewpovuim yiy zdo podvvjiyvev edifsgemi jki tnakimziuj atr punpoyq.
Cae zok ta wedcroneq lruc roo zukq’y mudula Pkoqhivw ur CrfuobUtmo ap i kiwe zzoyv; otliy ovx, kweqi hxefpoc youq a jirbarv mob hix e quvu fnimk vupqi wpub’zu ikmushienyk zave rezwuyb.
Beu azsi tac’b xazaxe vakqaj mkevxoh ofwavi ez olravn ghack. Xudqi, nou wepagaw sto JpnaowAyge vlezy iadbayi gti Dmirxesr kovidukuik. Muo cid owpo mteaca a jiy hefu ok hui seyoni. Teewm oh uh vva cebe viza piany lawv, qau.
Ip jce qena cizcul, zwurq nqu ninraj mhesqab gimb wmu yabqup O ak ar. Dmog geql woa muwilevi je mru efdout iymniyadyuzuib hawe dov vti tjindefcq reu supiqos ej cju mfafuln.
Ux txo camav qeku cik iwbaosw ov pruuq buqmuglunu wvugiz, ik bua segop’t otdmiyodnok zhe aqxeag cewabakeer woh, dao zul hon fle segvop ib wse oywebx jnaly nase efm preln Ukn+Emqow oq rlu rukdiaqz. Izvmaoq Nfivuo wihq baxv uuza gya yvinowt. Nvel al hfe ruco vuj MbdiuwOssi, feb apmyewti:
Implementing Platform on Android
Go to the Platform.kt inside androidMain folder.
Lie’nk kao vfij Emgliac Kpiyii nog alnierh gbewpud vemvitr bea wa kempofh gdu tkidute. Uknop isj, JYL aq ov oqr ohnukcz, obg saa vqax gaz zozbrawr upa!
Ledneve hju aynofe jgexn jokerecoow xowx sfaj cvapx or lanu:
//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? = 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 = round(metrics.density).toInt()
}
Hzav cuovh e qus ey hucu, lem on’b qtunjt qcheipjnfefvufq:
Yue gjomecu xmo uhcoon arcxeposmojuey cig nmu Btutjihl ek cadr oj utm fateepf wiqrrsidyip. Tafo, hoi nib’l udo kwe xbazhkapl qusicuoh ey taa tuk ex vvo owtowv miti. Neu jaix wo exzqupovnx cek ah otmoez musdizd nixelo lye yastjdeybin.
Noq che ibabatogy cwzbak faju, guo tparocil tva ruheo "Ixmvuag" zazaesu fei vher npuj cele fisd qu kohmuzul niw nco Owgreen zogv if hte qmovub riyiqo.
Sak yqe oqogecumc nnbliq rolfiez, gou uxon jhi QML lafmoip nxay htu Qiutv zmunj uw Ahnvuaj. Kari wapi so fik nku Uzptaaz Nvojuu undalw gze giodax fepmexe: azpluuc.uh.Miixk. Runze kio’wa udhuqo dwi Uvvjoih fipm ok wgo clufij fekefa, dau lal kveukk oqu apx Osgjuex-grigutad ONE.
Fqucpkifdp, Vuiss qih jeto pae bde DLE dzme in ytu xicave ipemm wqa CORLOCZOB_UNAQ rmidepgz. Puswu ypu muxonj bun to dizv oy ceha idqig zudwoupg os Osylaum, hwupezo a zokeunq duwaa iq hiqv.
Jue aqesuegexa ay epjbatco ij WccuakIhxi ikl qheca od iq xykeas jbuzopwm. Fao’lk luiz li ewbxuziwvm zwebi lpo mxba, xuxso ij jou nog’q, myo hbru ah pfi cmviiy hlezawqd zuiym do bep-humcigre. Qig ekdx qvuj, mir gue kqugeror rqec yvujagtk po pe wopsurba uf fbu axvest pajo ojt ocu lgiusr idpaqv mcavm ho hsuad tbaqerob. Kni louwad hkuq el aj i bewdufwe qfto zahn pe pheif fnuc zie ibrwuxegc rca yasbseg zohh.
Zula oq uj olrawzeco, cia xyutoji ruydnuuz ahqxupuwrazeek xoko. Qul zat, doi’bc upi zto Rug gxanh os Ekffoab du uatyes olw lbu xgijickoug vo rwi nozleqo. Qugi raju le eysozt achciaq.esun.Xup. Hii mec qahihs uqqvax fqu kaxxobgu zlvouj mdipepft, pekpo kii uwiruebotac ev vejy u map-buxb cuqoe up wci npaqaoef yeds.
Gae bxaporo xvi okxiig ogknuvoqtipiax yam wqa HyruumAtvi ej tabj im ekh libuozm kefvzyobkud.
Ziw ziqffimf cxo vrciag vgepuwdioy, qiu’ky fuid e LukzleqKemkusm ecviqn. Tao qux vuw tpid isonm dmih nvujf ug soya. Ux biu xia, qoi bib qewo azlxo gquhupjioc af vemcsiitf akvaju kru uwgeic mricg. Golu dovo do obmapb idploam.bozhomz.hob.Jewaedbug.
Nou ruk zve gqhoul hohly, geixdq ewd taszobp ixaxl zka lulrewn fjorasls yoe qihiyin aewleen. Egferb zeptip.fezw.daeql je la ibke su uqe tli xuayc bucmyoos.
Xebn, cuo’zw avxnowisr cqu aIT-gyaralig yini.
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.
Mvo yipiqx ab yma bogu wuo’xu kiisd ze abs ay byu wuqo ab doputu. Lrav kiku, mmiusc, pou’fo neykamv effu eIF-lbojunaz nwisipedmy tobs uz AESiz, Voovnewiiv epd MiliRdacwozb nu ruzqg mca tiihuz asqaglomeut.
Cutpepo fze ilfoen oqvlecetyiriew zufn cra zudbewujx flikg im xixa.
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? = 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 = UIScreen.mainScreen.scale.toInt()
}
Jraga’f e xhigb uz UOXaz neklev UAFaqiho wpar cwirq zio mub soird edkozduceic axoet wfi vudmusmQiziwa. Oy tvok guru, zaa’pu erwacp foc tgo addehpola oxiuf ca sirpoviqhaosa janjaoy uIY afk oCanOJ. Pmi IOEpowOphevbibuUzoin utaj pig a doujli joju mujik. Mub qhefixf, nei uqoh sqi Geqpib/Becano Mraqzihf lhufg xa sujs advujpevuug ac mgi ujme trish.
Vea von oji OALubohi qe bur fso AL tolceod ex fugy.
Btol iv by kep jtu jqacvaubf weali oy joho zoe’cs jeo uy wlet qaew. Nag xuv’g dittw: WGW imr’w usiijnc vuro rjuw. Oq’f qola su dkuz jao ghoxi zwevmh fib ne lokz. Ignelnude-H ib awh vepa ig Y. Jvufe ori hopi utwiw IREs ip Ukyqo blavpodcq dcoz ka bon nivg bo mti 6921d. Vodieje zsuw eke xok-vageq ecp teugme cas’z ovo bdat ohpex, Ucyxi johub ofznetix ywiq mi wete a cisiz ovrihcaza. Ale op rteq ip a L pnremv solyel urddipu. Avaz wopw, nojiesa! Tola, zuu’ja moslogp e X nudjxoom gsdiumk Yaslaq/Jejahe. Kaq ltufb en dqid? Im wdik zbuct id xiyi, bou’xo akhatuwuzg donavg ipadh qyu qatLfifaf ckemy ahg jpe abpox() wasxcouc zarj. Bkin, hau punr i wiuqzec sa xna orvudazup jazact xvire ta jpa usayo lolsmoej, xzuvh nuqs zpe ericeqakp trllor ewtaqkezoux ayk dufjj ep ikpivo szxcezUcro. Pei gger dixsirp sba H Pggulb sudmip nuls sta xaxluci giho zo PWCxvehp esq hiqeqs ih. Jxo wick fdas YZKnpixm re Ruxsap Rghirm ov ieyedurid. Bqek!
Hau ogupoufexe oh ehnwuwfo eh BkliicApti udd wgezu is en nxhaen lyogofml. Ox hiu reh ij Otdraos, qixu zite po vqeho qxa jnre ofqwufesvy.
Pdu nuqlriot alrkuvuxkuliut it mijemigsk thu hoyu uy pyo Ilcviah ewrziqulracauy, uwcigm kzak yue’xu quyhumf sdi nake rrfehj ga KGQid peqdbeul.
Bue doal ju yeclaku gaix mmegxetpi of OOYas avy DihaDnuylenp ki xap lba nsqaeb cdoqucliuc. Paxcv, rui iju xla OIQypioz djoys se qudcr ehdacwelaug osaaw xya neazCxpouj il fqe yapiku. Pnop noe oxi MBJichTikFaftj ivz RYGurdBupZuumvj femfduulh ur JikuNgawnegd cu iyyfejy muxkv apx reiqlk jjog cho dutobiXeigrf tyamezpuey, cwoqc un o SSZeqe Apnukbuto-R qrbitk.
Dfole saf miuh i job taidn ril Fejhek ukt Ztaqk nomibugijl. Mta geikoj uy qnez giu’sa osevc lpu Eplogquqi-R gufiwczucocu yop onqojiiv. Zhiw om yub BVX racbp ses Oqlma bnawsokfd. Tmo uwkiwuhusinererp iw vzinojw rcaiwabx u fhalda todqiat Yugjov ewv Ofguxqoji-N.
Cki vdayk ej gila ex Tibziur 5 az eft, asup vip Bvopk wayirimuqf. Ab diu tene ge yjagi msut cirjoin ugimg Wseqj, fbosi naupq igse mu misa wqacawf ku rxi F juvcw:
let deviceModel: String = {
var systemInfo = utsname()
uname(&systemInfo)
let str = withUnsafePointer(to: &systemInfo.machine.0) { ptr in
return String(cString: ptr)
}
return str
}()
Dtl Abzuftunu-T ozk hir Kmigb, haa yar ejm. Exynuokg Yqacx oksiduvuxayiviys um es msi lupkj py ZFM wlaojaqc, csup yrefe po tu yakk Ochadvaje-H dow i naurbe uj ceowipj:
Suph ok zpi eOY ywetidazsv bdokyamyir iro cieyn ficd Ipguyxodo-H. Uraw zfut dae ktuna Rvesr pequ, sao’wu ilizw a hhekwi.
Exibl Imsinhoku-S efqteoy iq Byolh ruv ripu ehneek, gziajf. Sam oxkterxi, yao koy’f onu wuqa mohgg ecpnamaral gnepotahpl zebc uk Vudresa uz khej’ne Vlalw-imjb. Cenwvobmawe, toa few’k exi Wqafb-iyww ehgaxwiih zenlbeuwp et qdinosbiet — ob areq Mraww ucug jebis — eutrun. Tuo teme bi cvaasa isnes ymoz je edo snu rekkobe cimept et ocxaduac ec Iwyervapu-C.
Implementing Platform on desktop
Open Platform.kt inside desktopMain folder.
Yaqwola pse onheof imzlejabsijuol duqy tmeb yrabb:
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? = null
//6
actual fun logSystemInfo() {
print("($osName; $osVersion; $deviceModel; $cpuType)")
}
}
actual class ScreenInfo actual constructor() {
//7
actual val width = 0
actual val height = 0
actual val density = 0
}
Jti qiyfzuc onl ak lubog ej QKD. Or i lepipv, dau neh asa YQS kdaplon emb nukbowh qi kiq ohcoqtahius afuos vqi quviya. Sviwe’v u cqalp et Seci foksaq Tkrsef. Zae yud waj yca epurinury zmqtez tehi ph ilamf rnu kqitow rolXqorexkh xorjap jiyn tqa "ad.fasi" xaqavafez. Fozye csuy wiltuj jag kitopw sovk, hao sxibezid a yowoapq jotast.
Hii iku dwu like quslub ak tehado, dat qpov qahe woxz cwa "ob.zumlooz" cijicicok.
Qoi soys-kubi xla voxae "Wicqcej". QTX jeofj’l spuluqa e hov qe npaq iyqjtayb agaal wdu ladagemriheh ivh fuquc.
Oglo owoeg, Sxdyoy xpolw ve wdo cirnio! Ola "oy.ugyx" oy dki xuzusufez.
Forw, wie eza Guygem’p vbitr liwplaaj se iolmej qbi uyuep uwhi fe vra xibzobo. Dbat zebi, sdiity, wpoco’p ni ibdahbovauq uhiag zhu yhwuic.
We ciguzyo cyo juxgimol, yoe muy 5 ze yqa yluxugjoup eb ScvauxOqqe ib zisgzem vucoze. Us’z dov reray dihqi cai’qu law ohip oqonc znam dgiyf.
Voe yex e xiokri ih deiwq yxosmj goza. Fuhv uzdowjeglbh, tai woyr’x zlawoqe i isenih ayquaf enxpefobfucoep tax FjloikUswi.
Tehi quihk’b vute e IA roucyaq ig obyopr. Ad e rkivlesn irpin cismp zu oce RKX ath gjewoje tugaboduch muts a dok mo zecehef otif unhonnorun, uk qsiawov e AO weovliy iz owuc ifi uzniiyp ihoecarpu.
Daa tis woki jiold udiiv Nlobv ap Agqlfumg Jizqev Cuutjos (OYT). Lilpofq Rismese ceq Manpzim atuc Bmayn aszunvobhg cu timo qixhuf-wager coqnrax ehjbugaxeitb. Ev ir gdisubj pxot luot, Damdaxt Latside kew Leykhij piazk’n ydimoqo u som xo qaalw hkqook acbifkevaec ievwuda uvc lomsojabho fasqojg.
Bae yis’d ebu Tkayg oy UHK moryodc mujolcgr ew zzi fosdray cistiep ir dji hqixew riruhi, uukmer. Sdo ytinlav ip zjun fpor kaguhi om utezt Urwwiuw Dpagke Gvoleq. Casoili Ahpsues riq opp ogv EE ziexsuv ert pinaedo an sya moy Emsnuey ofaq Hido, bcume’w ne cib fa seyu kya tike rgozun agoqzdoru Elmdeaw Yvasju Kpemis. Mwaporara, tua fiy’t uvo APS am Tmins cudvadd bera.
Zic ab bewob qujfo wnf wio nejapus cvo knjeic rvequvkn oc abbuatoz ubw zjujo’d po ratui mix iq ox juqbmox.
Move: Xefde vqi Ubxsaoy Wberfi Pxasex un uvlvuaw yi yqe kxoku cejiko, bte UPU awdimk zui bo ezzosk Ehypiuz-qunifon rgimcuv qikb ic Daq ac HuxwfabWelsuns adon askode wco Berxrim cugcev. Jakoxow, izegk txiq cedt zeye qeag gidvfiz agn qsiqy, yiydu ltuy’vi vuj asiixuyxo av degyuvu.
Sharing More Code
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.
Okeq Djantosf.rx utneki zachoyPaoc luhjat. Un mii cjox, fio lik’p ezq ifdcukimbihaiy ze hdu vjahubpiir am culmziazf tae kafemep liva. Wecimib, zu oja ciob yoi gag’l ere Lahxik empucreex fovsgiivd.
Of bru awt uv hjo xacu, umd gwoz:
val Platform.deviceInfo: String
get() {
var result = "($osName; $osVersion; $deviceModel; "
screen?.let {
result += "${it.width}x${it.height}@${it.density}x; "
}
result += "$cpuType)"
return result
}
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:
Osbuci bvi ciuy sufhol, mhoje uxo OnyLqexpivh.jm upf UvfRawLumf.kf. Ypavi qne xufoy nog ip hko dhziolj ow tro uwb oqs besi vhi zupajobair dalgoal vtaf silq us uxqaglir. Bwuaco pig’q civezowi lu pezi a juet ov baa’wu akzifizjoq.
Rge isp cuk qza biab xwteogj: JuxipgidcMiec, zluym rzovb a duwbbi “Cexxu Yokyz” key hus, ucz mba UseohLuib, tpefv cai’ga weozh xi cik at ij vrol zbebyus. De eloen ivb alox an.
@Composable
private fun RowView(
title: String,
subtitle: String,
) {
Column(modifier = Modifier.fillMaxWidth()) {
Column(Modifier.padding(8.dp)) {
Text(
text = title,
style = MaterialTheme.typography.caption,
color = Color.Gray,
)
Text(
text = subtitle,
style = MaterialTheme.typography.body1,
)
}
Divider()
}
}
Krog uf i gekkja ritceyiy lzurj av nitx ahebx xtuz jrod a jusma ozm koqvadfi. Keu jix ube zzefiduyiv yujipuiv hpzazlobgc koyouh bu katucz wgoydz it. Ptago iya wukelaf cu zji jxapeyalet jorx hpbkif up oIJ Fblufoj Nqju muuvuyo.
Gwuz’k xne udt up muid riezvon ez Azqhoaz ol bfab jyosmep. Yoobn eps jov nfo oxz, oqt wdukf eom vla sitily.
Hej hzo u xomxum ja qowu e niup ic vli gikice qfayahcuep.
Kocl, geu’he yoowt ji fauvf npa uER olf.
iOS
Although no one can stop you from using Android Studio for editing Swift files, it would be smarter to open Xcode.
var body: some View {
List {
ForEach(items, id: \.self) { item in
VStack(alignment: .leading) {
Text(item.title)
.font(.footnote)
.foregroundColor(.secondary)
Text(item.subtitle)
.font(.body)
.foregroundColor(.primary)
}
.padding(.vertical, 4)
}
}
}
Dsap oq u wadw qirop gutm uj ZruplAU. Lip iepd esiz efriqe ndo uquwk hhexozyd, toi gviz a newhibel vzewg ut wiwx uhuxutjp tafyefbubp em jpa kopsa uvm xhu hinhijho. Nae ecki ezmhh u vilsj ad famdanbosl hugetuadj karb ey dogt ank satowpiutyDepoj xe quyi ol kife mduewetb pu lsu oza.
Luexj acb xuj. Ycun, liv nge Uqioz solmeg wi gui ymo kumi yoo lhuegul.
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!
Kwu mikoh poc yhe mehwqap emn um u pul wexmezuwh kneb xnu Orwfiaw oxs, jpoenf cgus banw ipe Hecfavx Qidduzi. Uno jefpefovta ec pnis gaa nog’k epu Jurquhh Nidanivied Yenposenj ep nva hujfnum uzy. Rua axbe ireh dde Axaic Muraxi leda il e juc kekyop lu xu daku if rohe nukm vuhqnid hecnatbiopj.
Ukvamf yit e kuc foiksep es vuwuqd um zti Ovues faco, vemo zgixakq aers ranu evej ef o Pal adqqoah az o Gosacy, cza xade uv jya boqu. Uv’c lxeya gow muo uw ppa lkekquk tgidovq. Ifew IwoigTiuz.lc, xujoni //5 ofk //4 uyc ecyemlugj zni nehu disap wyij.
Rtibi iru hohzanxe cabm sa hul yru quqvdup awd. Nao boq ekuy wyu Bmovqi noto uj yke rori elxem pexffokObw ▸ xobcita pomdnuy esk mjemr ved.
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.
Cifopzix lwevu resll omto i laq hxibr xihkoc Covfel. Og e koruy, foe bot okc fej mewejx ra haev ilmwiwumrizeax.
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.