objc.io

az iOS 7 előtt a fejlesztők meglehetősen korlátozottak voltak abban, hogy mit tehetnek, amikor alkalmazásaik elhagyták az előtérben. A VOIP és a helyalapú funkciók mellett az egyetlen módja annak, hogy a háttérben futtassa a kódot, a háttérfeladatok használata volt, néhány percre korlátozva. Ha nagy videót szeretne letölteni offline megtekintésre, vagy biztonsági másolatot szeretne készíteni a felhasználó fényképeiről a szerverre, akkor csak a munka egy részét tudta elvégezni.

az iOS 7 két új API-t ad hozzá az alkalmazás felhasználói felületének és tartalmának frissítéséhez a háttérben. Az első, a Background Fetch lehetővé teszi, hogy rendszeres időközönként új tartalmat töltsön le a hálózatról. A második, távoli értesítések, egy új funkció, amely kihasználja a Push értesítéseket, hogy értesítse az alkalmazást, ha esemény történt. Mindkét új mechanizmus segít az alkalmazás felületének naprakészen tartásában, és ütemezheti az új Háttérátviteli szolgáltatás munkáját, amely lehetővé teszi a folyamaton kívüli hálózati transzferek (letöltések és feltöltések) végrehajtását.

Background Fetch and Remote Notifications egyszerű alkalmazás delegált horgok 30 másodperc falióra időt, hogy végre munkát, mielőtt az alkalmazás fel van függesztve. Nem CPU-intenzív munkára vagy hosszú futó feladatokra szánják őket, inkább a hosszú távú hálózati kérések sorba állítására szolgálnak, mint például egy nagy filmletöltés, vagy gyors tartalomfrissítések végrehajtása.

a felhasználó szempontjából az egyetlen nyilvánvaló változás a multitaskingban az új app switcher, amely pillanatképet jelenít meg az egyes alkalmazások felhasználói felületéről, ahogy az az előtérben maradt. De van egy ok a pillanatképek megjelenítésére – most már frissítheti az alkalmazás pillanatképét, miután befejezte a háttérmunkát, bemutatva az új tartalom előnézetét. A közösségi hálózatok, a hírek vagy az időjárási alkalmazások mostantól a legfrissebb tartalmat jeleníthetik meg anélkül, hogy a felhasználónak meg kellene nyitnia az alkalmazást. Később meglátjuk, hogyan frissíthetjük a pillanatképet.

Background Fetch

a Background Fetch egyfajta intelligens lekérdezési mechanizmus, amely a legjobban működik azoknál az alkalmazásoknál, amelyek gyakran frissítik a tartalmat, mint például a közösségi hálózatok, a hírek vagy az időjárási alkalmazások. A rendszer a felhasználó viselkedése alapján ébreszti fel az alkalmazást, és célja, hogy háttérletöltéseket indítson az alkalmazás elindítása előtt. Például, ha a felhasználó mindig délután 1-kor használ egy alkalmazást, a rendszer tanul és alkalmazkodik, és letöltéseket hajt végre a használati időszakok előtt. A háttérletöltéseket az eszköz rádiója egyesíti az alkalmazások között az akkumulátorhasználat csökkentése érdekében, és ha azt jelenti, hogy a lekérés során nem álltak rendelkezésre új adatok, az iOS alkalmazkodni tud, ezen információk felhasználásával elkerülheti a csendes időpontokban történő lekéréseket.

a Háttérletöltés engedélyezésének első lépése annak megadása, hogy a funkciót az info plist UIBackgroundModes gombjában használja. Ennek legegyszerűbb módja az Xcode 5 projektszerkesztőjének új képességek lapjának használata, amely tartalmaz egy Háttérmódok részt a multitasking lehetőségek egyszerű konfigurálásához.

Alternatív megoldásként manuálisan is szerkesztheti a kulcsot:

<key>UIBackgroundModes</key><array> <string>fetch</string></array>

ezután mondja el az iOS-nek, hogy milyen gyakran szeretné letölteni:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ ; return YES;}

