A Tutorial on iOS 8 App Extensions

Már kevesen próbálkoztak korábban (nézd meg ezt), de az Apple volt az, aki az első iPhone-nal meghatározta, hogyan kell kinéznie egy okostelefonnak és egy mobil operációs rendszernek. Az Apple hihetetlen áttörést ért el a hardver és a felhasználói élmény terén. Gyakran elfelejtjük azonban, hogy ők szabták meg a mércét abban is, hogyan működjön egy mobil operációs rendszer, és hogyan készüljenek az okostelefonos alkalmazások.

Az alkalmazások között betonfalakat építeni, teljesen elszigetelve és egymásról mit sem tudva, ez volt a legjobb módszer a biztonság és az adatok védelmére. Az iOS minden tevékenységet szigorúan felügyelt, és csak néhány olyan művelet volt, amelyet egy alkalmazás a hatáskörén kívül végezhetett volna.

“Az önmegtartóztatás a legjobb védelem!” – de hol van ebben a móka?

Ez eltartott egy ideig; túl sokáig, ha engem kérdezel, de az iOS 8-cal az Apple úgy döntött, hogy szórakozik egy kicsit. Az iOS 8 bevezetett egy új koncepciót, az App Extensions-t. Ez az új funkció nem bontotta le a falakat az alkalmazások között, de kinyitott néhány ajtót, amely gyengéd, de kézzelfogható kapcsolatot biztosított egyes alkalmazások között. A legutóbbi frissítés lehetőséget adott az iOS-fejlesztőknek az iOS-ökoszisztéma testreszabására, és alig várjuk, hogy ez az út is megnyíljon.

Mi az iOS 8 App Extensions és hogyan működik?

Egyszerűbben fogalmazva, az iOS 8 App Extensions egy új módszert biztosít az alkalmazással való interakcióra anélkül, hogy elindítaná vagy megjelenítené azt a képernyőn.

Amint az várható volt, az Apple ügyelt arra, hogy mindenben a csúcson maradjon, így csak egy maroknyi új belépési pont van, amelyet az alkalmazásod biztosíthat:

  • Today (más néven widget) – az Értesítési központ Today nézetében megjelenő bővítmény rövid információkat mutat és gyors feladatok elvégzését teszi lehetővé.
  • Megosztás – olyan bővítmény, amely lehetővé teszi, hogy az alkalmazása tartalmakat osszon meg a felhasználókkal a közösségi hálózatokon és más megosztó szolgáltatásokon.
  • Művelet – olyan bővítmény, amely lehetővé teszi egyéni műveletgombok létrehozását a Művelet lapon, amelyek segítségével a felhasználók megtekinthetik vagy átalakíthatják a fogadó alkalmazásból származó tartalmakat.
  • Fotószerkesztés – olyan bővítmény, amely lehetővé teszi a felhasználók számára, hogy a Fotók alkalmazáson belül fényképet vagy videót szerkesszenek.
  • Dokumentumszolgáltató – olyan bővítmény, amely lehetővé teszi más alkalmazások számára, hogy hozzáférjenek az alkalmazás által kezelt dokumentumokhoz.
  • Egyéni billentyűzet – a rendszerbillentyűzetet helyettesítő bővítmény.

Az alkalmazásbővítmények nem önálló alkalmazások. Az alkalmazás kibővített funkcionalitását biztosítják (amely más alkalmazásokból, úgynevezett gazdalkalmazásokból érhető el), amelyek célja, hogy hatékonyak legyenek és egyetlen feladatra összpontosítsanak. Saját binárissal, saját kódaláírással és saját elemkészlettel rendelkeznek, de az App Store-on keresztül a tartalmazó alkalmazás binárisának részeként kerülnek kiszállításra. Egy (tartalmazó) alkalmazásnak több kiterjesztése is lehet. Amint a felhasználó telepít egy olyan alkalmazást, amely bővítményekkel rendelkezik, azok az egész iOS-ben elérhetővé válnak.

Nézzünk egy példát: Egy felhasználó talál egy képet a Safari segítségével, megnyomja a megosztás gombot, és kiválasztja az alkalmazásbővítményt a megosztáshoz. A Safari “beszél” az iOS Social keretrendszerével, amely betölti és bemutatja a bővítményt. A bővítmény kódja lefut, adatokat továbbít a rendszer instantiált kommunikációs csatornáinak segítségével, majd a feladat elvégzése után – a Safari leszedi a bővítmény nézetét. Nem sokkal ezután a rendszer befejezi a folyamatot, és az alkalmazás soha nem jelent meg a képernyőn. Mégis befejezett egy képmegosztó funkciót.

