En handledning om iOS 8 App Extensions

Få hade försökt tidigare (se här), men det var Apple som med den första iPhone definierade hur en smartphone och ett mobilt operativsystem skulle se ut. Apple gjorde ett otroligt genombrott inom hårdvara och användarupplevelse. Vi glömmer dock ofta att de också satte standarder för hur ett mobilt operativsystem ska fungera och hur applikationer för smartphones ska utformas.

Att bygga betongväggar mellan applikationerna, så att de blir helt isolerade och omedvetna om varandra, var den bästa metoden för att hålla dem säkra och skydda deras data. Alla aktiviteter övervakades noga av iOS, och det fanns bara en handfull åtgärder som en app kunde ha gjort utanför dess räckvidd.

”Avhållsamhet är det bästa skyddet!” –

Det tog ett tag, för lång tid om du frågar mig, men med iOS 8 bestämde sig Apple för att ha lite kul. iOS 8 introducerade ett nytt koncept som kallas App Extensions. Denna nya funktion bröt inte ner väggarna mellan programmen, men den öppnade några dörrar som gav en försiktig men konkret kontakt mellan vissa appar. Den senaste uppdateringen gav iOS-utvecklare en möjlighet att anpassa iOS-ekosystemet, och vi är ivriga att se den här vägen öppnas också.

Vad är iOS 8 App Extensions och hur fungerar de?

Enklare uttryckt ger iOS 8 App Extensions en ny metod för att interagera med din applikation, utan att starta den eller visa den på skärmen.

Som väntat såg Apple till att hålla koll på allt, så det finns bara en handfull nya ingångar som din applikation kan tillhandahålla:

  • Idag (även kallad widget) – ett tillägg som visas i Today-vyn i Notifieringscenter visar kort information och gör det möjligt att utföra snabba uppgifter.
  • Dela – ett tillägg som gör det möjligt för din app att dela innehåll med användare i sociala nätverk och andra delningstjänster.
  • Åtgärd – ett tillägg som gör det möjligt att skapa anpassade åtgärdsknappar i Åtgärdsbladet för att låta användare visa eller omvandla innehåll som har sitt ursprung i en värd-app.
  • Fotoredigering – ett tillägg som gör det möjligt för användare att redigera ett foto eller en video i appen Foton.
  • Dokumentleverantör – ett tillägg som används för att låta andra appar få tillgång till de dokument som hanteras av din app.
  • Anpassat tangentbord – ett tillägg som ersätter systemtangentbordet.

Apptillägg är inte fristående appar. De tillhandahåller utökad funktionalitet i appen (som kan nås från andra appar, så kallade värdappar) som ska vara effektiv och inriktad på en enda uppgift. De har en egen binär kod, en egen kodsignatur och en egen uppsättning element, men levereras via App Store som en del av den ingående appens binära kod. En app (innehållande) kan ha mer än ett tillägg. När användaren installerar en app som har tillägg kommer de att vara tillgängliga i hela iOS.

Låt oss titta på ett exempel: En användare hittar en bild med hjälp av Safari, trycker på delningsknappen och väljer ditt applikationstillägg för delning. Safari ”pratar” med ramverket iOS Social, som laddar och presenterar tillägget. Tilläggets kod körs, överför data med hjälp av systemets instansierade kommunikationskanaler och när uppgiften är klar – Safari river ner tilläggsvyn. Strax därefter avslutar systemet processen, och ditt program visades aldrig på skärmen. Ändå slutförde den en bilddelningsfunktion.

iOS, som använder sig av interprocesskommunikation, är den som ansvarar för att se till att värdprogrammet och ett programtillägg kan arbeta tillsammans. Utvecklarna använder API:er på hög nivå som tillhandahålls av tilläggspunkten och systemet, så de behöver aldrig oroa sig för de underliggande kommunikationsmekanismerna.

Livscykel

