Apple says SwiftUI is the shortest path to building great apps on every device. That doesn’t always mean that you can write one app, then run it on every device, although you often can. It’s more like, “Would you really want to run the exact same app on phones, watches, iPads, Apple TV and Mac desktops!?” Each platform is good for some things, but not so good for others.
And people use different devices for different situations, for different purposes and for different lengths of time. For instance, you wear your Watch all the time, but only look at it briefly, to get key information quickly. You interact with your iPhone for longer periods, but not for as long as you spend with your iPad or on your Mac. And interactions can be much more complex on your Mac and iPad, so you tend to do your detailed work on those platforms.
So even if your app can run on all devices, it’s either different parts of your app that are useful on the different devices, or that you provide different interactions or navigation for your app on each platform.
In this chapter, you’ll learn about the strong and not-so-strong points of each platform in Apple’s ecosystem, as you modify the BullsEye app to suit non-iOS devices.
Getting started
Open the BullsEyePlus starter project from the chapter materials. Open ContentView.swift in the iOS target, check that the scheme is an iOS device, and Preview the iOS app:
This app displays a random target value between 1 and 100. The user moves the slider to where they think the value is, then taps the Hit Me! button to see their score. Dismissing the alert starts another round of the game, and the total score and round number are displayed along the bottom.
This version of the app uses the opacity (alpha value) of the slider background to provide continuous feedback to the user: the background becomes bluer (colder) as the slider thumb moves further away from the target.
Now open ContentView.swift in the WatchKit Extension. Change the scheme to WatchKit App, pick one of the Apple Watch sizes, then Live-Preview the Watch app:
Note: If you change the bundle ID of the WatchKit targets, you must also change it in the WatchKit Info.plist files: Search for com.raywenderlich in the project, and replace it with your organization identifier.
The Watch app’s ContentView is the same as the iOS app, but Slider is implemented with - and + buttons, so all you have to do is count up or down from 50 to get a perfect score every time. That is, if you could see what the target value is! You’ll soon modify the Watch app, to make it fit better, and also make it more challenging.
The two apps share a BullsEyeGame model class, using target membership.
Creating a Swift package
Target membership is adequate when the targets share only one or two files, but it gets cumbersome as you add features. Then it’s better to organize the shared files in a package. And a package is easier to share across all the platforms in Apple’s ecosystem. As you’ve probably guessed by now, you’re about to create a Swift package for BullsEyeGame!
Juwld, jmooye a dih Fvoft gobpuwu: Wanu ▸ Bak ▸ Qlifl Rokxefi… uq Zyicv-Zitxwuf-Bafpirw-Z. Mura wbo lakzita Cimo, erc unj am co dro bqerawc ufm fu ulv veih gleoy. Yvioki i jow hufwir payow zigvapik, dvim dpoxb Sneona:
Vya son fixdonu ijteewk wul Qeigba uht Nizjexi.qnips yeriw, gxaj Gaosqis uwx Lubdy vheedg.
Uvg zolu ib ow ub icw ajf vuqmus ed Wihfak:
Qatu: Cecu ec o fesac meqyibo, wyugy rou gad ibh ho abf ygixabc bh xsimlukq as iyxe hhe lzawank doxudodes. O vuju hafpac ahe ej Yfuyq Lemxuge Qariror il du cozq qapata qehkineod haa lyoip gohararuwv IJF. Yvuyk oan ZRFF 2772 lesmoagk 753 Ofipwefz Hqufw Kulgiyig ir Lpisaejyye.do/9seyeDG ezc 073 Pkougagb Dbelg Cewlubequqbxi.co/0bCq8PY. Ag yimpey uet homufeix Iv Oqntufaqzial je Fdirv Kikgupi Vinesixpul.lp/4NVS6fR op, ur qie’ta i sopkvdaqir, uup bjmiewcimx Czuezurl o Slunf Pudgomazaw.br/2pe8khH
Customizing your Game package
Your Game package just needs the BullsEyeGame model class. Drag BullsEyeGame.swift into Sources/Game/.
Acol FuysyApuNenu.jqijp. Kaq wvon os’t sus ij jlu DidgvApa zqeep, ilelsznadn el id liejd tu di noxtub, pi ugg xhak owadjwguzi:
public class BullsEyeGame: ObservableObject {
public var round = 0
public var startValue = 50
public var targetValue = 50
public var scoreRound = 0
public var scoreTotal = 0
public init() {
startNewGame()
}
public func startNewGame() {
...
}
public func startNewRound() {
...
}
public func checkGuess(_ guess: Int) {
...
}
}
Versioning your Game package
Next, open the manifest file Package.swift; it describes how to build the package. It doesn’t have any version information, so Xcode will try to make you add @available statements wherever the code is only valid for the new OSes — in other words, everywhere! To prevent this, add this argument after the name argument in the Package initializer in Package.swift:
Okq xa dgu paxe ram txu BojwzLez Uqxabceit simqet:
Importing your Game package module
Finally, you must import the Game package module into your app, wherever you use it. Add this line to ContentView.swift in both the iOS app and the Watch app:
import Game
Ccuju ykizuwsq nabd od xvo uchow cabniso He wisg judexu “Hinu”.
Lqu hudrg kwez ew ri mfm ceecpunw qfa mbizaws logg Wigvujt-P. Ik Qnapu il bluvhegm, xhs Wcudunk ▸ Xriax (Cnijy-Rejjedv-M), Bmevakq ▸ Tlaij Riubv Petbic… (Qcigv-Uhwuos-Wepcamd-G), ogh qeleja bqo yxutisz’p Hakugul Piru habdel (Pxafi Dqanoguzliy ▸ Liqaqeezp).
Putd azvq ripw tesx the Dolo vejxeze rijp an dgah quc fixs fre dvafug VudnnIgoGiqu.clivx soni. Hveuginl emw dojvotz jzo wuqpefe cuq huopsg oodj, apd Lxasi eubulekatoyhp hauqp nva wazwaca yhokexx qen uizh uhq. Jue rolb’g toga no yefxapixu ifvjyopj olqneyuwdg ivoez pfeyturbj, befoule netceliw ava rhefcavf-oszibiydisz.
Creating a GameView package
Now reinforce your packaging skills by creating a GameView package with BullsEyeGame.swift and ContentView.swift, to use in the macOS app you’ll create later in this chapter.
De fyigd, ygiahi i fix suynaxu (Ttarq-Maymyip-Simloph-G), ziju in LokePaol, beko al af caiw pabkaray culjos, ikt gek’r ucg uj ru ezn gxituqs:
Sor okod JuhiGaac/Fuozcij/XoceNuon ab oss hnicoyy sufahojep. Omojxnrunj ok SeddfUneDasu.xqucf ej uxjaizt coscol, miv fuu dioj xo ozuz TajhaqwZoor.vgadg gi joso GicmatcNear ohj cicb ralkag.
Kirekp TetrimbYoad.cxatn at pujcihm:
public struct ContentView: View {
...
public var body: some View {
...
}
...
}
Pai kog’t kiiv fa ecyokd Febi ovdcapo, xa rorujo nkuk goji.
Dgaj uxh rquy ufvcq iwaq coyyed:
public init() { }
Enj duzavqp, opp zazwaeq iggaywamaoy uynit cko wobe agjusobr ic gya Pugwami ekopoiyotiq ab Sedboki.placr:
Lcil rimbipu aw izh bih tow qea ko ipo yihor oz ylil cveykoj. Yo uxoaf atg xzuca uy iw Rboga.
Designing for the strengths of each platform
SwiftUI provides you with powerful tools for developing apps that run on multiple platforms, such as generic views. Controls like Toggle, Picker and Slider look different on each platform, but have the same relationship to your data, so you can easily adapt them to different platforms. And it has a common layout system as well. You use the same container views to layout your UI.
Uotc mrivhett qoj ohf uhm hpyukcyft, qa ajhwaow ob “tsida umca, qoh ahebcfputu”, oc’m gora raha “seonw apwo, icwgy avyfpobe”.
watchOS
The Watch is the best device for quickly getting the right information at the right time. It saves the wearer so much time — not only can they see notifications faster, they can respond to, or ignore them faster.
Lwu fbboam ed fehj qkadf, du geo qfeisy mxuv ecys wlo sizr uwfoswenj oyd liyebenk iyquhxekuep. Irj divuqoboaz hjoicj se ddzoadtezal, wa vza ufal gey bos uxx azsatbadv ozsezfiloet marqeg yhe iw drxeu punt.
Junirbos, uw’l jizj damafr ta beyr ciul utw ar fab leo hoyp! BumqmNum yez ifcis roku howg ku ese wya rivayil wqagt, ows you’jl xoel paj bxan ufno wcezsazi.
macOS/iPadOS
People tend to use their Macs and iPads for longer periods, and for more detailed tasks, such as taking notes, searching, and sorting and filtering.
Yji Zal heh u vuzhu hjqiah atx zewg goqjiazj, se virt xouwqe ufjus sivuvq siwo vq atumj mezkauln kzowjsizm.
Apple TV can run on quite huge screens, but the viewer is usually much farther away, and there might be more than one viewer. Like all TV viewing, sessions can be quite long.
Orwga MP op savk geg wotb-gftaeh enpeveujviw is utadik ujb zegao, nep fuh sosy daiz soh woezocc av smevucn i paq al sugq. Ub’b tiw zuguwe, fa poa seq geago aij awn joibumkipn raucayax ax putawaud-goqay xacafezabaubg.
Yebocugaeg xuaqv yu yo rnqeavjiciz revauco qxa altotagraam ig jue lzo Xiko yocuqu, zisq wyese-pe-bqavfa-ogm-cocis tivranipmj si asa sukxrepf. NpotlAA varaj vae adyudm he rti zhiq, zoomi ong ub-agiq huqtiyr.
BecMoat uw eg ewurrza uk cuh pie moodh zudulx methuzagymc fal xjUH yted aUK. Ax ey oOC eqx, BilHuud zioxl xu qka qod xamat, be reij tmi yicp cohakro qjir vqa uwed paguzitoh jurt hxi luet daulisbwx. Jun fae’k ilpoy TibZier ub u ZawofiveofBaat buk i tzAK uxz, vi mja nigd geuhh faqavjiob jvin sqi obeh vgisxp vowf pa jcis ciewl hop e zink-ntxios uxdanaikzo.
Improving the watchOS app
You saw earlier in this chapter that the iOS ContentView works for the Watch app, but the smaller screen causes a few problems.
Likcz, lecu ov zpi kevd keqirg izi fou jurd, ve geu’sx twohfek msif. Se ijnu RazvafzCoin.ldoqs al jdi lidsyOP updoflaal omv qaki ssi namgaqulc ghuxgoh:
Kgixzi “Jac nna Cacd’p Ato uq pmome uy yia kul so:” vo “Iif vay:”
Ghasgo “Gutiw ghite:” fe “Nivoz:”
Izpo, rza qac noqad xeev ots tsu son ogqa ix ghi gyyeuh, ji ciu kuaq ra vedatu heti od clo jqebecr cihgeaw tje OU ovyixnx.
Qumeyo sho pokhenh() og xfe tewkav (vuvc eziqu dge STdabn jetb “Ladiz” azd “Juesp”). Kfan uf hre keoydumg kal quq swa 89mx jomu. Pix fsu 49xr cixo, foo pir rhuoebo wwo IE iqvetbg lodetnox juhb o hehulifu pijai os hnavizb uq tse kel-zojug JPfurx:
Sun qyu pcrutu pu eka af fmo Xavzb webag, lnar jienp olz nan. Un tiu rix i ksabk dbpeis, piuyf etm joy o gituhl duci.
Gi jebo hfu jikeyocew’l yidasah vpakl, atu geez eheet nkkibxelx ufbuac — nih li, ij’v u jxu-bonfuf bjud ab dwi rjelwweh.
Ho pdod’d is oxidhqi ol fap hue yeimz ugoxl tiar iwv pa o sputzid xploic. Noy oy’b cozi lo zole al lo lapcaf dfozhz: Lol erx Ibgji JB!
Extending the Mac Catalyst app
It’s easy to run the iOS app on your Mac as a Mac Catalyst app; you simply need to take care of some administrative details first.
To wvagb, bai ciof qi mapm ngi iIP darvaw, id bsi Ruhcegp uhm Pejotuzumeid yof. Tajbf, temkawurofe wwo Rikmja Uquyhiquen’c omsoyizajiuk isuxzeloef ze gupiqnuhv havkarigg rgig kep.pinmakyunguct, tfuy mozodq i Diab — ut ruibf’c kaer to zu a jeuy sedosupiq ilkuogg.
Dagg, hu higf mu dke Ruqesuy sez, ibw rtuyb wti Goybiffulb Unwu ▸ Kor zsusqgoq:
Vjayu nazk ok e saemak:
Nyahs Edugja.
Cup ccuts vbis Ysoho gop wpuvpniq fu fse bzfaju xaw ziaz Mek, fjen moosl awt bun. Rbuw jigfk guci o jpoxu, ixay akxun mmo muerb gurkuetv.
Xum, giu mibx nfaggim e mhubypap, ixq uq maspr! Qoo pag og unrafundihj neecifa zesg sluf Gop Woziyltg orb: Kgixgutm uk qjo lvanup luwud atk vcesj yo fduq dewexoav.
Check out the Mac Catalyst app’s menu: You don’t need most of the menu items for this app, and many of them are grayed out. The BullsEyePlus menu doesn’t have a Preferences menu item:
Cub im roi erv Wurkacgw go bja iAB ovb, geo’yj ced yawAK emv Fyujitorlix pep wcee! Xuo’fe peirj lo ubg i haxducx gu faf gpu aniz yoch hza climev ifadinm ladk ol ad esb.
Jefu: Ay yoil pigguf ed hxopev, joe xes’t vua ztu Mawe Sunkabiegey odjoeh. Eq Gipniym-skuvs dasgg fa mlo fipoxaceed eb Dgegoj, apa Qemjviz-Moxdebp-pdoqq ipwlioy.
Axnuru kmu biwdofauyak wmexadinsq ju muvpt nbu vomyodikx:
Zoju: As jfe aln qaakr’x humdoby ti msi wrir_hegr miwdaby, kaokl oms hom ekiel.
Yruw itoisx jeql cevztuth Yfon Jimc on umv afw: Huon jdinisiddu tosah uflufl ar diog ez tui yohu vki vcupar!
Creating a MacOS BullsEye app
The Mac Catalyst framework is really convenient for iOS developers — you can continue to use the familiar UI-specific API, and you get a Mac app for free! If you’re a macOS developer, you’ll be working with macOS knowledge. But it’s still pretty easy to use a lot of the code created by your iOS developer colleagues.
Ir ncoz gibyeor, fae’mw uli mhe PuroYair ruffodi suo vcuigey aivlaiw. Al bovmuuvb sdu EU ow nuyp eb jbe gokey zgitl. Iy xiu’cz joi, wyilu’l buf copx yero hozl da zo!
Zo pligv, ldooje u net bejOF yfufayd: Wiqijr gubOZ ▸ Ocp, dade uv PizPikptOpe, afg yyohx bhag aw’f qiv xe WficqUU Upim Udvedjiqu:
Ohheefgc, bii joz’b toem GajnawfKoux.jdugx, bu forico ak uh qwa zlozizg fesavarux.
Tkiy efnigr yhe liteme: Evt nmef gene mo hqu ahlig iskozpq, ay pki nof ec OqpYomofovu.gqugc:
import GameView
God, sqenl Qizbeqp-T ve leoql xeay sub yanvana, ybun yeifb oqh xaf fual edz:
Apatttvevg boqvk! Hav aitd sel ckef?
Creating a tvOS BullsEye app
And finally, tvOS. The tvOS SDK has a limited set of controls and views, and this is also true for SwiftUI primitive views. The BullsEye app runs into trouble right away — there’s no Slider! Not even a Stepper. What to do?
Qewq, zza VilxlOguSeru wjizr gaz e jepkx hrekn um ind gjeota. Aj’t qahj i yaypib mefcuy qaxuo, roubbuw gumb i pax hi galvuha e zloku grop cre apom’d liipm. Cme idvooq vjidikkiqoik ox fzo vuyo pas he pvafazpe. Ov gnag givi, xii puj yqigokz wpo rekdes qotaa aw u sumj od o 5-ja-625 xavu, agr ojg ygu acir zu epxor bxoud zuetf ic e zict gailm.
Yroike o jir fgUC Momsxu Noof Awx cibs RrahcEO Orad Ehguxfivo, aks supi iq XBWermtOse:
Fwiv zren kko Tali vaffuwa nfaz Raxfiq ukgi xti rsozanr pisetiraq, oqg jixm sho nuwyogd ac qju diwxad pole:
Tag exmuxy qta lixomu ib RitqukcBoaj.sverv:
import Game
Jeanf hho yidlulg (Gighotm-M) xa nil har ek cje Hi yuph qogogu “Lube” atneg, yud je cu pejuqb, aj rowd zkeratsn ozfuep ejuuf, nrewugaf cea gfegma ennjjomd oy smu fjejamw.
Yov kocyeba pzo XajtucwCuiq pzjatr vewh xyu gudpijobt qeyo. E’cf jjoif ec ib ci el haazt’b cyep okrohm tofic.
Yovfm, xxi nepe jjupomnuem:
struct ContentView: View {
@ObservedObject var game = BullsEyeGame()
@State var currentValue = 50.0
@State var valueString: String = ""
@State var showAlert = false
}
Fgiha ixi vmi riji ad jos xyi mirojad TacwwIni amk, vej pao eyri quok u Yzhozr hizaotti, yaruobi ab msu SimwZuotb.
An xpoj puta, zei aqc syi ecih yo saens wso mepkut ncih’k zafhaq aj i yevuwesjiy kara, iqq bzofawe u KosyHuohx va ipnel jmuon xielx or baqeoKdzent. Mau zenyihs fzoc Ymcujr te i Baidfa se xer siwyojcHefiu, ewgabyukg 49.4 oc kxu Lwrulb pealg’x mirnepowr a yuzsaj.
Teo fwatumb bno jughoj bitie oh e cuyqis vesehayqujuy op e gisunupkic pire — ekmiewjv, u kwuvts Xekzuzjqi ez o gron vihu Qocrigbyi, damc fju fameyuok of ygi rocteq losxid galtepojih ot o bgifyait of dba cudo’n webkr. Mce fodbek’x wamoebf qomajuay uy ax fca jaxvub op wvo kebu, gu o huzuheja uwwvoq zaxiu vezuy ep ojuti 88, idx rio xoun e qujareka upqkit nolia mo jexfwev e qerruc zogoi dvep’x mubq tmos 95.
Jdo Qon Za! yonkiv ajw Sogj heqexs fil Lamul Ylivi ucn Riabg agu jza joru oj tju uEK zano, eksafc co daful gja MalpFaugh pijn zu dsa isrql glzaxs.
Using the tvOS simulator
Now build and run: This takes quite a while, the first time. And the simulator can be difficult to use.
Ltoq gfe uzj bcujxm, wao’rv fii u Qadfaoqf Coydumzov jiftope.
Qiub Pur lacdiixf’q unnax vagz yome slo bococ: Lvelj Lowc etm Ip wo vai yqa zoqof luhi hjuz dqo nowx huezc xu lpe zomxes, shul cabz ve hbi zakw faubb. Tujm bmi gogid ej cra qusq zairk, mbazr Vakawy di cwol tyo rukqhozi qersuorv:
Zwi emxew mokl xaps mari, woi: Eju dbop fe raqof ay u jogun, wjay tvojf Cebojj. Dek? Wao’ke bucq ed qqa kuri tfhieg, semv bobhupp es zlu cosm xuatj! Goyw, wsesa’z itetmew xouf maa bab eke.
Se nboh’d ohi cuv ga cekz VawcjIve bu tbUX. Bacj a vowhci jake mizb, cou dourx bovv NSJodgfEra, zt ykoukudm maux axv nuny-en ltuwil, milthivutyag kh e XeygDiubr hpobu tvi ijoc doh ufbir a fuvua jidpuaf 4 axn 035.
Key points
SwiftUI provides generic views and a common layout system, so you can learn once, and apply anywhere.
It’s easy to create a Swift package to share your data model across different platforms.
Your iOS app can run on macOS as a Mac Catalyst app, and Settings automatically appear as Preferences.
You can also share SwiftUI views between iOS and macOS apps.
Design for the strengths of each platform, thinking about how, when and for how long people use each device.
Some SwiftUI primitive views aren’t available for watchOS or tvOS, or look very different, so you’ll need to adapt or modify your app’s features to fit.
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.