Az iOS a folyamatok közötti kommunikáció segítségével biztosítja, hogy a gazdalkalmazás és egy alkalmazásbővítmény együtt tudjon működni. A fejlesztők a kiterjesztési pont és a rendszer által biztosított magas szintű API-kat használják, így soha nem kell aggódniuk a mögöttes kommunikációs mechanizmusok miatt.

Élettartam

Az alkalmazásbővítmények életciklusa eltér az iOS-alkalmazásokétól. A gazdalkalmazás egy felhasználói műveletre adott válaszként indítja el a kiterjesztés életciklusát. Ezután a rendszer instanciálja az alkalmazásbővítményt, és kommunikációs csatornát hoz létre közöttük. A kiterjesztés nézete a gazdalkalmazás kontextusában jelenik meg a gazdalkalmazás kérésében kapott elemek felhasználásával. Miután a bővítmény nézete megjelenik, a felhasználó interakcióba léphet vele. A felhasználó műveletére válaszul a bővítmény a gazdalkalmazás kérését a feladat azonnali végrehajtásával/törlésével, vagy szükség esetén a feladat végrehajtásához szükséges háttérfolyamat elindításával fejezi be. Közvetlenül ezután a gazdalkalmazás lebontja a bővítmény nézetét, és a felhasználó visszatér a gazdalkalmazáson belüli korábbi kontextusába. A folyamat elvégzésének eredményei a folyamat befejezése után visszakerülhetnek a gazdalkalmazásba. A bővítmény általában hamarosan befejeződik, miután befejezte a gazdalkalmazástól kapott kérést (vagy elindít egy háttérfolyamatot annak elvégzésére).

A rendszer megnyitja a felhasználó műveletének bővítményét a gazdalkalmazásból, a bővítmény megjeleníti a felhasználói felületet, elvégez valamilyen munkát, és adatokat küld vissza a gazdalkalmazásnak (ha ez megfelel a bővítmény típusának). A tartalmazó alkalmazás nem is fut, amíg a bővítménye fut.

Alkalmazásbővítmény létrehozása – gyakorlati példa a Today bővítmény használatával

A Today bővítmények, más néven widgetek az Értesítési központ Today nézetében találhatók. Kiválóan alkalmasak arra, hogy a felhasználó számára naprakész tartalmat mutassanak be (például az időjárási viszonyok megjelenítése) vagy gyors feladatokat hajtsanak végre (például az elvégzett dolgok jelölése egy teendőlistás alkalmazás widgetjében). Itt kell felhívnom a figyelmet arra, hogy a billentyűzetes bevitel nem támogatott.

Készítsünk egy Today bővítményt, amely megjeleníti az alkalmazásunk legfrissebb információit (kód a GitHubon). A kód futtatásához győződjünk meg arról, hogy (újra)konfiguráltuk a projekt App Groupját (válasszuk ki a fejlesztői csapatunkat, ne feledjük, hogy az App Group nevének egyedinek kell lennie, és kövessük az Xcode utasításait).

Új Widget létrehozása

Amint már említettük, az alkalmazásbővítmények nem önálló alkalmazások. Szükségünk van egy tartalmazó alkalmazásra, amelyre az alkalmazásbővítményt építjük. Miután megvan a tartalmazó alkalmazásunk, az Xcode-ban a File -> New -> Target menüpontra navigálva új célpontot választunk. Innen kiválasztjuk az új célpontunk sablonját, hogy hozzáadjunk egy Today Extension-t.

A következő lépésben kiválaszthatjuk a terméknevünket. Ez a név fog megjelenni az Értesítési központ Today nézetében. Ebben a lépésben lehetőség van a nyelv kiválasztására is a Swift és az Objective-C között. Ezen lépések befejeztével az Xcode létrehoz egy Today sablont, amely alapértelmezett fejléc- és implementációs fájlokat biztosít a fő osztály (neve TodayViewController) Info.plist fájljával és egy interfészfájllal (egy storyboard vagy .xib fájl). A Info.plist fájl alapértelmezés szerint így néz ki:

Ha nem szeretné használni a sablon által biztosított storyboardot, távolítsa el a NSExtensionMainStoryboard kulcsot, és adja hozzá a NSExtensionPrincipalClass kulcsot a nézetvezérlő nevével, mint értékkel.

A Today widgetnek a következőket kell tennie:

  • biztosítani, hogy a tartalom mindig naprakésznek tűnjön
  • megfelelően reagálni a felhasználói interakciókra
  • megfelelően teljesíteni (az iOS widgeteknek okosan kell használniuk a memóriát, különben a rendszer megszünteti őket)

Adatok és egy megosztott tároló megosztása

Az alkalmazásbővítmény és az azt tartalmazó alkalmazás egyaránt hozzáfér a megosztott adatokhoz a saját, privátan meghatározott megosztott tárolóban. ami egyfajta közvetett kommunikáció a tartalmazó alkalmazás és a kiterjesztés között.

Hát nem imádod, hogy az Apple ilyen “egyszerűvé” teszi ezeket a dolgokat? 🙂

Az adatok megosztása a NSUserDefaults segítségével egyszerű és gyakori felhasználási eset. Alapértelmezés szerint a bővítmény és az azt tartalmazó alkalmazás külön NSUserDefaults adatkészleteket használ, és nem férhetnek hozzá egymás tárolóihoz. Ennek a viselkedésnek a megváltoztatására az iOS bevezette az alkalmazáscsoportokat. Miután engedélyezte az alkalmazáscsoportokat a tartalmazó alkalmazáson és a bővítményen, a helyett használja a initWithSuiteName:@"group.yourAppGroupName"]-t ugyanazon megosztott tároló eléréséhez.

A widget frissítése

A tartalom folyamatos naprakészségének biztosítása érdekében a Today bővítmény egy API-t biztosít a widget állapotának kezeléséhez és a tartalomfrissítések kezeléséhez. A rendszer időnként pillanatfelvételeket készít a widget nézetéről, így amikor a widget láthatóvá válik, a legfrissebb pillanatfelvétel jelenik meg, amíg azt fel nem váltja a nézet élő változata. A NCWidgetProviding protokollnak való megfelelés fontos a widget állapotának frissítéséhez a pillanatfelvétel készítése előtt. Miután a widget megkapta a widgetPerformUpdateWithCompletionHandler: hívást, a widget nézetét a legfrissebb tartalommal kell frissíteni, és a befejező kezelőt a következő konstansok valamelyikével kell meghívni a frissítés eredményének leírására:

  • NCUpdateResultNewData – Az új tartalom a nézet újrarajzolását igényli
  • NCUpdateResultNoDate – A widget nem igényel frissítést
  • NCUpdateResultFailed – Hiba történt a frissítés során

A widget megjelenítésének vezérlése

A widget megjelenítésének vezérléséhez a NCWidgetController osztály setHasContent:forWidgetWithBundleIdentifier: módszerét használjuk. Ezzel a metódussal megadhatjuk a widget tartalmának állapotát. Meghívható a widgetből vagy az azt tartalmazó alkalmazásból (ha az aktív). Átadhat egy NO vagy egy YES jelzőt ennek a metódusnak, amely meghatározza, hogy a widget tartalma készen áll-e vagy sem. Ha a tartalom nem kész, az iOS nem fogja megjeleníteni a widgetet a Today nézet megnyitásakor.

A Tartalmazó alkalmazás megnyitása a widgetből

A Today widget az egyetlen olyan bővítmény, amely a openURL:completionHandler: metódus meghívásával kérheti a tartalmazó alkalmazás megnyitását. Annak érdekében, hogy a tartalmazó alkalmazás a felhasználó aktuális feladatának kontextusában értelmes módon nyíljon meg, egy egyéni URL-sémát kell definiálni (amelyet mind a widget, mind a tartalmazó alkalmazás használhat).

 completionHandler:nil];

UI megfontolások