az alapértelmezett lekérési intervallum soha, ezért be kell állítania egy időintervallumot, különben az alkalmazást soha nem hívják meg a háttérben. A UIApplicationBackgroundFetchIntervalMinimum érték arra kéri a rendszert, hogy a lehető leggyakrabban kezelje az alkalmazás felébresztését, de szükség esetén meg kell adnia a saját időintervallumát. Például egy időjárási alkalmazás csak óránként frissítheti a feltételeket. az iOS legalább a megadott időintervallumot várja a háttérletöltések között.

ha az alkalmazás lehetővé teszi a felhasználó számára a kijelentkezést, és tudja, hogy nem lesz új adat, akkor érdemes a minimumBackgroundFetchInterval értéket UIApplicationBackgroundFetchIntervalNever értékre állítani, hogy jó állampolgár legyen és takarékoskodjon az erőforrásokkal.

az utolsó lépés a következő módszer megvalósítása az alkalmazásmegbízottjában:

- (void) application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{ NSURLSessionConfiguration *sessionConfiguration = ; NSURLSession *session = ; NSURL *url = initWithString:@"http://yourserver.com/data.json"]; NSURLSessionDataTask *task = ; // Start the task ;}

itt végezhet munkát, amikor a rendszer felébreszti. Ne feledje, hogy csak 30 másodperc áll rendelkezésére annak megállapítására, hogy elérhető-e új tartalom, az új tartalom feldolgozására és a felhasználói felület frissítésére. Ennek elég időnek kell lennie ahhoz, hogy adatokat gyűjtsön a hálózatról, és néhány bélyegképet szerezzen a felhasználói felületéhez, de nem sokkal többet. Amikor a hálózati kérések befejeződtek, és a felhasználói felület frissült, hívja fel a befejezéskezelőt.

a befejezési kezelő két célt szolgál. Először a rendszer méri a folyamat által használt energiát, és rögzíti, hogy az átadott UIBackgroundFetchResult argumentum alapján rendelkezésre álltak-e új adatok. Másodszor, amikor felhívja a befejezési kezelőt, pillanatkép készül a felhasználói felületről, és az alkalmazásváltó frissül. A felhasználó látni fogja az új tartalmat, amikor alkalmazásokat vált. Ez a befejezéskezelő snapshotting viselkedése az új multitasking API-k összes befejezéskezelőjére jellemző.

egy valós alkalmazásban át kell adnia a completionHandler elemet az alkalmazás alösszetevőinek, és fel kell hívnia, amikor feldolgozta az adatokat és frissítette a felhasználói felületet.

ezen a ponton elgondolkodhat azon, hogy az iOS Hogyan tudja pillanatképezni az alkalmazás felhasználói felületét, amikor a háttérben fut, és hogyan működik az alkalmazás életciklusa a Háttérletöltéssel. Ha az alkalmazás jelenleg fel van függesztve, a rendszer a application: performFetchWithCompletionHandler:hívás előtt felébreszti. Ha az alkalmazás nem fut, a rendszer elindítja azt, meghívva a szokásos delegált módszereket, beleértve a application: didFinishLaunchingWithOptions: – et. Gondolhat rá, hogy az alkalmazás pontosan ugyanúgy fut, mintha a felhasználó elindította volna a Springboardról, kivéve, hogy a felhasználói felület láthatatlan, képernyőn kívüli.

a legtöbb esetben ugyanazt a munkát hajtja végre, amikor az alkalmazás elindul a háttérben, mint az előtérben, de a háttérindításokat az UIApplication applicationState tulajdonságának megtekintésével észlelheti:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ NSLog(@"Launched in background %d", UIApplicationStateBackground == application.applicationState); return YES;}

Testing Background Fetch

kétféle módon lehet szimulálni a háttér fetch. A legegyszerűbb módszer az alkalmazás futtatása az Xcode – ból, majd az alkalmazás futása közben kattintson az Xcode hibakeresési menüjében a háttér letöltés szimulálása elemre.

