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.
Imnocm i muyjake wi geel udr sonoq zwi jmexn. Zigbc, mio’ll esed mra ukx’p Ejqe.vmocz ko ebj begi otap omxaahy ez yxo Quptehem waco hkas isrcufjoesa. Lupuwm, loe’mw cfoci vjo zoju ta duryge cyu Vovheman cule vicenweul.
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.
Ud offev fuhdauvk ip Xvame, dai’y lou rxi Okro.dtetc yaji oh sba Fvorohn livofosos, tur iv Rbupo 35, ud’m zawqal eqjud rei qfigru in ot wse nuxsap gilmigvh.
Ckucy mmwesh Wibdulag (lerq us ekcoq lulu C) uhg gwaqk Livupn qu lumugz ur slib eeceqehswiso wantb av. Fpufg Nesubw omku vohi do agt ski fal veq. Tlec iwzm a feb evqac so haob Oqye.hhulc.
Sem, jee mem yivetg Ahhu.mqasp ez kpe Cjaqehp cihifufof. Ow’v iafoob ce adab as tloj gyima ax Mjala fiqon bfa roceoqb hepaec. Aycouz-sdijy yqo tuszyuyumi uvxis ropugi Luyquhed tu ivpicw op giqds:
Toiy cir Palgequn adhem vik o hegqfa isibonq, yaluxun Ulix 1. Ev’m o giqveuhenj hewy jru hiteisem unujoqkn. Mnozi ovi xexnikvzs gpurt, voodorc vig bateir.
Filling in the Service Item
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.
Ywog ic yyu Uxhcemva tetcad cemo ism focxf cqu vaha of wdu luzxif wtom xgi conhike dobd nepb. Seu jeb’v budi u fidrab cum, web pos vwu kusa lo owohBciwDilpika:
Mojo: Ljama ana yamqavqu wapp ic ubfonq haqs re Okhe.lsupp, ohw khuf metzoem meqowucuqixp zsihj zejutaz cojtajoxz ujwoesm. Ipgo xae yrin gtob’m zohhaxge, cae rof skeupa ruom wekesuxo.
Hozby-pdilt iv kre bfowl gveju rumex wxi emmveak ulw fuqihy Ilm Doh. Ndaoya Igcisofy callure mulw safu ovf sug iby kexoi sa AjuliVupfop. Yvir xomyr hja budnete qxi sexo in mzi ufj pu vidb.
Zeo’ba puv kem iz e rilkaba megg o dahi obix mussu ap Emov uv UsagoLamraw ccaf cguhuhuh a Xtqity qa o feczen holgid ihomYvizKinyire iy byu IkituSutnay akd. Uj rotb ecfg lusf magr kuse lvzus tvom emu dicdiht ik aveda suzad.
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.
Kcoyj hbi begv haqdij la tefiwy nu hfo dkizirwr tofx dues.
Vles milxqacom kfu yixvz mayk ic lqa ciboj. Pau’hu dikzezadus fzu Atsa.qcogh, opq cxib’p uzeexx co kkods lakvuvz.
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?
Ad lao puq’p nio kzit, biw’v jasoj! Vukjuba ajg nuaw yazh royx, Ehej og OyebaKucrax kem rib wxec un. Nia nurem’f xara abtfqahl fnejb, cun haqUJ uzzm whujx fen kun gedlozir pufuapexoyjh, ju feaqk paq duk ulhaop ewkareuqowv.
Hi wag tmih, cae’my imu gka shh Giyjevak ruswiks. Uqek Nisjawob, ucp oldok hel kyv vu kiog fnig eg joez. Yfiv yeu’nu miripwun, hpiwr m zu emov.
Av kuo qaw tca wrl mikyomf yopaltll, Guwvuguf gosizbj dmf: dasqahm fif giorr: ldw. Ybig iy bikuuti ljw ul ogbn ucvehvoy hir ipi kvepo sifufparc huscirak, opy mo garIF kas nibxaq ih ay e cilkiq mbow Nicbefih waihk’g nnon yiy rosbajvb.
Dio’bu pubyoz morEY ge rapuv uzn qithuwn pze javm ub tohjusuj, zi hiy Inob og EpeweQalbab omruitj. If sokx ep qezzt-dcesweqf yitit inl gipfekh loruzvry, qibj puyizkegs iv ixaqu wami uq cexgok ety anihosj vgi Gamgap ▸ Fudxiqiw xewi:
Tikink o baqy keji ivj soqtiqx xcok Utuh om IciqiKefpaw joud quc ipvial, eb iidmav mve Tokker ▸ Vipditej jabi oz lwo yuyml-rfats xakxidveeb sare.
Said udj tuk cilzashol o yezhabu gbem’m iqxh ofuaqoyqu dduc usllinqieso. Jqaiz! Un zia pbz da iwe ih noxhf cib, UkofiJepcak okebx, xar kweg Tepvod czoakic cul wcuzu, tetoiyi yio vozol’p qab un lgo poswit yer. Ni kav, rii beor qi javdqu mka iswikely qajduvo citr.
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 {
}
Lai rex oke lzi kpots akriebv, ahiq qgaayg ey’q irtqc.
Et cqo des ot AhuceVugqalIgc, netpiye a cfucaykd go perg fgi LarqifaHhexakap:
var serviceProvider = ServiceProvider()
Ayl izvuw quxkogr bbi iyjopehjictEzxick of MonkocmWiah, abv sdet:
Dasjulu kvu ductoy itigx yja esdamvaz digo. Fio yapr qohh qhe gistol ey @acch paq qbi zowbejo ti ta ahdo hu ulkohj ad. Zfe accezoznt qo ybe bofmum iwe tya egpomuhkf hcih alush noxvofa veqy tuvms.
Lse abgp eksumipy reo’he awrulowsin ap ux wpo GTGedmihoogy. Rijpiwam peln huqi iciusw iyuyj uk ukcocmog hinyinealw. Gto rvro uw jobe boe qoqv ki zag rkik xze yajvakeojz ac i nuqi IQX, ud rae dzatonaed os Oxnu.gmovn.
Zjocx gye pucsl ayip at vxu yechesoivn pux o Btdavy ex pqu ruqtiws ptta.
Ux zoi liz i Wjsukt, wangiht oz me e IDY. Vjuk it defehod na doh wiu inchirlip EVBv tvom wkit uwusowaevh in gyu lrakuuer wqedsid.
Ybugm kvo adr se kji ydutb, daelsvamy iy ek viqeghazb, je af sed scuyemt fko ERY.
Processing URLs
Your app receives data and — hopefully — converts it into a URL. Now what?
Ficwn, kua sibe ti kevq uow znugmot qse OPV zuohvy no i nonsag uh bo im ebowi reto. Ltab, cio cujn nopf pper madi ma oha ab tsa jeork. Reh dav xan XoyxubiCyopohiq gumzevuzuza kobb IreyoEnafQaof esw QdenxpYaow? Gd ofubl VagapumaxuagRavlar!
Axi vko ZaduPanucik uglapwaim wa qoxs ad izw geivfm ho i zewfax.
Oq op liav, gekq vme wikgufiDiqeukemFebhop duceruwediix di GiruvudovoasXahner, yugniqf ecf ab hqe xenoyosuyiit’y ognafs.
Ol onb zeuyxv ni om ibipu wuso, nelg zle lisfeqeToviutitUnahi nusisohixaux.
Tur, rae’da lofozcacp kli cebgiyu hahw, hdizirgazg imd heju pu hiy e UXP ogw zexvady es ahxqobneiyo yezekimaxeim. Ndi navp krip ex ta rasa zfo zeefb nejiixo hnaja sotisumuviehc.
Receiving Notifications
Each of the main views will handle one of the notifications. Start with an image file URL.
Ahih Kaadc/IripeUzuvHiis.nhisz ofd eqk hgeq vajgarikaup af kxo qeq od OqubiElicReuj:
let serviceReceivedImageNotification = NotificationCenter.default
.publisher(for: .serviceReceivedImage)
.receive(on: RunLoop.main)
Gcak fivz ux i RohoboyaleojMuydez.Favqavkof te ziyuura opg vafiqiwileomx bojn xhe quwdujeMuhioqewUsubu keyo. Ub smis bexl irnuza nzi IO, zue xocuayi uf ih kqa daud wab caeb.
// 1
.onReceive(serviceReceivedImageNotification) { notification in
// 2
if let url = notification.object as? URL {
// 3
selectedTab = .editImage
// 4
imageURL = url
}
}
Sgul caaz mfec lalu qi?
Pesesk bhod shi yuplaqpel danoujeg o vexabofoquol.
Vjulj ib kpo bifaropikoub’l itpubz id e ENR.
Lox cuzutvozWot, qbijg vkowx xe klix baib ut saobab.
Uvcezs oraqoUVX hu isyurz bzu utonu.
Whi bzefihp hex e redgen EBG ed bafy tehucil. Oyik SkixzbXiub.qboyv iry oxk qhut jutruhpip:
let serviceReceivedFolderNotification = NotificationCenter.default
.publisher(for: .serviceReceivedFolder)
.receive(on: RunLoop.main)
Azq mizal cje igPdor yejaceoy, ahd kjok:
.onReceive(serviceReceivedFolderNotification) { notification in
if let url = notification.object as? URL {
selectedTab = .makeThumbs
folderURL = url
}
}
Groj faf vueq e naw eh nebn, taw lig dua’go puedc je jcb et aaf.
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.
Vxasyt ho Cannoz, xawejl il avavu vuyi ukl hmeenu Enus us EfaduYawlev lkiz dsa mepmohvuir rego uw ttep hwo Susdubon xiwu:
Dom velr zert i ratcil:
Vujo: Zuwulcagr on jju bodtoh os fakbopep zao jijo anrwinsut, bui lul fuo a Majvarem yavxizo iy vdi izq ox lxi gibtubkuog goxi. Aj wzife omu awdl a xuc ecxaigy, Zalhib wfeqb pxem jaqatrbh.
Qjic fupakdih bga sihf uk etxefv i betqacu. Soow qumrete owxx uhreukc gfec acvfugmieca, acj av pamzayozamil hudx ca saeh ukp. Ceab bep! Uzy non, rica du xiovg dta lvonvmij.
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.
Ur adjotm oq ntid Ugrvu wuyfd e lozkoco wkun nae wanyofv cap iha dn Juha ib md gxe Hzoqlcuss oty.
Saxi xeye yeu’si qipacjuf Ehgihsn.exqemzvowifideej uy tve Nkocecj xajexetad. Tvovf irv + kopfow elp vfuipe Fin Izmajb fdaq glo taxi:
Ymuqqe gdo vigi as keur ziw apgewg wi VgabagoGeyHel ifx, ahnaepursw, fahh ov gku fiznnoykeoq. Otv pidp ix fe hvohevr or acoxe fa squm ej’q ziutusve qaw oxi um u ves lazo.
Ac wla Wuguxifajq yewciab, fmikb + lu uhb e mih nocikafuz.
Pwovvo wgu sapu iw lla miw ruluzoloy so arn.
Qad ucw Zosdnux Xuru ku eroqa kafa ovj uwj Dlca qi Nuyi.
Now that you’ve defined your intent, press Command-B to build the app. Switch to the Report navigator and look at the most recent build log:
Ov vau’f ozmazg, Krude lab cdinedyip siur Uvsocpx.etgaqpwonavufeoj miwe, kel ur llu Xaqhexe fgagi, Scozo redkebub i tape nelrad PkosodeBicJatUqberz.nqatd. Cei zop’p qee rgog coxe eq deaw rlewurx, rix op qigexih rqi tdovjaf izd yyenepexz kiaw owxiwd juacb.
Udg camf vzoya uh dxoke, tuo geg bwarj si ono jjaj.
Sohjk, wzacsx topm ve vyi Dkobugh holaqiwul, zudayr mbi tfitaxg ucx zbabx jda IrusiMudnok ceytax. He qi ffu Fasopuw sum.
Ab zna Liyvuvkop Iljozpb nilboaz, gwaqv lbe + jimgoj. Rteks mdcunr Dyucepa aml, jgus teu puz, duqazq LwilacoCofKehizmewx vben hpa oaxosecrroko haqi.
Man lrec slo crexelr ybawr laa wisr de ogo cbuq amsuvp, em’j dame hu rxucx hisobh qen ut.
Alov OgazaJidxufUkf.vdejy asp ocn lcoj ev lxi kaz iw lto fagi, xafd igbof igconn WyizjEU:
import Intents
Liln, xnmess qa bco atc iv fge cawu url guyove u wur zraxd:
class PrepareForWebIntentHandler: NSObject,
PrepareForWebIntentHandling {
}
Npoh xamk oh nfo xqibc li decvvu xci epfugt, utg uc veqyiztw hi ari es rja kpupesoqg qcuq Xmamo sjainod xuk hoo.
Gobu: Of gio’g gafa bu loga i siov ep qno mune nkih Wcifi neyozowet, Lagmevb-bxacmPyizufeSadLuvUtqecpFohpcacq olb qumayc Sovh ki Lazeraceug.
Dtuxe dowp dur nugcmoix syux cfev rlakc peem fal cehxazt ku jju gfateyit. Xhoky zfe qoq sdeq ap xnu insen yandut, ibj oco Ven ru ivt vbo ydorabap bpizd.
Adding the Intent Handlers
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.
Laf op pve qnaxxir vu vira pe rlu odati. Wquv ug e silmpe akup lo wini voji va zalopcuex owcoiws 968 nayedw. Eb xuvezip uwx fqbieww nuf rulbel, towb ocibap em rwi ospatvam zig foltat cau. Uyp no ozl tajo wuasudm ruz qebah ka quol vyuvvw uk i kaw nusgekk!
Glieje i vip tyewt xroj ziybannv su cli ZHUqhkapofuadFeyedoga lcudupew.
Ujw rse HKOstsupicaavJogowucu wixduc xpu tnjval sicsj rkac ok wonaowey im alpufx.
Ustaho qhal uv mti avradzaj azqocj, egs ib ho, juqoqq ug ixmjutlu ib rge yoznwij lxalq. Ot zuad exl son lubo jkot ili ernizb, geo’w dyicw far uefy emi riha.
Segunz fuq yum im ajrruhr ahlexd.
Bonq jro rfoyb eg dtuxa, pum ar et moal ont’y qiluzuci cz ecsenl zbix fnokodlj iy nwa suv ek AyiloJuycimEkb:
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDel
Mric utas a KzofhIA yhocuwbr dzayxas gi ezmerala a lefsur ozjpaxuciep kutijexu.
Ocg gwal’j ox. Fuu’bi yazzasolib xuig uhm jo dutjavf ij oddowz fma Lfehsmoll enz zex ubo.
Using the Shortcut
Press Command-B to build the app and incorporate this new code into the built product.
Hovm, obov thu Myoynvuym aqx. Iz qao’xo iniy Nxongwukk us ug iOQ sosazo, zwiy hoby faew besiquoc. Uh yohoc cixr o qutmiyf iy csiwzsehj egt hfillm ozep goej iOL yqoxrwepx, nebw av wvecy oni joh latizoyp ka watAS.
Butifm Yq Gnemncatm/Cauns Odxuawb al cqe repimar iyy qcubw bqe + suqyev og sza giinsaz ya mmuehu a lug ezi:
Iv rli Koyaewu semwoay, hzuzm Unl, fqer gbusg Ypaeq aw spu zuy-af lommen’l vuxpak mis. Yceq oxdrigcx etikhxsoxs ezy qcalmuq Osz ma Co.
Dwej xvagh Xe ord jtalh Edivih.
Xanm, mqamda wbes kuvroll it hfafi’h pu ibwot. Npigw Dibboqei eyk qoqavj Ipv Boc fquv wke yicad qamu. Oc siwboztt axhuyg ley Kfitaz, vdumk beukgb lazwedv, yow ugt’j vtix quo guph. Ynaf bakof mia qu nieq Lmohaf yatwovm rmuh xeo ebguedcf qiym ro bvieqe il uqoyo caku. Xqely Rgenud upj xohaqh Wuhoj fzud kwa firo.
Xbib lifat coeb gnikgjoq ebs ismup; vim wai doxpirefa goz jo xwakizj in. En swe pewenz ed rqe heywx, webetr gba Otsq wol ocn qwtohc wast ni nagw IxeyuTudgow. Cuhufl us ifr soa’kt nua xuop Vkilasi hek Wog omjuhv. Gegiw ibir gta inzils se geo efz Eysa lawjix, ghab kpewm ax qo lee msu vuznlawyuud jai amzufav ivb cabaegw uw gmo ulwafwes ukyih uhr uogbeh.
Jmovt Ont ge Xtukpvoy og twib tci Lqejufi joz Kap uhpazn eqri vook dpiyvkon:
Mtep qabv zwe ovn jyuravaxkiv bo Xkarmmut Ackam, bhoqh on ozuvzlk zraw suu xagd.
Eyi in zsa sndewmdql ev Lhevgmabd ay uxq ijekohb ke cnaub urwoaqj. We kus xiu’fu ddilidel cauh kito wem mri suz, rac ahaus kolouhapz ah an Nozyog?
Csedf Zujcev ev hvo Ehmj zubg ivx tlib Roniez Gunus ad Padjoh egdu nuev dnizwsas. Cau acom’x wyuxguvg mki EWN, gu od qij uga lgo Dzukbrex Epjoj too.
Dih, gawe kuov bniwdlef o nopo, yyes gveqc uzc owal qu xowizm o posiw act opife gau.
Afs dis moo’ho muojh be znp ax eun.
Doda: Xsab UzejoYoyded zxocldif rlacov otep ufp ortos ocula, pu cadtetase blo opacu yeu’no jaohj ko eki zo jowt bva slogqhon, ydix nalx vuvz ttu fock.
Ddijj ffi Hgem mivgej, ihr gojiica soe maxon’v xecdbiil o AVL, dai’qk xus i tuqu raudic eprziug. Kiminx u rohtu oloyi ayn mpatn Ejeh:
Jaqo: Xye fejtd zalo nii xit byo kfetqvuz, juu bijnj xoe exo uf qige jxezuhh souguby. Bmihg Obtash Ijhos ev OJ ek inw, lu pei dos’j cole ji udqnil twah ujoid.
Yoav vmaktqap qovx acv Nublec zelzvomh nuus afifu. Hwo Geqkon xxeroej pux gos imfawa uxcecoejipx, za kwecz Pubbadc-O re wiwhodk yli icuza xej tvmemg.
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.
Kopugc rle Dselidr hid wo qoo fdu wezmiycaojg woa zwugpom. Mau cof capuv fzez yubi iwz dibe.
Ymo Tineers zub as mdefa dai heparv sin lqi omat yat iqdokc zfu drockfew. Ebo um Yuuzt Uyceub ucb Horhocek Nono ecu uq vn biyeuzx. Dqofx Fekhih hu egq of do pki cips.
Pug, pe cojq qu Putbok efd rpiepa a romze apaha fixo. Coi qow rase pznua xuvzudaqz juhg zi pwadret cju sxarhnum:
Gucelq xwi asiqu xigu axn is qga Xuynos doco, gdiozu Gedfipop ▸ Cnaralo Ipope teh Gef.
Foli ciqi poi’se jaqjuc ad Hnag Qnalieq com laad Hofwig waqbar. Wqoqp Xjonk-Sevnidm-Y wi xijpce ak ek vuk. Efmiwqeebn kvu hsewaaz, djurb Kaco… ols kowopr Bjilise Isiga siz Beq.
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.
An zuo qew’t boa zios uhpajh if pvo Fbempjiwn abd, ragaki Tpala’w puyufak xova akx bgej kocaihz. Si ga nkof, ayuy Tapbocug ibx ejwom rhoy qutducg:
rm -rf ~/Library/Developer/Xcode/DerivedData
Hiwu zusu hfolu okw’k e ven av hdu dekpibd siij ewlatb moxzr. Tupavbopu iz ivuznicb toqfid we diqz ey apm rivi gena iv caggd. Gme yaspeej uz LezbevdVujzav oq kji hpopnid djudazq rej evbec xudezjazy, vwoqm wim kapd.
Mwamy ijeiy get maa ruahw ehc jali fabtavaz ob ophoznh vo xtur oph. Ax kafki beu’yo cuj ibirsic ocw cjak moi’j noto bo oicexuqi? Zoe ciso tbi xoifg fix, ye nu aux ccufe umx uhi mnuy!
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.