A widget tervezésekor használja ki a UIVisualEffectView osztály előnyeit, szem előtt tartva, hogy a homályosnak/vibrálónak szánt nézeteket a contentView-hez kell hozzáadni, és nem közvetlenül a UIVisualEffectView-hoz. A (NCWidgetProviding protokollnak megfelelő) widgeteknek a viewWillAppear:-ben kell betölteniük a gyorsítótárazott állapotokat, hogy megfeleljenek a nézet állapotának az utolsó viewWillDisappear:-ból, majd az új adatok megérkezésekor simán áttérjenek az új adatokra, ami egy normál nézetvezérlőnél nem így van (az UI a viewDidLoad-ben van beállítva, és az animációkat és az adatok betöltését a viewWillAppear-ban kezeli). A widgeteket úgy kell kialakítani, hogy egy feladatot hajtsanak végre, vagy egyetlen érintéssel nyissák meg a tartalmazó alkalmazást. A billentyűzetbevitel nem érhető el egy widgeten belül. Ez azt jelenti, hogy szövegbevitelt igénylő felhasználói felületet nem szabad használni.

Függőleges és vízszintes görgetés hozzáadása egy widgetbe nem lehetséges. Pontosabban, görgetési nézet hozzáadása lehetséges, de a görgetés nem fog működni. A Today bővítményben lévő görgetési nézetben a vízszintes görgetés gesztusát az értesítési központ elfogja, ami a Todayből az értesítési központba történő görgetést eredményezi. A függőleges görgetés egy görgetési nézetben a Today bővítményen belül megszakítja a Today nézet görgetését.

Technikai megjegyzések

Itt rámutatok néhány fontos dologra, amit szem előtt kell tartani egy alkalmazásbővítmény létrehozásakor.

Minden bővítményre közös jellemzők

A következő elemek minden bővítményre igazak:

  • sharedApplication object is off limits: Az alkalmazásbővítmények nem férhetnek hozzá a sharedApplication objektumhoz, és nem használhatják az objektumhoz kapcsolódó metódusokat.

  • A kamera és a mikrofon tiltott: Az alkalmazásbővítmények nem férhetnek hozzá az eszköz kamerájához vagy mikrofonjához (de ez nem minden hardverelemre vonatkozik). Ez egyes API-k elérhetetlenségéből adódik. Az alkalmazásbővítmény egyes hardverelemeinek eléréséhez ellenőrizni kell, hogy az adott API elérhető-e az alkalmazásbővítmények számára vagy sem (a fent leírt API elérhetőségének ellenőrzésével).

  • A legtöbb háttérfeladat nem elérhető: Az alkalmazásbővítmények nem végezhetnek hosszú ideig futó háttérfeladatokat, kivéve a feltöltés vagy letöltés kezdeményezését, amelyet alább tárgyalunk.

  • AirDrop tiltott: Az alkalmazásbővítmények nem fogadhatnak (de küldhetnek) adatokat az AirDrop használatával.

Háttérben történő feltöltés/letöltés

Az egyetlen háttérben végezhető feladat a feltöltés/letöltés, a NSURLSession object használatával.

A feltöltési/letöltési feladat kezdeményezése után a bővítmény befejezheti a gazdalkalmazás kérését, és a feladat eredményére gyakorolt hatás nélkül befejezhető. Ha a kiterjesztés nem fut a háttérfeladat befejezésekor, a rendszer a háttérben elindítja a tartalmazó alkalmazást, és meghívja az alkalmazás application:handleEventsForBackgroundURLSession:completionHandler: delegate metódusát.

Az alkalmazásnak, amelynek kiterjesztése a háttérben NSURLSession feladatot kezdeményez, rendelkeznie kell egy megosztott tárolóval, amelyet mind a tartalmazó alkalmazás, mind a kiterjesztése elérhet.

Gondoskodjon arról, hogy a tartalmazó alkalmazásnak és minden egyes alkalmazásbővítményének különböző háttérmunkameneteket hozzon létre (minden háttérmunkamenetnek egyedi azonosítóval kell rendelkeznie). Ez azért fontos, mert egy háttérmunkamenetet egyszerre csak egy folyamat használhat.

Action vs. Share

Az Action és a Share kiterjesztések közötti különbségek a kódoló szemszögéből nem teljesen egyértelműek, mert a gyakorlatban nagyon hasonlóak. Az Xcode sablonja a megosztás kiterjesztés célpontjához a SLComposeServiceViewController-t használja, amely egy szabványos kompozíciós nézeti felhasználói felületet biztosít, amelyet használhat a közösségi megosztáshoz, de nem kötelező. A megosztási kiterjesztés közvetlenül az UIViewController-től is örökölhet egy teljesen egyéni kialakításhoz, ugyanúgy, ahogyan az Action kiterjesztés is örökölhet a SLComposeServiceViewController-től.