App Extension har en annan livscykel än IOS-appar. Värd-appen startar tilläggets livscykel som ett svar på en användares åtgärd. Därefter instansierar systemet apptillägget och upprättar en kommunikationskanal mellan dem. Tilläggets vy visas i värd-appens kontext med hjälp av de objekt som tagits emot i värd-appens begäran. När tilläggets vy visas kan användaren interagera med den. Som svar på användarens åtgärd slutför tillägget värd-appens begäran genom att omedelbart utföra/avbryta uppgiften eller, om nödvändigt, starta en bakgrundsprocess för att utföra den. Direkt efter detta tar värdprogrammet bort tilläggets vy och användaren återgår till sitt tidigare sammanhang i värdprogrammet. Resultaten från utförandet av denna process skulle kunna returneras till värd-appen när processen är avslutad. Tillägget avslutas vanligtvis strax efter att det har slutfört den begäran som mottagits från värd-appen (eller startar en bakgrundsprocess för att utföra den).

Systemet öppnar tillägget av en användares åtgärd från värd-appen, tillägget visar användargränssnittet, utför ett visst arbete och returnerar data till värd-appen (om det är lämpligt för tilläggets typ). Den innehållande appen körs inte ens medan dess tillägg körs.

Skapa ett apptillägg – praktiskt exempel med hjälp av Today Extension

Today extensions, även kallade widgets, finns i Notification center’s Today view. De är ett utmärkt sätt att presentera ett aktuellt innehåll för användaren (t.ex. visa väderförhållanden) eller utföra snabba uppgifter (t.ex. markera de saker som är gjorda i en widget för en app med en att-göra-lista). Jag måste här påpeka att tangentbordsinmatning inte stöds.

Låt oss skapa ett Today-tillägg som visar den mest aktuella informationen från vår app (kod på GitHub). För att kunna köra den här koden måste du se till att du har (om)konfigurerat App Group för projektet (välj ditt utvecklingsteam, tänk på att App Group-namnet måste vara unikt och följ Xcodes instruktioner).

Skapa en ny widget

Som vi sa tidigare är apputvidgningarna inte fristående appar. Vi behöver en innehållande app som vi ska bygga apptillägget på. När vi har vår containing app väljer vi att lägga till ett nytt mål genom att navigera till File -> New -> Target i Xcode. Härifrån väljer vi mallen för vårt nya mål för att lägga till en Today Extension.

I nästa steg kan vi välja vårt produktnamn. Det är det namnet som kommer att visas i Notifieringscentrets Today-vy. Det finns ett alternativ för att välja språk mellan Swift och Objective-C i det här steget också. När du avslutar de här stegen skapar Xcode en Today-mall, som tillhandahåller standardheader- och implementeringsfiler för huvudklassen (med namnet TodayViewController) med Info.plist-fil och en gränssnittsfil (en storyboard- eller .xib-fil). Info.plist-filen ser som standard ut så här:

Om du inte vill använda den storyboard som mallen tillhandahåller tar du bort NSExtensionMainStoryboard-nyckeln och lägger till NSExtensionPrincipalClass-nyckeln med namnet på din view controller som värde.

En widget för Today ska:

  • säkerställa att innehållet alltid ser aktuellt ut
  • respondera på lämpligt sätt på användarinteraktioner
  • prestera väl (iOS-widgetar måste använda minnet på ett klokt sätt, annars avslutas de av systemet)

Delning av data och en delad behållare

Apptillägget till appen och dess innehållsapplikation har båda åtkomst till de delade data som finns i deras privat definierade delade behållare. vilket är ett sätt att indirekt kommunicera mellan den ingående appen och tillägget.

Är det inte fantastiskt hur Apple gör dessa saker så ”enkla”? 🙂

Det är enkelt och vanligt att dela data via NSUserDefaults. Som standard använder tillägget och den ingående appen separata NSUserDefaults-datamängder och kan inte komma åt varandras behållare. För att ändra detta beteende införde iOS App Groups. När du har aktiverat appgrupper på den innehållande appen och tillägget kan du istället för att använda använda initWithSuiteName:@"group.yourAppGroupName"] för åtkomst till samma delade behållare.

Uppdatering av widgeten

För att se till att innehållet alltid är uppdaterat tillhandahåller Today-tillägget ett API för hantering av en widgets tillstånd och hantering av innehållsuppdateringar. Systemet fångar ibland ögonblicksbilder av widgets vy, så när widgeten blir synlig visas den senaste ögonblicksbilden tills den ersätts med en levande version av vyn. En anpassning till NCWidgetProviding-protokollet är viktig för att uppdatera en widgets tillstånd innan en ögonblicksbild tas. När widgeten tar emot widgetPerformUpdateWithCompletionHandler:-anropet ska widgets vy uppdateras med det senaste innehållet och avslutningshanteraren ska anropas med en av följande konstanter för att beskriva resultatet av uppdateringen:

  • NCUpdateResultNewData – Det nya innehållet kräver att vyn ritas om
  • NCUpdateResultNoDate – Widgeten behöver inte uppdateras
  • NCUpdateResultFailed – Ett fel inträffade under uppdateringsprocessen

