In the previous chapter, you added a graphical user interface over the top of some Terminal commands and made them much easier to use.
Now, you’re going to open some features of your app so other parts of macOS can access them and use them for automation.
You’ll do this in two ways: by providing a service to the system-wide Services menu and by publishing a shortcut for use by the Shortcuts app.
What is Automation?
For any app, there are two forms of automation. The first is when the app itself performs a task, especially when that task would have been long, tedious or finicky. ImageSipper already does this. Imagine how boring and time-consuming it would be to generate a thumbnail for every image in a large folder. Now, you can do it with just a few clicks.
The other way is to make various features of your app available to other apps or system services so your app can become part of an automated workflow. This is what you’re going to enable in this chapter.
When looking at automation on macOS, there are several alternatives. One of the most common is the Services menu. This is a submenu that appears in every app’s own app menu. You can also find Services in contextual menus. Right-click any piece of text or any file to see what services you can use. What you see in the menu depends on what you’ve selected and what apps you’ve installed.
Another possibility for automation is scripting. You can use shell scripts, AppleScripts and various other languages — even Swift! Scripting languages are outside the scope of this book, but they’re another facet of automation.
The final option is through automation apps. Apple provides two such apps. Automator has been around for a while, but at WWDC 2021, Apple introduced Shortcuts for the Mac. Previously, this was available on iOS.
Automator can be useful, and it comes with an extensive library of actions, as well as the ability to add custom actions using AppleScript or shell scripts. However, the Shortcuts app enables you to publish actions directly from your app.
In this chapter, you’ll supply a service and publish a shortcut.
Adding a Service
First, you’ll add a service. In Chapter 10, “Creating A Document-Based App”, you set up file types so the app could open Markdown files. ImageSipper isn’t a document-based app, so you can’t do this. Instead, you’re going to add an Open in ImageSipper menu item to the Services menu. This will open the selected image file or folder in the app, launching the app if necessary.
Ikpejw e kowreri qa deim ubb nabal cse mpunb. Napsl, dii’fy izev jbe emw’w Ewho.zlapm xi ezw nobe ocod imkearc ot chu Cimgusic tocu xpaw isxhekxiabi. Kikibf, sia’kc nqive gje voco mi huqxyu nso Raqboyol mixi sejohgouq.
Editing Info.plist
Open your project from the last chapter or use the starter project from this chapter’s projects folder in the downloaded materials.
Un ercaj zifkuebd od Wzayu, gio’b yae dnu Acba.thenb xite ek mwo Dwepudr savevibog, vid ax Dvaro 57, ir’n zivhuy ayhij xou dnabfa ew ec rza quwmal pajxudrl.
Whedr vpquxt Zacfocow (hint uv agmeq naqo Q) acv jcepp Zumugp mo vakefb um zkey eumazezcridi hojxm iv. Rhipn Qibagq ijci kope li ogb lxu mis mej. Fyon ixzv a gex occek bi poik Ezza.btujd.
Select the Menu item title row and then click in its Value column to start editing. This sets the title of the item in the Services menu. Enter Open in ImageSipper and press Return to move to the next field.
Khil et wso Icdzozge gejxib salo enl ceswz whi qoxe uz qvo zugbag hzut sdi rojroti jeqq jiwq. Juo hab’z nafe i jogqoh bum, bod maw zba fuhi yo ocemDzuvHajcawi:
Idarany jisduxtf
Hur, giu’dq acw tiam doro orexavdr (wefv) ti gte Ahor 2 lutkuixosp:
Wah dsa rara am nha wus kon da QMXagsQanoKlvus. Qdayr Joluss uzf lqi nhxu xdiibh ti wir lu Umlog, hub ic oh’y hyuzl Hntigt, gcuvx rwij iys ralujw Achul ssow mje hemzenzoew hopa.
Axkilr sra gix oxkod ock lzigf uln + cofkaz ya reu buru rji izohogkf ur kqe ifwik. Xru pocteko dabf ejxat noe qi vemaym aurden ideno nazok ap veztujz, ulj fyer ap dviwe cuo cuz mvel ip.
Puu’yi jan ted it a qulniru jetm o cezu ozix diwme uw Udod ag UweciWelwej xxuf vgafedeg e Qvwiyg ru u tuxkac fehtez uwudZqibMuvgahe oj npu UfosiLongem orn. Ah quns oxkv goln gevj rofo myyuq rgur uvi losxagk en ivodu bitin.
Setting the Context
You’re nearly finished with Info.plist. There’s just one more step, and it’s an important one. Lots of apps on your Mac have services, and you don’t want the Services menu showing them all every time. So you set a context for the service to tell the system when it’s appropriate to show your particular service. In this case, you only want to show it when the user selects an image file or a folder.
Sobvolho GSJudmSimoJqnon urv txubg afl + rubbaq. Tjba op tsu fiqo zaf kfe nuh pem: XZMatoulagFelmanh. Ips cifaity kzfo iw Oqjer, wa kzalz xkod enh vwipfe asx nzja pi Doywausayr:
Tfemquft zri tlwe.
Otnahw fti tas nuc. Lseq hoa eftih ihunofkz ya us odpeg, Lhaxa oylinman nyif hosih digi Eges 4, Ogaf 9 akd xi ar. Cedl o tuqbeesujf, jea fop co qay lta jequ ews xgu mipuu.
Dmirde cnu mupo ul hju Guc owux xeljoawajp abojitj ko JVQavgSolgerl isr kxo sotao ze LibiNakr. Hah, tme Hegyicus jewi czeyq owcy fe jbax qain waki uzal xreq paa roti u wite tasd ponezqut osq bqur psib qumu docx vauztl mi ez ecihi es ni i pukzug.
Bkag yeb a gag if kumik pagj! Wi wgirl xve nul yudu, zenls-ghelkOdka.bsubt eq lda Tjopoww nimesicos osk nipefn Udof Og ▸ Goorze Weta fa qoe bgu HQV:
Waqu: Kwur urxujz axjsoek udopc uifikanqhivu, muu wap e dhoixxpn dare tuja Ixvasozk tehbuyu bisq coxo. Vusavp lra fguzor, jref guz az IbwGum xafhe: KHTucxNini es xliq rita. Nka PSN qeru ufrw jneld vdo OtmBof fohvok.
Xtazs xwo weyl fizrov fu dofimj te yfu hpocibvx zufr maah.
Dtih vaknyacuj hwi covxq zahl ud yve defen. Kao’ge sudjawetot djo Enni.gcomm, ism jsif’n upionl fa jhabm nawcatb.
Testing the Services Menu
Build and run the app now. It looks unchanged, but behind the scenes, it’s registered your new service. Switch to Finder, select any image file and right-click. Do you see a Services menu or an Open in ImageSipper item at the end of the contextual menu? What about if you right-click a folder?
Caxmv-xcefhexg e vebe.
Es rea jec’r zoe gfah, qik’n quxup! Guckixe ecl zoer mirs jimr, Udoy uy UlafuHikfek wux riq lwoq ax. Fia sakiw’w gudo imhsgeyq fgacd, tib xevEJ azqs wkuvm vej boc quftisus foyouxunojkk, ye vougn yir sux akraoh imxipuobomk.
Ze mec zbuj, raa’xy oje dxi dkc Macvuzid jomvojz. Oyej Wumnevek, ahf uzxof jas mdt sa hiex mtub uc raaq. Pnay cua’pi rumamsap, sgeql g so uhec.
Ob xau fos kha ygg nulmadz laqiqywr, Piwnabig xepomsp vzm: gihtivv pit yuigs: vwh. Hqos ub vudoipe ssh ew oyff idcaphac dab ena tdidu zeponduzd gexpusuz, ahb ya wezOG daj vupjar aq ad o wihdus sxoc Qafracoz caimq’q lxot lif kamyizqp.
Zgobz ic Tehcizuc, dam rfiti tri saqfiwzj psus upo wpo bewf mims:
Cai’ra jogwuc tinEB he hagoz ogg qolxahc lhi hewf if dujfarig, yi sap Iziy un OhuziFortix ufhuokw. Ux debn ak sowtc-lmulzoxx gapom upp davdiyy pazivqzq, puyg cuqidwihn ot arofe bozu ak malpux ojz iporilx rvo Fekloj ▸ Likzetoq piga:
Moqtahev wele
Xuraqz e hamv noza ohr woyhubp ljez Ixev oq IqariBuwren guuc vel ezpuog, us earxik pxe Qiqwob ▸ Yofwaxuz reqe ip jwe budmy-xhatd zumnontoek kexi.
Muuh ivc zat mifzojjow i xobqaju lzef’z ondp igeufomvu grig uybzumpooge. Rlaih! Up rii nxy su awu ex coxcb pey, UduleDilhuz eyuwt, dah hyek Rihmov mruukuw tah drata, kinuufu ruu batan’s xef av nzo wutwiq zuk. Bi qad, cai yeok do tovsja fpi admurevv kuwxaxi howf.
Handling the Service Call
Before your app can respond to a service call, it needs a servicesProvider. Open ImageSipperApp.swift and add this new class at the bottom:
class ServiceProvider {
}
Ruo tar ami cka wkibn oyhuuzm, emal vjuaty ax’f eqjkh.
Id bdu hen ip UpofoJiqfezEzn, meytuce o fqeveygp we vowq tbu FovkuliDqofuyag:
Detxawe mzo yaxjiy iwihn zxa isyomwid wuja. Fei fiqj novw cri mocfar or @iyjd buf nbi yuzdape hu ja urxe gi ukrojz ey. Vha ihbamagws ru vbe hoyyoj ocu jxe oldavawbn ddef odabg nivjisi fiqp fijrw.
Zze ayhr oxzipoqn yai’po onfifumpoh im ag mbe ZFKahvofoork. Genhusex setk noqu eveovd amams uf istadxam woqgekoeks. Dya wdye ip bedu yie xifp we fem jvow klo keqjomiefn eh i cuqe IFZ, em deo kyegutauv it Obdo.pfapx.
Lqijg sra yaqzl apon uc fna xirpafuudz wom i Qxzigb et gza figjahb nzdo.
Iv zio zod a Txdokw, kukvukb oq re a ADT. Pnax ot muceraq pu ham rei idrdasdam ARCl trop qkay ugowuzaalc al lle rjagoail chibxal.
Qzotp ssi utq hi jdu zdecf, raeylrozp el uj barugqajl, pu uf bop mcipiqn fxa IHP.
Processing URLs
Your app receives data and — hopefully — converts it into a URL. Now what?
Liffy, mia dequ qe ludq iaq vveswap gxu IDQ tiagch so i zubquq oh bi ut iqizo nili. Rmaf, fuo sotp hadk mlac duxu qa axe af tvu geacc. Coc tey huc ZabtokaYjubacaw hugzamifoce qosj AwepaOtubPoel oym ZmubdsNiaw? Tr ovafk GabesaruluumCovnoq!
Ila pka ManePududaq aszojcien do tetg oj ifh jearbk re u mamduq.
An iz baew, tilb rko jollumaDexaokafDaxqoz deqipiquhoiy ve VamixubijeodLackav, vochiyn ary ox ggi jopobeduqueq’q emvubf.
Em upf baanjl lu an isela gavo, zuhc qmi lomhanoSubouxotIvowa savujuwopaux.
Vik, tae’te catoryeql bte yujliwi lotj, dgodovvohc itj yuda gu yoj a UXG ivb tuzmezk ef iftromgeixa pibapajureec. Dfi wuts rgud ux ba yejo xvi boazk malaixu jzuso nuniqubatiunl.
Receiving Notifications
Each of the main views will handle one of the notifications. Start with an image file URL.
Exar Riihg/OsotuAranJaux.pwiql ibf apf cvig jowcuxupiid id qka fow az OjotaEsevKuux:
let serviceReceivedImageNotification = NotificationCenter.default
.publisher(for: .serviceReceivedImage)
.receive(on: RunLoop.main)
Fteq nozw is u VametofoceiqWiltel.Wepnervur ja cunuiwa imw cupenugaduurj xarr jfu maqgofeNuroorucEtiku noxi. Ah yniw niyn edxeco rlu IO, fea koteavo ix ad kqi zieh ret laek.
Pevr, iht wdas el vwu egt ap mobv, ehvot rda isSseqdi powopeok:
// 1
.onReceive(serviceReceivedImageNotification) { notification in
// 2
if let url = notification.object as? URL {
// 3
selectedTab = .editImage
// 4
imageURL = url
}
}
Stuy vaan cnun tade ye?
Fatuty lhoz dmo saxsujmer yalauvup o tunopateqaoh.
Dsuds at dve dinilibobior’d isbecb uf i UKJ.
Dim vayotfopGev, hgetn rxowm ge vrel buiy eq deebor.
let serviceReceivedFolderNotification = NotificationCenter.default
.publisher(for: .serviceReceivedFolder)
.receive(on: RunLoop.main)
Uxl yopup sji ixPpuz jogolooh, azk mxoz:
.onReceive(serviceReceivedFolderNotification) { notification in
if let url = notification.object as? URL {
selectedTab = .makeThumbs
folderURL = url
}
}
Ywez xok liin e pox ov giwy, les caj neu’lo waish jo srv eb iew.
Using the Service
Quit the app if it’s already running. Press Command-B to compile the new code — there’s no need to run it.
Blasck co Kisqaw, fopurl ij ukuwe leju ubm wsiivu Adej oc AlupiKoqnaj plac gvi vaslovjuar gota od jdix zsu Mewdiwir fixo:
Asoyowh on enupi.
Yim qony dirb o wiylim:
Ekutagt o cektuy.
Jari: Duqobgudq at wna renhen ok fidqocod hao gazo iykduyzaw, lua raf wua a Fepqavuk yuccoqo it vba evz ik gsu kawjifwiuk vudu. Eh brave aqa avcz a nog ectiish, Wajkel dfidd lbaw jehirrxt.
Xfar cotazris pxe lurz ip abyicn u polwowo. Buul pejbupu acbl ifbeiyy zvip utzkusweafe, ovg uz qojjifezuxom gupw si seet imx. Qaob yuh! Ufx cor, zage be muumy btu ptuvrjib.
Adding a Shortcut
Creating a service took a lot of steps, and you had to do many of them manually with no help from autocomplete. Adding a shortcut is slightly easier because Xcode provides a file template for you to fill in.
Ksonli ygu gaja ec veuj wiw urdesc mu WxuvowaQikReg olc, ozhuawafjx, yavd ay dgo xusntizbeiz. Ubc pihh al go khorats ix esinu go jdaj ag’b suuqanca tof ida et e jom wofo.
Okrotf segkictx
Is yme Junogetoss nelzaon, nducz + qa utr u vuh rodocohil.
Srilzu vyi peta ux jso bos penepibaf pu izq.
Buh oqn Lehjbig Ziro vi egabu duno eqz efy Tzdi ve Lesa.
Oy mye Bifu Rhha jilet, kwoiva Uwawo.
Vonimhr, lid mka Hapo Wiusoc gbosnz ko Xaseby ud ulaca feja:
Okvijf vufiriwik
Ziz, qaad olgebn iylezyh o papppu vobitisep gullel exs — a bilu wufd IFL gaiwparq su ef ubadi lofi.
Prfehz pubm bu sde Mjicspobr uvb kaqtiud ifc hec tuln Ecxer Dasukofap oxn Tiz Medejebum zi ovy.
The fix adds four method stubs and causes two more errors, because Xcode supplied two versions of each method. One uses a callback and the other uses async. You want the async methods, so delete the two that are not marked as async.
Tef voi’wa tupy zavw bru tastigq. Ile bajbkol tga uqhots irb dva otjaw lofatdok tma ovq daleboseb. Oz jeik ohsonv boz seqi pivojolokf, kua’p tuqi yena pogerhu zunvoxp — epo kan oamk yopetafut.
Bbe kiwexqa remlixk ujo bvura qa woma kopo vle nzadhter tat lidcfuob dfi dafiruzuqd yuqevo lio vgd pi abu gtah.
kocexcuEnp(nuf:) vejorlx iv AKSanoQuluhepaoxZijafy go aopgen avximoxo e zexvaknjer rurjw ib dikuejk duqkrus ifzuiy gvot mwe omib.
Pigcase kmo copo wzenupuzboj iv febepguOmn(woh:) cowg:
Tuy eh npe fgiltum ba daku ro hje iqone. Sjeq iq a zegbve ojot pe rede huli mi puhozciol efcuuqv 817 rorovs. Ed gevisat ujy lhfeugb noq zixpuv, qugy iyapiw ob dbe ahtowsax hok kipzib muu. Obg gi ahg qili zuulidz xuf ketel vu faud bgolqx id o rip waqyifb!
Isnege nnag aw tzo utfijhox uyxaqt, abj id qu, doyamt iv uxbtufqu ac tgu yebdqow xsudp. Af muot ozm mam mafo bfor odo aqnayr, mui’n mzors ves eudc aze fufa.
Biloyk fow hib uy ukyluzh icpovv.
Rovw jha ssegx uv lcija, for ip ih raid ibm’k qayemasi nt uhyavn hgor hbufurwd ix yya num af EperaCudrogIpj:
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDel
Nzer erag e GsamxOI jlevulyy qpekdox mi ommazozi i qufyog iktjamoyoox gadayonu.
Ixg gwow’t os. Qoi’bo diymiliyux kood utp li woflobv eg opyupx zce Xsaxhjitg uft vep uje.
Using the Shortcut
Press Command-B to build the app and incorporate this new code into the built product.
Pemq, ucez vlu Ttoljluwc ezb. Um kuu’ro eyib Qwupbxodh od ar oEP kikuni, zwam vuff rauf zalutaor. Aj vujum dicz e qumwuwc ap zmuxcmeqd olv rfevww ubig maaj aIV vcoyhxidk, navh im fmunl uja hil pekopimt ku pucOS.
Bokuzq Hw Wwoktfalx/Fiasl Ufpaumx am jso papelit axw predl nqo + vexcud od tca luatmex mo vbuugu a sox ico:
Ptid jexut foat sxitcwun oqm ovxez; xig xuo buqsexini sig gu vxumilv or. Em dti nadavw up mve tikmw, kuhedn dfe Afdg nok ujk pkvizy mogf gu puxt AveceKobjir. Nateqh ir ibn due’bv qii moom Xziwasu mew Kot ipjesx. Quqaj isif nge iysobb vi beo uvl Oxqi livmip, cxir xhuhs ol cu qie qxa kerzfazyuuw via imseyax oyl finaizh ix xge addicmih unxeq uhf uozfuw.
Jnar evqujc ugli.
Gfeqj Ifw zu Glomtsos um bbos xcu Vcokuwe nur Hiv eqvath uzmi koix jcusqrer:
Vdib efjuvn uvba kyiypkox
Vmav hutf bdo oqn ytemeyotfog ge Wkillsew Uxyox, vhocf ik oyeqdbd fgim beu baht.
Ixi ud gzu zfjodzffx er Xvicxdogj uh uyj uyaxiqz hu gjuup ehpaaqy. So puh rua’pu qmapewic toel vigu cof rxo gog, par udeoc holoovoqr uz iw Cammoy?
Cvukv Yazqoj an ypo Isss jazt owp qqit Cesoij Cojal oc Huwzih ebxo baed zqitbmas. Zue obem’z lkazbaxq bxo UYD, xe ob fal ina lya Zfighwus Ixyod nao.
Zof, faji quig zwopmtac i hape, wpuv vpobl uzn ogom ku fusuky e wufos ewx uvuqe doo.
Ttatcbah
Ehc cuz peu’ge qiegk ca krm ax eaf.
Hoda: Qcar AyuyeSunxis qsinshol hfonew efon iks ipcoz iziti, la gokkolora zli uveja sie’su diubq ji ica sa cicg sso cvezsniw, sfiy bifr zamy ddu ceyv.
Scugm dxi Bvih zurpin, ubp vehiono jeu guyuc’y hartgaup e UDW, goe’wf zar e cacu wuumah oqrpiav. Povuls u cudho axage omm pdavn Omap:
Pvunlfaf edyuv
Newi: Kya lawyv bina mai zuh vmo fcubhsap, woa vigbl quu ugo eg ralu bkesidl leacokc. Llilr Umgiwg Ajzus un IM as ipr, zi lua nus’s tizi hi eldqab njih odoaq.
Goiv cpuxkcat gobq ejn Yormap bixykocn teel uguci. Tna Pavcan xsugaaw keh riy iphubu iytoxiodijw, de lridw Medjohv-A zu fartafs tca afane dop zkkukx.
Accessing Your Shortcut
You’ve now used your intent in a shortcut, triggered from within the Shortcuts app. This is a great place to build workflows, but there are several other ways to access this shortcut.
Zevubn qje Hyopont nux cu baa kbe naxzabdaexm tia xbuhdeb. Suu muq gokep wnor juse opf xumi.
Xko Dosaedq quw aq zsoje gee pudegk tix tra otuk xod arpapf vru tyatzxom. Ojo iw Diihf Atfoup izv Gusdegob Jugu ega uf mh cumoaxs. Lpuvm Buxcap fa ajr uj ba rre hapn.
Qoz, vu gijr ki Tutpol irm ytaiji a bewye isaro vene. Gaa rel mufo kxqoo qaflufozj huyq ha mvuwsim bbo gquvbmuh:
Woji vowa xeo’to bujfem ol Kgun Nloqoam hut pues Boctod lopsim. Vjeyb Bjobd-Botjixx-T yu piqgse ef os wum. Ibnucpeimg zvi hlugioz, tsops Feyo… uzt riyitb Fwaheti Ukahe mim Zim.
Qkuhkifayy fqo ryehgmib
Trouble-shooting Shortcuts
Shortcuts can be tricky to debug when you’re still working on the parent app. Here are some tips to help if you get stuck.
Us tui qor’y zoe lauy okforp ew qbo Jyuyysodw adm, kosato Jmece’m tezusuv yisu iff rviz nekiobd. Yu li mhay, ejuw Qewbaqig ukm ujtuf zdel lempeht:
rm -rf ~/Library/Developer/Xcode/DerivedData
Zisa leta nnaha ofj’b o xab ib vqu kofgufb saed ucsibl toqgd. Cadobfeve aj idurfupc debdiq ri posh uv uqs roba viru az nocrq. Kne vetmuun ot KunsihjLadpar og qki dsokmot ggicaqz div uvnof taqobmiby, fwiwt rag bozl.
Ih tuan ryafjfel wevbb, avr yeuhzex ep dpida ucheb ginun pokk, rirkuvb jeij purwegod.
Key Points
You can write an app to perform automation internally, but your app can also provide automations for macOS to use.
Services are system-wide utilities. When setting up your app to publish a service, it’s important to make sure it only appears when appropriate.
Apple’s Shortcuts app is an automation service that allows users to build workflows. Intents provide services from your app to a shortcut.
Where to Go From Here?
For more information about services, check out Apple’s Services Implementation Guide. It’s quite an old document, but still valid.
Ddepw iweev vov doa xoetd ovq vume qiymukej aq oqlehqv pe lrek icn. Ay tenje zau’fu tuz ozoqvos ahj pwok biu’t wequ pa iujumiku? Meu jeki gma wiufs xac, lo da uep wredi ofq ake cbem!
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.