A kétféle kiterjesztés közötti különbség abban van, hogy hogyan kell használni őket. Az Action bővítménnyel olyan bővítményt hozhat létre, amelynek nincs saját felhasználói felülete (például egy olyan bővítményt, amelyet a kiválasztott szöveg lefordítására és a fordításnak a gazdalkalmazásba való visszaküldésére használnak). A Megosztás bővítmény segítségével közvetlenül a gazdalkalmazásból oszthat meg megjegyzéseket, fényképeket, videókat, hanganyagokat, linkeket és egyebeket. A UIActivityViewController mind az Action, mind a Share kiterjesztéseket vezérli, ahol a Share kiterjesztések a felső sorban színes ikonokként, az Action kiterjesztések pedig az alsó sorban monokróm ikonokként jelennek meg (2.1. kép).

Tiltott API-k

A fejlécfájlokban a NS_EXTENSION_UNAVAILABLE makróval vagy hasonló, elérhetetlenséget jelző makróval jelölt API-k nem használhatók (pl: HealthKit és EventKit UI keretrendszerek az iOS 8-ban nem használhatók egyetlen alkalmazásbővítményben sem).

Ha egy alkalmazás és egy bővítmény között közös kódot használ, akkor szem előtt kell tartania, hogy egy olyan API-ra való hivatkozás is, amely nem engedélyezett az alkalmazásbővítmény számára, az alkalmazás elutasításához vezet az App Store-ból. Ezt úgy is kezelhetjük, hogy a közös osztályokat hierarchiává alakítjuk, közös szülővel és különböző alosztályokkal a különböző célokhoz.Egy másik lehetőség a preprocesszor #ifdef ellenőrzésekkel történő használata. Mivel még mindig nincs beépített célfeltétel, sajátot kell létrehozni.

Egy másik szép megoldás a saját beágyazott keretrendszer létrehozása. Csak győződj meg róla, hogy nem tartalmaz semmilyen, a kiterjesztések számára elérhetetlen API-t. Egy alkalmazásbővítmény beágyazott keretrendszer használatára való konfigurálásához navigáljon a célpont építési beállításaihoz, és állítsa a “Require Only App-Extension-Safe API” beállítást Yes-re. Az Xcode projekt konfigurálásakor a Fájlok másolása építési fázisban a “Frameworks”-t kell kiválasztani a beágyazott keretrendszer célpontjaként. Ha a “SharedFrameworks” célállomást választja, az App Store el fogja utasítani a beadványát.

Egy megjegyzés a visszafelé kompatibilitásról

Bár az alkalmazásbővítések csak az iOS 8 óta állnak rendelkezésre, az alkalmazást tartalmazó alkalmazást elérhetővé teheti a korábbi iOS-verziók számára.

Apple Human Interface Compliance

Az alkalmazásbővítés tervezésekor tartsa szem előtt az Apple iOS Human Interface Guidelines (Apple iOS emberi interfészre vonatkozó iránymutatásai). Biztosítania kell, hogy az alkalmazásbővítménye univerzális legyen, függetlenül attól, hogy a tartalmazó alkalmazás milyen eszközt támogat. Annak biztosításához, hogy az alkalmazásbővítmény univerzális legyen, használja az Xcode-ban a célzott eszközcsalád-építési beállítást az “iPhone/iPad” érték megadásával (néha univerzálisnak nevezik).

Következtetés

Az alkalmazásbővítményeknek egyértelműen a leglátványosabb hatása van az iOS 8-ban. Mivel a készülékek 79%-a már használja az iOS 8-at (az App Store 2015. április 13-i mérése szerint), az alkalmazásbővítmények hihetetlen funkciók, amelyeket az alkalmazásoknak ki kell használniuk. Az API korlátozásainak és a bővítmények és az azokat tartalmazó alkalmazás közötti adatmegosztás módjának kombinálásával úgy tűnik, hogy az Apple-nek sikerült megoldania a platformmal kapcsolatos egyik legnagyobb panaszt anélkül, hogy a biztonsági modelljét veszélyeztetné. Továbbra sincs mód arra, hogy a harmadik féltől származó alkalmazások közvetlenül megosszák egymással az adataikat. Bár ez egy nagyon új koncepció, nagyon ígéretesnek tűnik.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.