Alternatív megoldásként egy séma segítségével módosíthatja az Xcode alkalmazás futtatásának módját. Az Xcode termék menüpont alatt válassza a séma, majd a sémák kezelése lehetőséget. Innen szerkesszen vagy adjon hozzá egy új sémát, és jelölje be az Indítás a háttér-lekérési esemény miatt jelölőnégyzetet az alábbiak szerint.

távoli értesítések

a távoli értesítések lehetővé teszik az alkalmazás értesítését, ha fontos események történnek. Lehet, hogy új azonnali üzeneteket kell kézbesítenie, híreket kell küldenie, vagy a felhasználó kedvenc tévéműsorának legújabb epizódja készen áll arra, hogy letöltse offline megtekintésre. A távoli értesítések nagyszerűek a szórványos, de azonnal fontos tartalomhoz, ahol a háttérletöltések közötti késés nem biztos, hogy elfogadható. A távoli értesítések sokkal hatékonyabbak is lehetnek, mint a háttér-Lekérés, mivel az alkalmazás csak szükség esetén indul el.

a távoli értesítés valójában csak egy normál Push Értesítés a content-available jelzőkészlettel. Lehet, hogy küld egy push egy figyelmeztető üzenetet tájékoztatja a felhasználót, hogy valami történt, miközben frissíti a UI a háttérben. De a távoli értesítések csendesek is lehetnek, nem tartalmaznak figyelmeztető üzenetet vagy hangot, csak az alkalmazás felületének frissítésére vagy a háttérmunka kiváltására használhatók. Ezután közzétehet egy helyi értesítést, amikor befejezte az új tartalom letöltését vagy feldolgozását.

A Csendes push értesítések aránya korlátozott, ezért ne féljen annyi küldéstől, amennyire az alkalmazásának szüksége van. az iOS és az APNS szerverek szabályozzák, hogy milyen gyakran szállítják őket, és nem fog bajba kerülni a túl sok Küldés miatt. Ha a leküldéses értesítések korlátozva vannak, előfordulhat, hogy késnek, amíg a készülék legközelebb nem küld életben tartandó csomagot, vagy újabb értesítést kap.

távoli értesítések küldése

távoli értesítés küldéséhez állítsa be a tartalom-elérhető jelzőt egy push értesítési hasznos teherben. A tartalom-elérhető jelző ugyanaz a kulcs, amelyet az Újságos alkalmazások értesítésére használnak, így a legtöbb push szkript és könyvtár már támogatja a távoli értesítéseket. Amikor távoli értesítést küld, előfordulhat, hogy bizonyos adatokat is fel szeretne venni az értesítés hasznos adatcsomagjába, hogy az alkalmazás hivatkozhasson az eseményre. Ez megtakaríthat néhány hálózati kérést, és növelheti az alkalmazás válaszkészségét.

javaslom a Nomad CLI Houston segédprogramjának használatát push üzenetek küldéséhez fejlesztés közben, de használhatja kedvenc könyvtárát vagy szkriptjét.

A nomad-cli ruby gem részeként telepítheti Houstont:

gem install nomad-cli

majd küldjön értesítést az APN segédprogrammal a Nomad

# Send a Push Notification to your Deviceapn push <device token> -c /path/to/key-cert.pem -n -d content-id=42

itt a -n jelző megadja, hogy a tartalom-elérhető kulcsot be kell vonni, és -d lehetővé teszi számunkra, hogy saját adatkulcsokat adjunk a hasznos adathoz.

az eredményül kapott értesítési hasznos teher így néz ki:

{ "aps" : { "content-available" : 1 }, "content-id" : 42}

az iOS 7 új alkalmazás-delegált módszert ad hozzá, amelyet akkor hívnak meg, amikor push értesítés érkezik a tartalom-elérhető kulccsal:

- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{ NSLog(@"Remote Notification userInfo is %@", userInfo); NSNumber *contentID = userInfo; // Do something with the content ID completionHandler(UIBackgroundFetchResultNewData);}

ismét az alkalmazás elindul a háttérben, és 30 másodpercet kap az új tartalom letöltésére és a felhasználói felület frissítésére, mielőtt felhívja a befejezési kezelőt. Gyors hálózati kérést hajthatunk végre, mint a háttér-lekérési példában, de használjuk az erőteljes új Háttérátviteli szolgáltatást egy nagy letöltési feladat lekérdezéséhez, és nézzük meg, hogyan tudjuk frissíteni a felhasználói felületet, amikor befejeződik.

NSURLSession and Background Transfer Service

míg a NSURLSession az iOS 7 új osztálya, az alapítványi hálózatépítés új technológiájára is utal. A NSURLConnection helyettesítésére szánt ismert fogalmak és osztályok, mint a NSURL, NSURLRequest és NSURLResponse megmaradnak. A NSURLConnection‘s csere, NSURLSessionTask segítségével hálózati kéréseket készíthet és kezelheti a válaszokat. A munkamenetfeladatoknak három típusa van-ADATOK, letöltés és Feltöltés–, amelyek mindegyike szintaktikai cukrot ad a NSURLSessionTask értékhez, ezért a használati esetnek megfelelőt kell használnia.

An NSURLSessionkoordinálja a NSURLSessionTask s közül egyet vagy többet, és a NSURLSessionConfiguration szerint viselkedik, amellyel létrehozták. Több NSURLSessions-t is létrehozhat a kapcsolódó feladatok azonos konfigurációjú csoportosításához. A Háttérátviteli szolgáltatással való interakcióhoz hozzon létre egy munkamenet-konfigurációt a használatával. A háttér-munkamenethez hozzáadott feladatok egy külső folyamatban futnak, és akkor is folytatódnak, ha az alkalmazás felfüggesztésre kerül, összeomlik vagy leáll.

NSURLSessionConfiguration lehetővé teszi az alapértelmezett HTTP-fejlécek beállítását, a gyorsítótár-házirendek konfigurálását, a mobilhálózat használatának korlátozását stb. Az egyik lehetőség a discretionary jelző, amely lehetővé teszi a rendszer számára a feladatok ütemezését az optimális teljesítmény érdekében. Ez azt jelenti, hogy az átutalások csak akkor mennek át a Wifi-n, ha az eszköz elegendő energiával rendelkezik. Ha az akkumulátor lemerült, vagy csak mobil kapcsolat áll rendelkezésre, a feladat nem fog futni. A discretionary jelzőnek csak akkor van hatása, ha a munkamenet konfigurációs objektumát a backgroundSessionConfiguration: metódus meghívásával hozták létre, és ha a háttérátvitel akkor kezdődik, amikor az alkalmazás az előtérben van. Ha az átvitel a háttérből indul, az átvitel mindig diszkrecionális módban fut.

most már tudunk egy kicsit a NSURLSession – ről, és arról, hogy egy háttér munkamenet hogyan működik, térjünk vissza a távoli értesítési példánkhoz, és adjunk hozzá néhány kódot a háttérátviteli szolgáltatás letöltéséhez. Amikor a letöltés befejeződött, értesítjük a felhasználót, hogy a fájl használható.

NSURLSessionDownloadTask

először is kezeljünk egy távoli értesítést, és kérjünk egy NSURLSessionDownloadTask – ot a háttérátviteli szolgáltatásra. A backgroundURLSession – ban létrehozunk egy NURLSession – et egy háttér munkamenet-konfigurációval, és hozzáadjuk az alkalmazásmegbízottunkat munkamenet-delegáltként. A dokumentáció nem javasolja több munkamenet példányosítását ugyanazzal az azonosítóval, ezért a dispatch_once – et használjuk a lehetséges problémák elkerülése érdekében:

- (NSURLSession *)backgroundURLSession{ static NSURLSession *session = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSString *identifier = @"io.objc.backgroundTransferExample"; NSURLSessionConfiguration* sessionConfig = ; session = ]; }); return session;}- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{ NSLog(@"Received remote notification with userInfo %@", userInfo); NSNumber *contentID = userInfo; NSString *downloadURLString = ]; NSURL* downloadURL = ; NSURLRequest *request = ; NSURLSessionDownloadTask *task = downloadTaskWithRequest:request]; task.taskDescription = ]; ; completionHandler(UIBackgroundFetchResultNewData);}