Kontrollera när widgeten är visningsbar

För att styra när en widget visas använder du metoden setHasContent:forWidgetWithBundleIdentifier: från NCWidgetController-klassen. Med den här metoden kan du ange tillståndet för widgets innehåll. Den kan anropas från widgeten eller från den app som innehåller den (om den är aktiv). Du kan skicka en NO eller en YES flagga till den här metoden, som definierar att widgets innehåll är redo eller inte. Om innehållet inte är klart kommer iOS inte att visa din widget när Today-vyn öppnas.

Öppning av innehållsappen från widgeten

Today-widgeten är det enda tillägget som kan begära att öppna sin innehållsapp genom att anropa openURL:completionHandler:-metoden. För att se till att den innehållande appen öppnas på ett sätt som är meningsfullt i samband med användarens aktuella uppgift bör ett anpassat URL-schema (som både widgeten och den innehållande appen kan använda) definieras.

 completionHandler:nil];

UI Considerations

När du utformar din widget ska du dra nytta av klassen UIVisualEffectView, med tanke på att de vyer som ska vara oskarpa/vibrerande måste läggas till i contentView och inte i UIVisualEffectView direkt. Widgets (som överensstämmer med NCWidgetProviding-protokollet) bör ladda cachade tillstånd i viewWillAppear: för att matcha visningens tillstånd från senaste viewWillDisappear: och sedan övergå smidigt till de nya uppgifterna när de anländer, vilket inte är fallet med en normal visningskontrollant (UI sätts upp i viewDidLoad och hanterar animationer och laddning av data i viewWillAppear). Widgets bör vara utformade för att utföra en uppgift eller öppna den ingående appen med ett enda tryck. Tangentbordsinmatningen är inte tillgänglig inom en widget. Detta innebär att alla användargränssnitt som kräver textinmatning inte bör användas.

Att lägga till rullar i en widget, både vertikala och horisontella, är inte möjligt. Eller mer exakt, att lägga till en rullvy är möjligt men rullning fungerar inte. Horisontella rullningsgester i en rullningsvy i Today-tillägget kommer att avlyssnas av notifieringscentret, vilket kommer att orsaka rullning från Today till notifieringscentret. Vertikal rullning i en rullvyn i ett Today-tillägg kommer att avbrytas av rullning i Today-vyn.

Tekniska anteckningar

Här kommer jag att peka på några viktiga saker att tänka på när du skapar ett App Extension.

Funktioner som är gemensamma för alla tillägg

Följande punkter gäller för alla tillägg:

  • SharedApplication-objektet är förbjudet: App-tillägg kan inte få tillgång till ett sharedApplication-objekt eller använda någon av de metoder som är relaterade till det objektet.

  • Kamera och mikrofon är förbjudna: App-tillägg kan inte komma åt kameran eller mikrofonen på enheten (men detta gäller inte för alla maskinvaruelement). Detta beror på att vissa API:er inte är tillgängliga. För att få tillgång till vissa maskinvaruelement i apptillägget måste du kontrollera om dess API är tillgängligt för apptillägg eller inte (med kontrollen av API-tillgänglighet som beskrivs ovan).

  • De flesta bakgrundsuppgifter är förbjudna: App-tillägg kan inte utföra långvariga bakgrundsuppgifter, förutom att initiera uppladdningar eller nedladdningar, vilket diskuteras nedan.

  • AirDrop är förbjudet: App-tillägg kan inte ta emot (men kan skicka) data med AirDrop.

Uppladdning/nedladdning i bakgrunden

Den enda uppgift som kan utföras i bakgrunden är uppladdning/nedladdning med hjälp av NSURLSession object.

När uppladdnings-/nedladdningsuppgiften har påbörjats kan tillägget slutföra värd-appens begäran och avslutas utan att det har någon effekt på resultatet av uppgiften. Om tillägget inte körs när bakgrundsuppgiften avslutas startar systemet den innehållande appen i bakgrunden och appens delegatmetod application:handleEventsForBackgroundURLSession:completionHandler: anropas.

