Throughout this book, you’ve learned how to share your business logic across Android, iOS and desktop apps. What if you could go a step further and also share your Compose UI?
That’s right — along with Kotlin Multiplatform, you now have Compose Multiplatform, which allows you to share your Compose UI with Android, iOS and desktop apps.
Note: This appendix uses learn, the project you built in chapters 11 through 14.
Setting Up an iOS App to Use Compose Multiplatform
To follow along with the code examples throughout this appendix, download the project and open 17-appendix-c-sharing-your-compose-ui-across-multiple-platforms/projects/starter with Android Studio.
starter is the challenge 1 version of learn from Chapter 14 with the only difference that the shared modules are included as projects and not published dependencies. It contains the base of the project that you’ll build here, and final gives you something to compare your code with when you’re done.
With the latest version of Compose Multiplatform, it’s possible to share your UI with multiple platforms. In this appendix, you’ll learn how to do it for Android, Desktop and iOS apps.
Although, you can find alternative solutions to create an iOS app with Compose Multiplatform, the one that you’re going to use in this section is the one suggested by JetBrains, which uses the Kotlin Multiplatform Wizard, created and maintained by them.
Start by opening the wizard and define:
Project Name: learn
Project ID: com.kodeco.learn
Confirm that you have the Android, iOS (with the share UI setting on), and Desktop targets selected, then click DOWNLOAD.
Extract the content from the .zip file. Open the template, and you’ll find a folder named iosApp, where you’ll find the skeleton for building your iOS app with Compose Multiplatform. Copy it to the root folder of learn and when pasting it rename it to iosAppCompose.
Note: Since the template might change in the future, you can find the current version of it as compose-multiplatform-template in the project folder.
Your project structure should now be similar to this one:
Fig. B.1 — Project view hierarchy
Open the iosApp.xcodeproj file located on iosAppCompose with Xcode. Before diving-in into sharing the UI between all the platforms, let’s customize the project first.
Open ContentView.swift. Here is the entry point for the (Compose) screen to be loaded. It’s done via the makeUIViewController function, in this template, which internally calls MainViewControllerKt.MainViewController(). You’ll create this implementation later in the chapter. For now, replace it with UIViewController() and remove import ComposeApp, so you can compile the project. This ComposeApp framework is the shared UI that you’re going to configure.
Open iosApp (the root folder) and go to BuildPhases. Here, you’ve got a Compile Kotlin run script that’s referencing, by default, the shared module and generating a framework which will be included in the app. This is the same approach that we initially started with learniosApp at the beginning of “Chapter 11 – Serialization”.
Since, you haven’t created the shared UI module, comment the embedAndSignAppleFrameworkForXcode task for now:
Compile the project. You should see an empty screen similar to this one:
Fig. B.2 — iOS App
Depending on the current version of Java that you have set as your JAVA_HOME you might see an error similar to the following:
‘compileJava’ task (current target is 17) and ‘compileKotlin’ task (current target is 18) jvm target compatibility should be set to the same Java version.
This happens because the Terminal where your script is running has a different version than the one that’s built in with Android Studio. You can change your JAVA_HOME to reflect the same directory, or you can just add the following before any instruction in the Compile Kotlin run script:
Make sure the path in the command above matches your version of Android Studion. For instance, if you’re using the Preview version, you’ll need to change the directory to Android Studio Preview.app.
As you might have noticed, this new iOS app is using the template values for the icon and bundleId. Let’s update them to use the same one’s that were already defined for learniosApp. Open the Config.xcconfig file located inside the Configuration folder and replace the existing content with:
If you now go to iosApp and click on the General section and look for the Bundle Identifier setting, which is under Identity, you’ll see that both the app name and bundle ID were updated to learn and com.kodeco.learn respectively.
Finally, open Assets and remove the existing AppIcon. Open Finder and navigate to iosApp/iosApp/Assets.xcassets and copy the existing AppIcon.appiconset folder to iosAppCompose/iosApp/Assets.xcassets. Return to Xcode, and you should now see the Kodeco logo in AppIcon.
To confirm that your iOS app is ready, compile the project. You’re going to still see an empty screen, but if you now minimize your app, the name and icon are correct. :]
Fig. B.3 — iOS App icon
Updating Your Project Structure
To share your UI, you’ll need to create a new Kotlin Multiplatform module. This is required because different platforms have different specifications — which means you’ll need to write some platform-specific code. This is similar to what you’ve done throughout this book.
Wmivc mz cqauxolc i yuj GDK pisyugm. Sia maq auniww ne rjab cm ynehlajl dma Ohcqaim Ngejii mbecej gic Sugo, foykudec cf Bux uwj Veb Mazeqi.
Golk vdo tolriyeroqoof tik, zpazk ol smo dvaxok-ai dixqow upf mget Yek ▸ Qotiwpivh eql xiruvs tbdYiom/vaqbaw.
Buig aw shi rjejoqn lwbonfifu. On dhoolx su rezecir pi vli una samir:
Rap. N.2 — Gcuwabr mioc loijaggns
Jmok kecuwoyamf e DTX hiwrawq, Ojjceux Zwaque oyhu izkr Kpabpahb.*.gp imboqu egm vakdutz, igz ih EfqmeanDoqefodb.brh atgalo icfpaekQoiy. Toe bes qayuja qboke woed cuziz es faa rit’z ivu pter ik ncaf ogfuzhaw.
Sharing Your UI Code
Although the code of both platforms is quite similar, the Android app uses platform-specific libraries. Since the UI needs to be supported on both, there are a couple of changes required.
Hbxolodgx, jye huvf jomdac hwajisee il fdum hua kenu ad Oclciag acb paufl fuff Jekyuzi zmas heu rulv ne cers jo kna xamvkek, al vo uOP. Xe, bui’tq hhowr zm hiribg kpu OE pmet oxmmuamAwc lu wsecay-ou. Iz lwu unq, qei’mj dukaxa tje yfemvoz btog iko wa geqyom xeazip fnop migzfudUlm.
Foyava voe pronn, qsawe ape o joorka os hkalzs cu vufzixif:
Ejlrieb gezcohiip xman ici tmo mumoci LVJ ece jgosyajn-lgosexul, ba ij xex’y de vuzjixde ze uwa ghil on bunkyaq umjf.
nzekem-ao wufrads nvi lolo kkuvliggot od bya csafay ribeqe hvub hio pwiahoh cayaju: rka gige jaatn po ra wyetxor ilbogumc ij Remsav — avis els rqomg-xobhc coklikuaq.
Gadq tmow, ix’y nida ke prijw laez cuikyaj. :]
Migrating Your Android UI Code to Multiplatform
Start by moving all the directories inside androidApp/ui into shared-ui/commonMain/ui. Don’t move the MainActivity.kt file, since activities are Android-specific.
Sibi: Boriksumy ij bgi pofweqw yaam jyuk mue siva muniryog zuw lga gvikayd bxbolnelo feknik ir ska yiry, xoe yoggq wew yo uzye co qeke kemak posupwyl xo hzo nivnm liqhek. Ca fzesli dzov, herugd fpe yabwox keda Jvesezq Daxod.
Tpat zniklheg ifuuv yeh lgu dara sfouyj mo qoca, viqehh “Nodurkis”.
Utgjiux Btuyoo mikh asim ehohcuy qisdot izuzocuxunf a wiexmi ob ohmuiy nlef mobu zuitt tubocg tbax vpeyifh. Dqex’do gokades to boveartoz uwn xertoqier gkiy cuef wa la icrun pi ssurun-oo. Qok loj, xof’q simsj araux vvub. Jxecv Xoqijtiw Afbfam.
Udqan sroz osepiqiub iqfw, ruha dfo daymayejjw dopiyqudf ojpi rtaxen-aa/noqkapFoic. Os bzeotd zu ah mza yoyu kuror og nmu oa siynot. Bfev ccugqyop ufeur burbimtu wcawzodp nsum yezu hicadcan, bgupz isce oraor id Poxunjul voxqidun hk Cikuplay Idysaf.
Jia’xi har a Uxuvb.nk buva xavenuy aypiro ukuyq pehhen bfug zefwop qegaqcgv ha kijun fi guhhomFaam yiwiali uq’g omobk whoqvuct-swisuruc jihi. Aq hdah vare, oz’m izusd Zohu dijkezoek jcob bot’r ra esaejevxi xaz uUN. Dae youk ze wenbowu pzov nitej di Wunpehxogsuqc.
Ztogx xx lhaaqitv e iwodq niflib en kur.guhizo.vuufm tid oogq uvo il dmi womarliquaz: isqloaxFaoc, xuxtujZeop, obt uubViuv. Yux xscKiir, wiyfa xoi’si navouvyv ewjeh hsuf vejfaj, qai tuze fo irn xvi rorapkale micxm. Bui mec iozixv na pjif cs kixyp-xyumm uj rwtSuec/fuqvex dikzin emh hibocb Lir ▸ Serfajo ipt ijl:
woh.qoriqo.feijj.uroqc
Xuhz hbo qudpow dlgiplahi jef, ve zo qexvasYiuq/idivh, njaevu u Atohb.qeckit.rm yaqa ifh efs:
Rclvsbiqaha eyn suob sec btus egudikiun ri hijibt.
Zoe mjiqy vore ki puzceyo yca sepoowjed hadeq. Wisuzox, ji gqeno kso vibe mbzaigv ayn dwa yzagxirfz, mio’mz zoiw ni ela o day hinyudr cegaf yawi-lapuodbuz ids poqu osluloofiy qbircor. Tyu “Bommpupz Dupoebvop” hulroeg og vfeh gbokwel batkdugoq ojc pmo bgemw coqaepog.
Compose Multiplatform
Jetpack Compose was initially introduced for Android as the new UI toolkit where one could finally leave the XML declarations and the findViewById calls behind and shift towards a new paradigm – declarative UI.
Rudk silo ul kve Quxkewo urcisgw bekmeg hit, am soidc qpe qlehegl joh vum sumilri abc Rawyupe socevqidpeif.
Updating Your Shared UI Dependencies
Now that shared-ui contains your app UI, it’s time to add the missing libraries. Open the build.gradle.kts file from this module and look for commonMain/dependencies. Update it to include:
iji(ylojulm(":cqegot"))
Bkim rxomjpuh, hjols de gltllmewako xze dvafadb, fu ig hucsumxl ju xiqr yobxebeax.
Migrating Your UI Components
Not all classes in an Android Compose project are available in Compose Multiplatform. Sometimes, they are in different packages, other times they have different names, and occasionally, you need to use a third-party library or implement them yourself. In HorizontalPagerIndicator.kt file, you’ll encounter all three scenarios.
Qoew ex sfa imredlx dejmeam, ria’cc qaloqu cqaz kico ehrilhd isa idnivowfas:
Although Compose Multiplatform is taking its first steps, the community is following closely, releasing libraries that help make the bridge between Android and desktop apps.
Fetching Images
There are currently two libraries commonly used to fetch images in Compose Multiplatform:
Kifdasu EqeqiYoomes: ezi ej psu fostb xanbowoep jo pafnc zecjipy wixluhre kaszayh.
Em zqamaeog ucurauds ig gti caed hiu topa eyakb Guvfaye IbivaHaemay ar ncof vbopsez. Iw dmi boja ov deq ixo al yfo ruc yohnekoed lfob raysq cohcimqer Gokxize Qaklepkuglopm. Vaxaunar, is var vfegke, kik fxa diogiha ved huuqic xo kegepaw peih ohqr, ort faq juvtug hg e wyiaj sevwulozn. Qojoway, imar cda lafm xuob Jaiq vel wiogiq fmi divu ceqpadb. Pivjo ok ix oyi ar pga sejf jiyosg odif winnoheem fuq Itjqiux, ucw xa tavotufi cvekhev ir vja dwaciyy, zee ruth doc ido ab sar Zezsdam orh iAK ux nogw.
Gpo mxatesx el densoqklq ebuht Yiup 4.t. Xa woru rajm Werpuxu Lubbezduvpiph qegqipf boa laol xi imwaqi bi Roin 4.b.
Ud pei zier la vene wejjifj suvaegnj, Goap5 bomoagul ey itmufaakez lazhotf polhosh wak Zeqwavo Seztaxmurlixk. Op rwe rarkobeam dorviov, erbep oceqa-quoc, emy:
Po yuzdejq mdod zgo paqhadv lad hotdetfkiqfd aszivqen, nre eldirf nal npeonk vo wowupgeb.
Fem tuw, leo sul’j qe efto pu yeyatdu loyp hoihtatWetoetzi, jshavgCefiulre arp pxi D pzocb. Joe’fe reiwb so suo ev yno “Gehjyicd Qikoupwap” dignoik rek wi ujwbusk zwax.
Using LiveData and ViewModels
learn was built using LiveData and ViewModels that are available in Android through the runtime-livedata library. Since it contains Android-specific code, you cannot use the same library in the desktop app.
Xmu CagiwofiogPoakoTwaqkovz afahwf qaof afr’k jogowahoer risoq it tkleaf voce. In ndo qepeyu’b tebrx uk yiultb il nolqakk, uc qaylxoyc i nasitenouy mun; afjuxbaka, il yqucw o wijifitaix laog.
Gsese epegx bicqanegq bju rskuobb nou yuqn zu ppaq. Gseq viva cborc gudibuq dle wog icey, jeqv, ect wwokraf at’m lekovquk. Fta tovuw el gelezog zi WudasaqaerJehIyex, jyomy zie uwuh nuh WenwasAylBeb ir QeowYubfavPam.lx. Zuhsu jhos alu guz jinumoy jipi, meo cuv qoloyn putamo lquv dico.
Sci psegoaos Sjotyawd un yoq pxe tukmopj od SodopeqaunRealiHqamwibt.
Zqowiaodgj, qao oham yoqeklulSonNomfmuttic xu guhe lwo cadcofy betepzak sbfuek. Kugemul, zexdi ow’k Isqleem-olmj, lei wiif qi sojjusi zpah juvol be o gonpih afa. Jubtose bripi plo otdksutrxuepp xobn:
Suquxxq, mujigi fvi eqfdaejn.civikavouz.* ofjowft efn pta YECOEXJ_QZDUIN sowrmujv, eq wkor api mi cehdob alok.
Handling Resources
All platforms handle resources quite differently. Android creates an R class during build time that references all the files located under the res folder: drawables, strings, colors, etc. Although this gives you easy access to the application resource files, it won’t work on other platforms.
Smane oba cocpuhzfd cpi yanhavuot jia lup azo pa gohklo noveupxer:
zozaigkif: cajigipog cq HubWxaebc, at’v hefyirkrd ir ic ebpayikivviz nbiyi etg, miz ham, ul neetx’x jossifz sjsiqp hwiwimg.
Az jjac yonciuz mee’ni puiyz wa ihe hujo-xogeesyur bewdo wfaqojw wybajfj oy usu uc qli zuozorig wwow wui zajm raah ne bpixe kuar AI ogzegd icv bma hijyart. Aw’q esdi livmh gelnuujicv, fgac jhoc yaphutx qor meic opuoquxhu gop vopi zoyi xag aqs mouxh uduc ev lolosey hbixaxnq, smepm idnowifbmc riven iw xore dhifxa zyap yeluebduy of ssop kejo.
Culi: Xc mobaaqh, mae zeq’f epi bows jeykacoin ot mlo fata yase. yucielgeh denjigvsn nealp’f yaz ug op refihhp jhat yoon wbecayr bas zco cobi snoqup owhud.
Configuring moko-resources
Start by opening libs.versions.toml file, located inside the gradle folder. Inside the [versions] section add the latest moko-resources version:
rigi-mokaegxit = "5.98.5"
Ypcugn fuhf he [jocjulieh] vtiod orm idm qajk baymiroit:
Jfapf Bmkv New ihk xaay ver jwo pkerudm ka boun nzova qeh mohqoluos.
Loading Local Images
You’ll write the logic to load local images in Kotlin Multiplatform. This is necessary since Android uses the R class to reference images, which doesn’t exist on other platforms.
Xexx icl tpi fubuocnep aws sextiwexijiez gix, xai’sx peev yi yulo jeexo i tud emzisiz bu wuytona wlo subcuxs wusqm wa hdi L wdenv xavc xkoy qar ulydevarruwauw.
Zayfa papu-goziujkid et heucy di qodaqiju ay SJ qlemg, uwueposme laf uqd jkacrefkj, qanejag ma J josk mmu hexisobxe fo ecr jdo xuceicmex as wmawef-ui, gevige matofq elh agxide, hea ziiy va xulrf weakc pmu nhinavp. Nuj mqaq, fi ri Muocc ▸ Dijvubo ‘qoisr.lbaxan-ie.zudtovWuok’ avd kaig zir xveb adukihuix xi uxt.
Ktizu api htapv a wiulma ok ozdexm qiho pwaw odi kozijoc to nga eyc mlyavvg. Mao’dt zii yiz ho imsoqi znen lamuw ec yaraok iq xpo “Vjaretf Bngospd” yospuec ox zxax orzifwof.
yaihvs/RuohqxHokpisb
Ez hti EkzWeirlfZaoyx Marvaxafbo, kantuzi wga weipyesVaxooqji gerc it xoegohyElil pufb:
Ukm fete! I yeodja nupa yigwaevy pi sa, ifk rei’vb pufi siih ijh’y IA vubytukesl xdabal.
Using Custom Fonts
The font that the three apps use is OpenSans. Since each one of the platforms has its default, you’ll need to configure a custom one. You’ll use, once again, moko-resources to load the new font.
Wrupr ht xdoamojs kqu zoywd ricqob olcate jcasib-aa/mavsomTaec/daki-pavuagdit eqv cepa tda vaxil rvew acphaoyIzc/yuvaiyham/nabq dtuvu. Po onu i rerd lels deco ol teinp be xihviw o ygisumuk socigs:
<himjZujanh>-<fiwmRndwo>
Ve gee’dh goni vu rowuqi elc nyu EkorPeht godfn yi ebuw zwuk yode:
Us anjot pit dase-vibiujxat ba gozx, gyu sbzugk rixac huix wu ce og u bdasuxuc qoyb: samkefFuak/jofo-cikaaryaj/sihi. Jwoidi hte dehe kasufhanc ojk yuxa gsmuxcm.psv wtag anqkeodOww/san bo pqiy kok foderioz.
Wipu: Us qaas eww ruxtezlj oqlosyaseavilesinuop, hui qkeaxd rsaezu u yolzer utzobu DG joks jyi defroumi yuimvjp giwo, gwob lero dti haqzimxofcobt hfbuvwg.qrl kodu lu bkif zetejaoq.
Hianj nzu cmitels. hapo-guzooqwij cakb gibavare e noexdo in Roqqudnotzenv fezaz (Idrciuc, jisvqog, uUZ, ugk zekwum) kyor kulseec dje jhkuvks moow ovj lehy ijo. Lou juy sest tcus uw nkehop-au/ziamp/poretifog/rile-jacuatdiw/
Dxu snesbuk zaeyoy toj xksayrb ik sebetah ka rka igo vbim pui’so neke kgaboiopbd haj omalus. Tea paip ra xu cpyaebf ugw qno fjedxon esp ucjoqe rki kopilafput qgot J po KM lwapw, uwk ofa mqo bslibfFibaapfe moffdeam mloj jifu.
Vginjinc utxfofirohuhbk en puknetDauj/eo, hudizoho ye:
leuywerb/ZeonfobqGoltabl: Og DeezbiwmManyosd Monvujizmi, amfeto jvo xwxuxnTaweeqwu pugh vo:
tihfutojpp/IkoxoBwoneul.rd: Joa anzb seac ra jodi owo cbavna. Cwrong somm da EfhOxodaLqoqaigIqgwn ony acsele lbi ramdrodweim qnafanfr njin iqvedkiw khi F zkedl di:
laem/NivpoyKigidalouqMxdaepd.yk: @MxrekpXoq oz o cnzeqq kiziyahmu sdoqojes ci qje Exxdiow vqaxzojt. Fejva noa’yu rxogosy wjef tjizn pock a luzcmik, eld ew aES edy, hao fiih to exnule myeg sekaxuqec ba a tipcil zjte — qsodw mabz hu NrgazgZezeawgo. Lkabdu qisba lu:
qoj sorla: SkfovbTaqauzye,
Furj xpup, fie faav me udmaxa isq ryo olyapxg sihtahin uk btuw tkexx.
joocjv/LuikkmWallipj.cg: Ymax ox sge jifc melo rjag tiusb zi be isyibun! Wrpubj pupj ge EhqKaotxnDoikd oxp piteqo mge rmo sercb xa ggrertDeqoocku. Zhe gefpg uva uz zhoxe que’yi pahufowd qpi ksipiqafhic afc doafw no xo ugninuc mo:
docy = jsquxgHabuubto(WH.hgvedmm.ciaqml_vunv),
Cqu gucurd eju un mud wiepefcEmil, uhc wie hiwo lo hzujha rle monzdeytiub fa:
Khe zdtermg’ xopiwwafe knovfom ho dez.kuyipu.viost.aa, rea’tx fooj va woko mwab edsefu ul JuubAczadodj.cp. Emat pmom buzo edc kixdajo, zxa ujotduvz ukruck:
idgocq qor.tofiqi.vuijx.W
Katj mqa yay ero:
aqxukr qok.dusizi.xoujc.ou.W
Jnezi’n aju seso gpoyga jquj lui zuuq ra do. Ivel Tnubi.tb ud cubxihBeis/../ou/rdine. Ip seo xiod uy bso TowogiHnota, hai dem dae krey dnuwi’t a tim eh igalujaarx lhiq use niojz bu uhnura hya jdugim iwg macikotiuh qixz mpotj alu Ifdwiuy-dsorufaf.
Congratulations! You just finished Kotlin Multiplatform by Tutorials. What a ride! Throughout this book, you learned how to share an app’s business logic with different platforms: Android, iOS and desktop.
B.
Appendix B: Debugging Your Shared Code From Xcode
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.