létrehozunk egy letöltési feladatot a NSURLSession osztály metódus segítségével, konfiguráljuk a kérését, és leírást adunk a későbbi használatra. Ne felejtse el felhívni a hívást a tevékenység tényleges elindításához, mivel az összes munkamenet-feladat felfüggesztett állapotban kezdődik.

most végre kell hajtanunk a NSURLSessionDownloadDelegate módszereket a visszahívások fogadásához, amikor a letöltés befejeződik. Előfordulhat, hogy NSURLSessionDelegate vagy NSURLSessionTaskDelegate módszereket kell végrehajtania, ha hitelesítést vagy más eseményeket kell kezelnie a munkamenet életciklusában. Olvassa el az Apple dokumentum életciklusát az URL-munkamenetről az egyéni küldöttekkel, amely elmagyarázza a munkamenet-feladatok teljes életciklusát.

a NSURLSessionDownloadDelegatedelegált módszerek egyike sem választható, bár ebben a példában csak a műveletet kell végrehajtanunk. Amikor a feladat befejezi a letöltést, egy ideiglenes URL-címet kap a lemezen lévő fájlhoz. A fájlt át kell helyeznie vagy át kell másolnia az alkalmazás tárhelyére, mivel az eltávolításra kerül az ideiglenes tárolóból, amikor visszatér erről a delegált módszerről.

#Pragma Mark - NSURLSessionDownloadDelegate- (void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{ NSLog(@"downloadTask:%@ didFinishDownloadingToURL:%@", downloadTask.taskDescription, location); // Copy file to your app's storage with NSFileManager // ... // Notify your UI}- (void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{}- (void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{}

ha az alkalmazás még mindig az előtérben fut, amikor a háttér munkamenet feladat befejeződik, a fenti kód elegendő lesz. A legtöbb esetben azonban az alkalmazás nem fut, vagy a háttérben felfüggesztésre kerül. Ezekben az esetekben két alkalmazásküldő módszert kell végrehajtania, hogy a rendszer felébressze az alkalmazást. A korábbi delegált visszahívásoktól eltérően az alkalmazásmegbízottat kétszer hívják meg, mivel a munkamenet-és a feladatmegbízottak több üzenetet is kaphatnak. Az application: handleEventsForBackgroundURLSession: app delegate metódust a NSURLSession delegate üzenetek elküldése előtt, a URLSessionDidFinishEventsForBackgroundURLSession pedig utána hívják meg. Az előbbi módszerben completionHandler hátteret tárol, az utóbbiban pedig a felhasználói felület frissítésére hívja:

- (void) application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{ // You must re-establish a reference to the background session, // or NSURLSessionDownloadDelegate and NSURLSessionDelegate methods will not be called // as no delegate is attached to the session. See backgroundURLSession above. NSURLSession *backgroundSession = ; NSLog(@"Rejoining session with identifier %@ %@", identifier, backgroundSession); // Store the completion handler to update your UI after processing session events ;}- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{ NSLog(@"Background URL session %@ finished events.\n", session); if (session.configuration.identifier) { // Call the handler we stored in -application:handleEventsForBackgroundURLSession: ; }}- (void)addCompletionHandler:(CompletionHandlerType)handler forSession:(NSString *)identifier{ if () { NSLog(@"Error: Got multiple handlers for a single session identifier. This should not happen.\n"); } ;}- (void)callCompletionHandlerForSession: (NSString *)identifier{ CompletionHandlerType handler = ; if (handler) { ; NSLog(@"Calling completion handler for session %@", identifier); handler(); }}

ez a kétlépcsős folyamat szükséges az alkalmazás felhasználói felületének frissítéséhez, ha még nem vagy az előtérben, amikor a háttérátvitel befejeződik. Továbbá, ha az alkalmazás egyáltalán nem fut, amikor a háttérátvitel befejeződik, az iOS elindítja a háttérben, és az előző alkalmazás-és munkamenet-delegált módszerek application:didFinishLaunchingWithOptions:után kerülnek meghívásra.

konfiguráció és korlátozás

röviden kitértünk a háttérátvitel erejére, de érdemes átnézni a dokumentációt, és megnézni azokat a NSURLSessionConfiguration opciókat, amelyek a legjobban támogatják a használati esetet. Például a NSURLSessionTaskstámogatja az erőforrások időtúllépését a NSURLSessionConfiguration timeoutIntervalForResource tulajdonságán keresztül. Ezzel megadhatja, hogy mennyi ideig szeretné engedélyezni az átvitel befejezését, mielőtt teljesen feladná. Ezt akkor használhatja, ha a tartalom csak korlátozott ideig érhető el, vagy ha az erőforrás letöltésének vagy feltöltésének elmulasztása a megadott időintervallumon belül azt jelzi, hogy a felhasználó nem rendelkezik elegendő Wifi sávszélességgel.

a letöltési feladatok mellett az NSURLSession teljes mértékben támogatja a feltöltési feladatokat, így a háttérben feltölthet egy videót a szerverére, és biztosíthatja a felhasználót, hogy többé nem kell elhagynia az alkalmazást, ahogy az iOS 6-ban történt. Egy jó húzás lenne, ha a sessionSendsLaunchEvents tulajdonság a NSURLSessionConfiguration a NO, ha az alkalmazás nem kell indít a háttérben, amikor az átvitel befejeződött. A rendszer erőforrásainak hatékony felhasználása mind az iOS, mind a felhasználó számára boldog.

végül van néhány korlátozás a háttér munkamenetek használatában. Mivel delegáltra van szükség, nem használhatja az egyszerű blokk alapú visszahívási módszereket NSURLSession. Az alkalmazás háttérbe állítása viszonylag drága, ezért a HTTP átirányításokat mindig elvégzik. A háttérátviteli szolgáltatás csak a HTTP-t és a HTTPS-t támogatja, és nem használhat egyéni protokollokat. A rendszer a rendelkezésre álló erőforrások alapján optimalizálja az átutalásokat, és nem kényszerítheti az átutalást a háttérben történő előrehaladásra.

azt is vegye figyelembe, hogy az NSURLSessionDataTasks nem támogatott a háttér munkamenetekben, és ezeket a feladatokat csak rövid életű, kis kérésekre szabad használni, letöltésekre vagy feltöltésekre nem.

Összegzés

az iOS 7 hatékony, új multitasking és hálózati API-jai számos lehetőséget kínálnak mind az új, mind a meglévő alkalmazások számára. Fontolja meg az alkalmazás azon felhasználási eseteit, amelyek profitálhatnak a folyamaton kívüli hálózati átvitelekből és a friss adatokból, és hozza ki a legtöbbet ezekből a fantasztikus új API-kból. Általában úgy hajtsa végre a háttérátviteleket, mintha az alkalmazás az előtérben futna, megfelelő felhasználói felület-frissítéseket hajtva végre, és a munka nagy része már megtörtént az Ön számára.

  • használja az alkalmazás tartalmához megfelelő új API-t.

  • legyen hatékony, és hívja befejezése kezelők a lehető leghamarabb.

  • a befejezési kezelők frissítik az alkalmazás felhasználói felületének pillanatképét.

további olvasmányok

  • WWDC 2013 session “Mi újság a Multitasking”

  • WWDC 2013 session “Újdonságok az Alapítvány Hálózatépítésében”

  • URL betöltő rendszer programozási útmutató

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

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