Den app som tillägget initierar en bakgrundsuppgift NSURLSession måste ha en delad behållare konfigurerad som både den innehållande appen och dess tillägg kan få tillgång till.

Se till att skapa olika bakgrundssessioner för den innehållande appen och var och en av dess apptillägg (varje bakgrundssession bör ha en unik identifierare). Detta är viktigt eftersom endast en process kan använda en bakgrundssession åt gången.

Action vs Share

Skillnaderna mellan tilläggen Action och Share är inte helt tydliga från en kodares perspektiv, eftersom de i praktiken är väldigt lika. Xcodes mall för målet för share-förlängningen använder SLComposeServiceViewController, vilket ger ett standardutförande för komponeringsvyn som du kan använda för social delning, men det är inte nödvändigt. Ett share-tillägg kan också ärva direkt från UIViewController för en helt anpassad design, på samma sätt som ett Action-tillägg kan ärva från SLComposeServiceViewController.

Skillnaderna mellan de här två typerna av tillägg ligger i hur de är tänkta att användas. Med tillägget Action kan du bygga ett tillägg utan eget gränssnitt (till exempel ett tillägg som används för att översätta den valda texten och returnera översättningen till värdprogrammet). Med Share-tillägget kan du dela kommentarer, foton, videor, ljud, länkar med mera direkt från värd-appen. UIActivityViewController driver både Action- och Share-tillägg, där Share-tillägg presenteras som färgikoner i den övre raden och action-tillägg presenteras som monokroma ikoner i den nedre raden (bild 2.1).

Förbjudna API:er

API:er som är markerade i headerfilerna med makrot NS_EXTENSION_UNAVAILABLE eller liknande makro för otillgänglighet, kan inte användas (t.ex: Om du delar kod mellan en app och ett tillägg måste du tänka på att även om du hänvisar till ett API som inte är tillåtet för apptillägget kommer din app att avvisas från App Store. Du kan välja att hantera det här genom att omforma de delade klasserna till hierarkier, med en gemensam överordnad klass och olika underklasser för olika mål.Ett annat sätt är att använda förprocessorn genom #ifdef kontroller. Eftersom det fortfarande inte finns något inbyggt målvillkor måste du skapa ett eget.

Ett annat trevligt sätt att göra detta är att skapa ett eget inbäddat ramverk. Se bara till att den inte kommer att innehålla några API:er som är otillgängliga för tillägg. Om du vill konfigurera ett apptillägg för att använda ett inbäddat ramverk navigerar du till målets bygginställningar och ställer in inställningen ”Require Only App-Extension-Safe API” på Yes. När du konfigurerar Xcode-projektet måste du i byggfasen Kopiera filer välja ”Frameworks” som destination för det inbäddade ramverket. Om du väljer destinationen ”SharedFrameworks” kommer din inlämning att avvisas av App Store.

En anmärkning om bakåtkompatibilitet

Trots att apputvidgningar endast har varit tillgängliga sedan iOS 8 kan du göra din innehållsrika app tillgänglig för tidigare iOS-versioner.

Apples överensstämmelse med mänskliga gränssnitt

Håll dig till Apples riktlinjer för det mänskliga gränssnittet för iOS när du utformar en apputvidgning. Du måste se till att apptillägget är universellt, oavsett vilken enhet som den ingående appen stöder. För att se till att apptillägget är universellt kan du använda inställningen ”targeted device family build” i Xcode och ange värdet ”iPhone/iPad” (ibland kallat universellt).

Slutsats

Apptillägg har definitivt den mest synliga effekten i iOS 8. Eftersom 79 % av enheterna redan använder iOS 8 (enligt mätning från App Store den 13 april 2015) är apputvidgningarna otroliga funktioner som appar bör dra nytta av. Genom att kombinera API:s begränsningar och sättet att dela data mellan tillägg och den ingående appen verkar det som om Apple lyckats ta itu med ett av de största klagomålen på plattformen utan att kompromissa med säkerhetsmodellen. Det finns fortfarande inget sätt för tredjepartsappar att direkt dela sina data med varandra. Även om detta är ett mycket nytt koncept ser det mycket lovande ut.

Lämna ett svar

Din e-postadress kommer inte publiceras.