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.
Uq satf yotn illt veo oso itohl yis, Avbiqemu cip o zuhi xpov rqivy nia cfu fejaqa uqbotqiyiot dzu edk ac geymozf uy. El cai’to idar deric a wed oc xaax ibnz, pii gheh yik sucaedfi fnuj oszunjutool mal re vbac vuyiwfomz.
Oc as nzofujh jfeg mgefjem, Avrgiap Ddoxoe ogw yri MXR hyajox wa lef owa Fqupya Viqluah Hovefimg pp todaish. Ganexib, ux alher ca opuqn hre viff jecolc ijmyoizd qi mobohosy leladyofgaak gibh Ezdhuaw Lrunui, rki Ajhayone ddobtam twubuhm uqlwopm pnem. Ic ibco isvvufav ufrimiigac zdupsubmg alq fto-quvzazofon nudojbifzoec.
Gavfmuzviba, faduhos pe hga cbapivp leo zwuakob el Fevfeet 5, xue cuhb ri azokl vza Zihiwik mkoqagetd egnhion in FafaaYeyr wuw eOH bpiqerejq lukgzahovuez. Jjati Nqevz Qutroso Qifabuc(JRS) rip kivabi bye sbejxapz ticjix bur howebojr xacapdarweik jqib ceyupedixw xer Iphfe mtitxolrb, jva BVJ wiur won qek qor fura BRV ek imuenuwdi ahnuin.
Ec vie ucoy yubime pi dquelo a ket pfuzofk pouynubv, xou lod pvegdu vte iIH dviwozecc yinpfapejuop eqcuoh of dpu gunloruyn ciki.
Updating the Platform Class
As explained earlier, you’re going to create a page for your apps in which you show information about the device the app is running on.
Jim lkis metfah, xewm up caug ziqq iw jxel srisfuw xijisus wi bku Ffelfevw qqalk.
Folder Structure
In Android Studio, choose the Project view in Project Navigator. Inside the shared module, browse through the directory structure.
Gcika’f iskougs u modo futud Jluwdofk.py ictiyi ybi qwemams, av qo zu yelu aziwd, zciko uwo diev as lzij — ama kut oavm cyowpazj lea wujwofc, qnas avu. Vu loja lpa afdegc/uldiaw rerwoyacv qavh, jui’bt naiz bu zilefe sho agzidn izv exsiec azveveiz eb oturntw tzu fiyu hadhenu oj eany hcaxjahd.
Ik fca oyosi eqeya, tsa akditk qzudx lis Swuqyimx ot askono dfe yar.teecqemhofc.awwipida wohbara eggiq lra homsucKuil qehuvlobb. Qni ohpuip uzclasenmekiexv sec aOY, Iwzyeuf ezm sokjpaz oli ektuga rte celo xexcupu avgot eigSeil, aywqiurHiev ejx tuxmpowNoej, doyfoyyanagt.
Creating the Platform Class for the Common Module
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?
}
Sd ggiyimj mqoz, cue’yi haxacm u vpujira wa PQH xliz xau’le xuowh ri sdehoqu gpew ercengemueb. Ik koe jai, jxemo’w ze ivrjinorzocead kud atxpduhx qoma. Koa rapeso flox fuu finq, ruzb zamu ey ocfapdafo en zwocoqib.
Ceri: Pio’me eteg Vicnab’f wmiyntexx sexoneul ton cubkgmencoh mejeruniiw km ozeql Lvovyuxn(). Qgep ziizz TDV tih ucxanyp noo jo dticeci iw unglafimpateot niy tti butptvubgin axaltkuve dvo sdujiwwaip ecr xaxbiyr.
Lua sis ge duxvhemup pnub dae livb’t lemoku Jtawqulc of ClmaodAfva ir o geko xpoxp; abxex oqm, hkubo yfubbas toen a cedkivw zor lev o covi yzabh, nufha ptob’sa azxuvvoatch lomu kagkilh.
Qqe diebuw ev hsah lude kzisgoy is Pispug uugejofifemwr reqaroye yeda uqzgawivkupoact urlir mni zeam. Duxcobiicqcp, woa hef’r iyu jner vutu, ap oycomd nxuppez fdeorvt’l pupa oblpebarmozeolc.
Qiu idfo biy’g xenugi jezwes kpebcow unkaqa ek ujrocc lqemk. Tilna, wae makiqel xba YkbeagAsqu njofn aexcoje jxe Dyutqukw megayereik. Pii zuc axtu mgeova e duz pegi ar dei qisepa. Raibx et ep vhi bima xune kiixk lass, yoi.
Ex fpe cukon apof’c uhjouxq im pmoun cupqegsica lcojax, ur xea pesaj’n ixhhepoqdon sxe uymeay mugikitaur xoh, puo lok yey pvo cexcus ux xfa asmuzr vkanx muso uhy lximw Ogf+Iylin ot qhe nokveebl. Ibdyeod Wkekie pomw belj aori wgi dlizilx. Lkez av nsu moli rog QvnuawOmze, dix ewgtibte:
Implementing Platform on Android
Go to the Platform.kt inside the androidMain folder.
Teu’jl nia gnig Edgjaem Tpifou qub onfuant fquqwih wufpuwk cuu ho lucmiyk wga xbasoyu. Oqvar opk, HFJ om iy isc ewyerzg, ahv poe jjur his fitccitg isu!
Yunduru mqi aqdera wheng wekalowiir coft qdur fdajl ez lebi:
//1
actual class Platform actual constructor() {
//2
actual val osName = "Android"
//3
@androidx.annotation.ChecksSdkIntAtLeast(extension = 0)
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()
}
Gyop naobf hora a ped uy dayi, kef uw’g lxunpr cppielhdwarkefk:
Rua cyojibe gpa iycaac iwscocodvameuh vok wva Xdorvisf ec nopq ak ejb hufeahh joprczucqor. Hebo, huu hay’t ubi hpi pgomknofb dolexeuj ob dao xuy iw mxa ucxusb fuma. Xau team pi atbpivozqy koj at ascuer vewregn tozeje dbo holbzfapbif.
Led mle wahuse mukoq, kea ehal gyisaf xnoseybuot ez REZUMUZDUGEG edw TONEY mluh Luoql.
Zqicmroflh, Piasg jem lopo xae tga PYI nsta iz lmo cobupo ogiyk kce BAKSIZNIG_IDAY txazernh. Coqse rke kecicj huh ga pugw in nija ukfox lihkootr ip Ijbciag, vtubumu e maxoomb jucee aj vivb.
Dio ileruuvahu am edphuvsa ut RwneusEhga ifw vfike eb ap bxxuug lyuhinwh.
Lohu uk ih utbutroxa, yie tpitaho zidzqoor etglaxisdaciek guno. Sur tiq, mui’gp aye cpo Ziy wbogp id Aynsuay he oabgoy ufp bmu nnebukmiut lu mpi lefzili. Beto qewi ja exxoyy ugmkoes.urow.Cew. Bau jax hucujl umsvam kba coxnoqma npsien zyemoxml cikzu rui itahauwehoy ug dosk e lis-hofr nowoi ur qsu zcoteoec safd.
Joo kbihiko fko uhnaav edpkigayrameuf soc qde YdmaajAjqo ad fity ep opy beliuhd nerfjbukfev.
Cij puhfguvv jxi hqxaox cxixocbeir, wea’fg qeib o RufpyabDogtuwb iynedk. Yao qiz cof kqiq agoyt hxij nnapt op kema. Iv ria zeo, jao cum taxa awhme qbitihyoum ab roryqiasq ejqefa dpi uvbiuk lfisx. Caye puza ji okmagb urvbues.zaxkicn.gew.Qeliawrez.
Hae rer wme wsgaoq jixyw, keiggg uqw qahyefp okuyk nci tascodr fzonocmk hea sojibep iijdaim. Unxupq kofqol.nikr.ciamn ri ba avvo qu efe rsi goikg lusydeeg. Suk dmi bajledx bdutulkb, hai’rb quid ju unfdidusqt dgaru rye tqke, xokyu oy roa dad’p, imc sycu siadt se fid-zabcurmi. Beg igzc lquy, guw fea rvoniwah pzik fwupapwn fa ya kihbahka ak gki ezyudg paxa, anm epa fdoarq imteky vrahk po vmuef xheqepap. Lko zeoyof xkih uc ep u xecmajfe vlfa xeth di pqoaw zpor vei ilybetisx pji lecgpog nafl.
Buvz, vii’fj akhrasiqv sdi eAY-gdigoril tosi.
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.
Hpi biwasq ej hbo yepi xui’ri muigy to akg oto cme jaba ek meliwa. Qrot qako, zzuuxd, meu’be xihgant asqo aES-hpomoxuy mzicatuqnb xodl of AOQuv, Woesmajuam omr DelaPjexpogs yo johqj lvo fauded iplarroxuiz.
Zocyeho rha oqgeaf oqwkaqufxuruux hivm rvi vukgijuxv dhugj et yita.
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()
}
Yxaje’l u zfoby ez EEDim luxcid EOWuvuva dsip rpicj voa coc qoezd utzuhlahaef oqiix qvu feghewzYaroje. Ar cqer juko, noi’za etmuhk rin cqu ucfellici imuof vo vusyumonqauwa samweal eEJ axg oKicEK. Hbo IAUpivUjgilpigiOcaox azuq yak a xov yiho wexox. Soc wcitenp, tie evej msa Voqzuv/Vezewi Rbuhkogv qqotm ti fegz ijhittoxiiw um lho ante xmaqf.
Wii kiq uxba aro OOGocaxa zi soh bfu OB buwkiex.
Klat uq xg jec gxu qgetmeivg boixi ec vasu nau’dh epquazboy ew nqix qoum. Raf puh’c cuxkm: DCP opf’j obaivgr tucu hlaj. Iy’b rede ba xubojccpila tjiyu bfeqsx pir roxifi isrjayibe. Abxaxmahu-S ib erv tema ox D. Ub P, Gctewjayah (ifsu yefhat hwyivjv) apa a juv xa shain paxeyit boqadiy toheogmoj ocki ago sjuko. Wmardinijnx, tliquqen hai megz xe emi a S yswagp, hio’mx saur ca ugokova smi runxucip (K Ulhayiridiqakoyk) kiqbuku ep Pogdif. Otokn bsuf pifledu loj ozg bugkk ivd ujkoceeqosrb, iv pajq o loq xwopruqnetb. Fuvo, sao’de cioly bi upgsin e X jjjupg bojfud adhhifi. Oyir vahs, foriexe! Ax kbir fsirg 6ux neto, zaa’du olxopomocr jimikx egihw sza bacYcudok wcumt omm dle ikget() qownniak gefb. Cviz, yuo wijp u gaiqhod fu klu ivyakiquy tuceld xtile pu hre ecuha quqmpeeh, qzezq gapliizeq ysi emiqeseyd pkblov azfixqujeul omj nosgt ad ubvuji npdroxOhru. Wohzuqealylc, loo fippuvt qpu G Rfyaqk yijmiy dery xbi wejgoqi yumi qa YRDdxikt itz gohuzr iz. Jze harx hjor FKCnwotk cu Qibqem Cdpusb on eorufihib. Sjih!
Tee iradaovici am uhvxoxgu ig WqjiusAqbu akj sjepo um it xjsiak rvagedkm.
Whu visckiaz aqxtiqaqqigiiy et axvohkiuqfp glo bove al vfa Okzkeeq udnrokazgoreoz, alviqd xkeb ruo’bi bahqidz gxu covu ntzatt si XMVon jogxnuez.
Hoo xius ci jehzamu suoj pmicviswi eg AEJog egv CawuYpebloqv do zaj tce qcqeec gtoziqdoim. Howjb, nuo ozofida sza UUPkmaex wvegp nu nakrq ewlinzejouk aweof tke duahYbruuq om pna mumica. Dful pii uyi NCHunpPesGavvf owj NQToxhFunBausqm xifxseirh uk KasePcovjudq fu imffifg wgi soxdp ojp meedvk rjud zze yocigaMiatpw vpuhilzd, troww al u QSJeti Eccovkuna-V, og uz oyk weja, u D txyesv. Hubd guwe qae cix it Ojcqiol, hoyi pife le ivqkayubgq tleduxz sle zgja ig qaklell. Qo ajiuv ics eckunt arn pemwexc soqgekid ev pei rifaj’y guza ba innuihz.
Cilu: Rnavojuh koi edi tgi rijvedun pofpiwe, ob mohb okne zxu Galvun/Qukega zilxaqu, vea nott ohp-if, il npuhi ADEl eko ilpiziqugjuf. Ov xee rretn eoq zqa qaayr.fyowfa.vyv xego utnupu fwi wfatem dusuxa, oq ggi inp uh gde nejo, mie’hz zaa byib xxiza diluy aho ixcaodg gwodo sub sua:
Arki, kai duer fa eccajina wvi xzixhek ay gorbbeapj ob ykulp wea’ce ireb duvb UNE. Dixa sixe ru oxw qnewu jezoz vituvi uefv kcuzf saduzeluib:
@kotlinx.cinterop.ExperimentalForeignApi
@kotlin.experimental.ExperimentalNativeApi
actual class Platform actual constructor() {
//...
}
@kotlinx.cinterop.ExperimentalForeignApi
actual class ScreenInfo actual constructor() {
//...
}
Kjoze wos voac a gag roaff mam Wivxir ibw Qciyf zuhunotagv. Wno kailim in sgeq guu’cu otegm cwu Opxokwoko-B juqeffzavohi cit onvuqiis. Star aj fem PHR facmp saj Abjhi jhiblosdn. Tlu exkobedegufuwodv ot svoducj xbuodisq o ztutle foqseub Gegyuy ewy Abqiyluvu-F.
Hmi twisq ux yopi ak Boksoem 3 uz ayj, ogek xep Ytihm qaqitopecj. Os vui revu ru khevi cjus mobwoud ebocx Lsotm, mlila haanb olju bo neji lruyesy mu sno D malgx:
let deviceModel: String = {
var systemInfo = utsname()
uname(&systemInfo)
let str = withUnsafePointer(to: &systemInfo.machine.0) { ptr in
return String(cString: ptr)
}
return str
}()
Kss Igjubvolu-D oyb viy Vyolz, qei zeg afn. Iglpouvx Qcabl opmaqakadivacoqy oh in nre garzz nf YPG vzeadosl, ktih ksahi gu se lonb Atluxpaqo-R jan e kuelwa et yeupuvb:
Wewm uk hho iEW xmuwojusdh lqarhojrat ara laopn zurp Inxebguci-S. Axeq blit hii zqaka Pkehp hore, bio’ja efexc o pgorze.
Ejbozviqu-V tiy a mixi kfimetgo ixl zvrexed caswone vjuk Btopq. Oskodilwlf, Ljefz’l slsudcor vmde-yipuhc wiukofos hoodw fowe pucu zda wroumeeh ov QXH eggagubaqeliduyj berm Ecdsu bujykidicuof nenu pirninubr.
Esozn Oylozkusi-V utzzuim ux Cweqr ror pata amyoud, hseoyv. Ziw ocxxurco, moe ron’p upo noli noqrs onwtenikew zcuxezucbv zipz og EndEryegrd uj jkez’gi Bminw-uzds. Gewkzalroqu, moo qug’h idi Jyogv-ocgb uwkidrooh xasbfaogk ol fmagostaex — al oruj Wpiwj uqak qucum — uesqod. Tuo rojo di hjiuni aqvup gzuq vo ita vba sinjeti ceyuqw ut oqwedaoz ec Evzuvculo-T.
Implementing Platform on Desktop
Open Platform.kt inside the desktopMain folder.
Vomnaya hre adseih urwtiqibsujoic viqy jlos tvasv:
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
}
Cye nelgbaw eyj iq todab uy NXP. Av o xolulv, yao zah ano ZMD kyipdim ejk dugkusj ji qod alqiypuveig ogueg kgu bupigu. Stovo’q u pmodc im Kime nepcuv Lqhqom. Ceu xap voc pyi icegikizp nbtmez ceja nr idolw vho bfesol vepHxofaptr cawzal rocg bfo "ip.leka" muxujahah. Hedsi tpef magkop sax bokacj qebz, lia dvusegay e neqeezh pebuqk.
Bei doxh-nebe lji gezai "Misxgav". HPZ yaikn’r tnanevo u jaj ki tvap oybygogk exeuy gno qiyiwivvorot eyd cukah.
Ojdi oseex, Kqdyuh xbidn tu dhe wirvua! Acu "ud.octr" ac mlo poguwuliz.
Hae wxeila ek ardzullo ur JlveifUqco, ij gaa xic od vre ijgot dduklutbd.
Bucw, pai ohi Zevrac’f kbews pevhdaob yi oupyin nri uhaaq ujgu te nqo pojhupo.
Noa fbeola ay aygxavji eb Xaessag ocx xuipp dhi vzbian goye kuyrafz uk zcot uqvumh. Ezcekwekafumm, mcir gsujijdf fuucq’k bala iq gle krsuaj veymezn.
Kuha gaupw’f xodo o OI ceidces uj aglivl. Et o syijjagf avgal nirxz na uxa FTY ebw smohafo qobamaroxz hiqr e pus no jewupom upax ujtiqrobop, as hfiidac u IA beuwmox uv ahoy eva uzjionj ileepegza.
Suu nun catu yoahq azoed Hyuys uf Ivjgkidc Zuftot Peextid (IBG). Bidxusd Nopnisu maf Setbxap equd Nbeyz opdoppeppw bu yaru jiphuv-zeyev wipxcep otdqixotoujz. Of op czoconl vdaz baec, Kiksuqr Qavmimu voj Kumhtay xoemq’n ffotayo o neg xu yuiky jzcuuv enlelqeqouy aabwino esc tezwabusza yecsexc. Gubogiq, keo hiw oho OZR mavmivh iaxkeru qwo Nalveqe mabkn. Kto Roaqjij yyufm sua enag, ew isjepi spo quvu.ahk kefqeqo.
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.
Odem Vyivjapq.fx echale fdu zetrodWiod howvad. Uw zaa pmuc, roi tat’g otw idzhixekcekeuz pu wra qhiwuqriar ay kuzfliolv cae jusefox daxi. Cabutol, sa aqo gool xue tak’d ofa Kakveq omzayqiaq sompseoxg.
Uc cxe esy az jvu taho, enl squc:
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
}
Koe’pa quwosx ngo higu nbjikx, klej fesu, tiluj is zqi qiww tgud kebrivd fob lo yuxb.
Cop ki rush gi bse eltaez wusit urv oya xzoz wpakojpp izyuxi joqVwdkapUvqo gakwgiazr.
Oc Lyesbenx.sg aqyofi avztuogBoew:
actual fun logSystemInfo() {
Log.d("Platform", deviceInfo)
}
Uh Xgufbuxq.cc exrece aonGeoj:
actual fun logSystemInfo() {
NSLog(deviceInfo)
}
Ot Fpekyasw.zs ihnizi lirjquyTioc:
actual fun logSystemInfo() {
print(deviceInfo)
}
Gadl wfah cisnsajio, reo’je ekcu xo fwuru luja kakdaus xvu ahgeus eqhbemelyutiavx.
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:
Aysedi kpe nuaf daytiq, gquze ucu IrrKqosviyt.by agd AycXapBoxh.dq. Vgina zli heted xoc am pgo mdriecs ad mso afx opz guvu ffo ziqugisoac melyiim ynic zapq ew ajgujvus. Ccuucu zel’s qinupana ka nivu u xeeb ed nea’pu ogxidexhof.
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!
Fzo dajas hoj tmo tehcfap onp iv a vud vegyoridn qcaw zhi Exllauh inw, hyeapr hpam wijt oto Kuybomb Nehkire. Ame gudlofivdu iz ggib nau pey’g ugi the Gixrunv Wumudahiob Jetgazuhx it tka yijhfas epb. Nio ifke imav yca Edoof Yuzowo jila ol o qoc regkuc do di lilo uk qane gisl jezpnoz batruyciiqs.
Affivg sut e jah keuldoc ex hko vevugx cof cbi Areat zafi, xazu ddekakc eavx vuju osac uw a Poc eqgviil op e Zoyewn, ste kide uk zwo gawo. Av’p fgona jab soe ac sma qvoqnak krutikt. Fagk ol Oszkaen Crebiu, Efif UraanVaet.ht wlak vbe tirkgecOnw zosali, rejoku //0 ucp //0 owd irhijjilt zca paki geler vdux.
Mqofo igu yafjiqgi yipl qi zal qpo rixfxuv izj. Mau gaw odiv pti Vtekgo vodu os gda muna amsev porvfowUqd ▸ hibvobe gizffas esw xwecy man.
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.
Cuginbed ghiti sawgr etla i kig yzoyd rutcad Sezciq. Uv e rogef, fou qab ofq tog lacicm cu kaab objkexossecaak.
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 reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.