voorafgaand aan iOS 7 waren ontwikkelaars vrij beperkt in wat ze konden doen toen hun apps de voorgrond verlieten. Afgezien van VOIP en locatie-gebaseerde functies, de enige manier om code uit te voeren op de achtergrond was om achtergrond taken te gebruiken, beperkt tot het uitvoeren van een paar minuten. Als u een grote video wilt downloaden om offline te bekijken, of een back-up van de foto ‘ s van een gebruiker naar uw server wilt maken, kunt u slechts een deel van het werk voltooien.
iOS 7 voegt twee nieuwe API ‘ s toe voor het bijwerken van de gebruikersinterface en de inhoud van uw app op de achtergrond. De eerste, Background Fetch, stelt u in staat om nieuwe inhoud van het netwerk op regelmatige tijdstippen op te halen. De tweede, externe meldingen, is een nieuwe functie die gebruik maakt van pushmeldingen om een app te melden wanneer een gebeurtenis heeft plaatsgevonden. Beide nieuwe mechanismen helpen u om de interface van uw app up-to-date te houden, en kunnen werk plannen aan de nieuwe Background Transfer Service, waarmee u out-of-process netwerk overdrachten (downloads en uploads) uit te voeren.
background Fetch en Remote Notifications zijn eenvoudige application delegate hooks met 30 seconden wandklok tijd om werk uit te voeren voordat uw app wordt opgeschort. Ze zijn niet bedoeld voor CPU-intensief werk of langlopende taken, in plaats daarvan, ze zijn voor het in de wachtrij zetten van langlopende netwerkverzoeken, zoals een grote film downloaden, of het uitvoeren van snelle inhoud updates.
vanuit het perspectief van een gebruiker is de enige voor de hand liggende verandering in multitasking de nieuwe app-switcher, die een momentopname van de gebruikersinterface van elke app weergeeft zoals het was toen het de voorgrond verliet. Maar er is een reden om de snapshots weer te geven – u kunt nu de snapshot van uw app bijwerken nadat u achtergrondwerk hebt voltooid, waarbij een voorbeeld van nieuwe inhoud wordt weergegeven. Apps voor sociale netwerken, nieuws of weer kunnen nu de nieuwste content weergeven zonder dat de gebruiker de app hoeft te openen. We zullen later zien hoe we de snapshot kunnen updaten.
Background Fetch
Background Fetch is een soort slimme polling mechanisme dat het beste werkt voor apps die regelmatig inhoud updates, zoals social networking, nieuws, of weer apps. Het systeem ontwaakt de app op basis van het gedrag van een gebruiker, en is bedoeld om de achtergrond haalt voorafgaand aan de gebruiker de lancering van de app triggeren. Bijvoorbeeld, als de gebruiker altijd een app gebruikt om 13: 00, het systeem leert en past zich aan, het uitvoeren van fetches voorafgaand aan de gebruiksperioden. Achtergrond fetches worden samengevoegd tussen apps door de radio van het apparaat om het batterijgebruik te verminderen, en als u meldt dat er geen nieuwe gegevens beschikbaar waren tijdens een fetch, iOS kan aanpassen, met behulp van deze informatie om fetches op rustige tijden te voorkomen.
De eerste stap in het inschakelen van Background Fetch is om aan te geven dat u de functie in de UIBackgroundModes
sleutel in uw info plist zult gebruiken. De makkelijkste manier om dit te doen is om de nieuwe mogelijkheden tab in Xcode 5 ‘ s project editor, die een achtergrond modi sectie bevat voor eenvoudige configuratie van multitasking opties.
als alternatief kunt u de sleutel handmatig bewerken:
<key>UIBackgroundModes</key><array> <string>fetch</string></array>
Vervolgens, vertel iOS hoe vaak je wilt ophalen:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ ; return YES;}
het standaard fetch-interval is nooit, dus je moet een tijdsinterval instellen of de app zal nooit op de achtergrond worden aangeroepen. De waarde UIApplicationBackgroundFetchIntervalMinimum
vraagt het systeem om zo vaak mogelijk te beheren wanneer uw app wordt gewekt, maar u dient uw eigen tijdsinterval op te geven als dit niet nodig is. Een weer-app kan bijvoorbeeld alleen de omstandigheden per uur bijwerken. iOS wacht op zijn minst het opgegeven tijdsinterval tussen het ophalen van de achtergrond.
als uw applicatie een gebruiker toestaat uit te loggen, en u weet dat er geen nieuwe gegevens zullen zijn, kunt u minimumBackgroundFetchInterval
terugzetten naar UIApplicationBackgroundFetchIntervalNever
om een goede burger te zijn en bronnen te besparen.
de laatste stap is het implementeren van de volgende methode in uw application delegate:
- (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 ;}
hier kunt u werken wanneer u door het systeem wordt gewekt. Vergeet niet dat u slechts 30 seconden hebt om te bepalen of nieuwe inhoud beschikbaar is, om de nieuwe inhoud te verwerken en om uw gebruikersinterface bij te werken. Dit zou genoeg tijd moeten zijn om gegevens van het netwerk op te halen en een paar miniaturen voor je gebruikersinterface op te halen, maar niet veel meer. Wanneer uw netwerkverzoeken zijn voltooid en uw gebruikersinterface is bijgewerkt, moet u de handler voor voltooiing bellen.
de handler voor voltooiing dient twee doeleinden. Ten eerste meet het systeem de kracht die door uw proces wordt gebruikt en registreert het of nieuwe gegevens beschikbaar waren op basis van het UIBackgroundFetchResult
argument dat u hebt doorgegeven. Ten tweede, wanneer u belt de voltooiing handler, een momentopname van uw UI wordt genomen en de app switcher wordt bijgewerkt. De gebruiker zal de nieuwe inhoud zien wanneer hij of zij van apps wisselt. Deze voltooiing handler snapshotting gedrag is gemeenschappelijk voor alle van de voltooiing handlers in de nieuwe multitasking API ‘ s.
in een real-world applicatie moet u de completionHandler
doorgeven aan subcomponenten van uw applicatie en bellen wanneer u gegevens hebt verwerkt en uw gebruikersinterface hebt bijgewerkt.
op dit punt vraagt u zich misschien af hoe iOS de gebruikersinterface van uw app kan snapshoten wanneer deze op de achtergrond wordt uitgevoerd, en hoe de levenscyclus van de applicatie werkt met Background Fetch. Als uw app momenteel wordt onderbroken, zal het systeem het wakker maken voordat u application: performFetchWithCompletionHandler:
belt. Als uw app niet actief is, zal het systeem het opstarten en de gebruikelijke delegatiemethoden aanroepen, waaronder application: didFinishLaunchingWithOptions:
. U kunt denken aan het als de app draait op precies dezelfde manier alsof de gebruiker het vanaf springplank had gelanceerd, behalve de gebruikersinterface is onzichtbaar, gerenderd offscreen.
in de meeste gevallen voert u hetzelfde werk uit wanneer de toepassing op de achtergrond wordt gestart als op de voorgrond, maar u kunt achtergrondlanceringen detecteren door te kijken naar de applicationState
eigenschap van UIApplication:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ NSLog(@"Launched in background %d", UIApplicationStateBackground == application.applicationState); return YES;}
Testing Background Fetch
er zijn twee manieren waarop u een background fetch kunt simuleren. De makkelijkste methode is om uw toepassing uit te voeren van Xcode en klik op simulate Background Fetch onder Xcode ‘ s Debug menu terwijl uw app wordt uitgevoerd.
u kunt ook een schema gebruiken om te wijzigen hoe Xcode uw app uitvoert. Kies Onder het Xcode-menu-item Product schema en vervolgens schema ‘ s beheren. Vanaf hier kunt u een nieuw schema bewerken of toevoegen en het selectievakje starten vanwege een fetch-gebeurtenis op de achtergrond zoals hieronder weergegeven.
meldingen op afstand
met meldingen op afstand kunt u uw app waarschuwen wanneer belangrijke gebeurtenissen plaatsvinden. U kunt nieuwe chatberichten te leveren, breaking news alerts te verzenden, of de laatste aflevering van uw gebruiker favoriete TV-show klaar voor hem of haar te downloaden voor offline bekijken. Meldingen op afstand zijn geweldig voor sporadische maar onmiddellijk belangrijke inhoud, waar de vertraging tussen achtergrond ophalen niet aanvaardbaar is. Meldingen op afstand kunnen ook veel efficiënter zijn dan Background Fetch, omdat uw applicatie alleen wordt gestart wanneer dat nodig is.
een remote Notification is eigenlijk gewoon een normale Push notificatie met de content-available
vlag ingesteld. U kunt een push sturen met een waarschuwingsbericht om de gebruiker te informeren dat er iets is gebeurd, terwijl u de gebruikersinterface op de achtergrond bijwerkt. Maar meldingen op afstand kunnen ook stil zijn, zonder waarschuwingsbericht of geluid, alleen gebruikt om de interface van uw app bij te werken of achtergrondwerk te activeren. U kunt dan een lokale melding plaatsen wanneer u klaar bent met het downloaden of verwerken van de nieuwe inhoud.
Stille pushmeldingen zijn beperkt, dus wees niet bang om er zoveel te verzenden als uw applicatie nodig heeft. iOS en de APN-servers bepalen hoe vaak ze worden geleverd, en je zult niet in de problemen komen voor het verzenden van te veel. Als uw pushmeldingen worden beperkt, kunnen ze worden uitgesteld tot de volgende keer dat het apparaat een keep-alive-pakket verzendt of een andere melding ontvangt.
meldingen op afstand verzenden
om een melding op afstand te verzenden, stelt u de vlag voor inhoud beschikbaar in een payload voor pushmeldingen. De content-beschikbare vlag is dezelfde sleutel die wordt gebruikt om Kiosk apps te melden, dus de meeste push scripts en bibliotheken ondersteunen al meldingen op afstand. Wanneer u een melding op afstand verzendt, wilt u mogelijk ook gegevens opnemen in de payload van de melding, zodat uw toepassing naar de gebeurtenis kan verwijzen. Dit kan u een paar netwerkverzoeken besparen en de reactiesnelheid van uw app verhogen.
ik raad aan om Nomad CLI ‘ S Houston utility te gebruiken om pushberichten te sturen tijdens het ontwikkelen, maar je kunt je favoriete bibliotheek of script gebruiken.
u kunt Houston installeren als onderdeel van de Nomad-cli ruby gem:
gem install nomad-cli
en stuur vervolgens een notificatie met het apn-hulpprogramma dat is opgenomen in Nomad
# Send a Push Notification to your Deviceapn push <device token> -c /path/to/key-cert.pem -n -d content-id=42
Hier geeft de -n
vlag aan dat de inhoud-beschikbare sleutel moet worden opgenomen, en -d
stelt ons in staat om onze eigen gegevenstoetsen toe te voegen aan de lading.
de resulterende melding payload ziet er als volgt uit:
{ "aps" : { "content-available" : 1 }, "content-id" : 42}
iOS 7 voegt een nieuwe applicatie delegeren methode, die wordt genoemd wanneer een push-melding met de inhoud-beschikbare sleutel wordt ontvangen:
- (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);}
opnieuw wordt de app op de achtergrond gestart en krijgt u 30 seconden om nieuwe inhoud op te halen en de gebruikersinterface bij te werken, voordat u de voltooiingshandler aanroept. We kunnen een snelle netwerk verzoek uit te voeren zoals we deden in de achtergrond Fetch voorbeeld, maar laten we gebruik maken van de krachtige nieuwe Background Transfer Service om een grote download taak te vragen en te zien hoe we onze UI kunnen updaten wanneer deze is voltooid.
Nsurlsession and Background Transfer Service
terwijl NSURLSession
een nieuwe klasse is in iOS 7, verwijst het ook naar de nieuwe technologie in de netwerkvorming van de Stichting. Ter vervanging van NSURLConnection
blijven bekende concepten en klassen zoals NSURL
, NSURLRequest
en NSURLResponse
behouden. U zult werken met NSURLConnection
’s vervanger, NSURLSessionTask
, om netwerkverzoeken te doen en hun antwoorden af te handelen. Er zijn drie soorten sessietaken-data, download en upload-die elk syntactische suiker toevoegen aan NSURLSessionTask
, dus u moet de juiste gebruiken voor uw use case.
An NSURLSession
coördineert een of meer van deze NSURLSessionTask
s en gedraagt zich volgens de NSURLSessionConfiguration
waarmee het is gemaakt. U kunt meerdere NSURLSession
s aanmaken om gerelateerde taken met dezelfde configuratie te groeperen. Om te interageren met de Background Transfer Service, maak je een sessieconfiguratie met . Taken die aan een achtergrondsessie zijn toegevoegd, worden uitgevoerd in een extern proces en gaan door, zelfs als uw app is opgeschort, crasht of wordt gedood.Met
NSURLSessionConfiguration
kunt u standaard HTTP-headers instellen, cachebeleid configureren, het gebruik van mobiele netwerken beperken en meer. Een optie is de discretionary
– vlag, waarmee het systeem taken kan plannen voor optimale prestaties. Wat dit betekent is dat uw transfers alleen over Wifi gaan wanneer het apparaat voldoende stroom heeft. Als de batterij bijna leeg is of alleen een mobiele verbinding beschikbaar is, wordt uw taak niet uitgevoerd. De discretionary
vlag heeft alleen effect als het sessieconfiguratieobject is geconstrueerd door de backgroundSessionConfiguration:
methode aan te roepen en als de achtergrondoverdracht wordt gestart terwijl uw app zich op de voorgrond bevindt. Als de overdracht wordt gestart vanaf de achtergrond zal de overdracht altijd in discretionaire modus worden uitgevoerd.
nu weten we een beetje over NSURLSession
, en hoe een achtergrond sessie werkt, laten we terugkeren naar ons voorbeeld van kennisgeving op afstand en wat code toevoegen om een download te vragen op de background transfer service. Wanneer de download is voltooid, zullen we de Gebruiker informeren dat het bestand beschikbaar is voor gebruik.
NSURLSessionDownloadTask
laten we eerst een melding op afstand afhandelen en een NSURLSessionDownloadTask
opvragen over de background transfer service. In backgroundURLSession
maken we een NURLSession
met een achtergrondsessie configuratie en voegen we onze application delegate toe als de session delegate. De documentatie adviseert niet om meerdere sessies met dezelfde identifier te starten, dus gebruiken we dispatch_once
om mogelijke problemen te voorkomen:
- (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);}
We maken een downloadtaak met behulp van de NSURLSession
klasse methode en configureren de aanvraag, en bieden een beschrijving voor later gebruik. U moet niet vergeten aan te roepen om de taak daadwerkelijk te starten, aangezien alle sessietaken in de opgeschorte toestand beginnen.
nu moeten we de NSURLSessionDownloadDelegate
methoden implementeren om callbacks te ontvangen wanneer de download voltooid is. Het kan ook nodig zijn om NSURLSessionDelegate
of NSURLSessionTaskDelegate
methoden te implementeren als u authenticatie of andere gebeurtenissen in de sessiecyclus moet afhandelen. U moet Apple ‘ s document Life Cycle van een URL-sessie met aangepaste gedelegeerden raadplegen, waarin de volledige levenscyclus van alle soorten sessietaken wordt uitgelegd.
geen van de NSURLSessionDownloadDelegate
gedelegeerde methoden zijn optioneel, hoewel de enige waar we actie moeten ondernemen in dit voorbeeld is. Wanneer de taak klaar is met Downloaden, wordt u voorzien van een tijdelijke URL naar het bestand op de schijf. U moet verplaatsen of kopiëren van het bestand naar de opslag van uw app, als het zal worden verwijderd uit de tijdelijke opslag wanneer u terugkeert van deze delegeren methode.
#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{}
als uw app nog steeds op de voorgrond draait wanneer de achtergrondsessie is voltooid, is bovenstaande code voldoende. In de meeste gevallen, echter, uw app zal niet worden uitgevoerd, of het zal worden opgeschort in de achtergrond. In deze gevallen moet u twee methoden voor het delegeren van toepassingen implementeren, zodat het systeem uw toepassing kan wekken. In tegenstelling tot eerdere delegate callbacks, wordt de Application delegate twee keer aangeroepen, omdat uw sessie-en taakdelegaties meerdere berichten kunnen ontvangen. De app delegate methode application: handleEventsForBackgroundURLSession:
wordt aangeroepen voordat deze NSURLSession
delegate berichten worden verzonden, en URLSessionDidFinishEventsForBackgroundURLSession
wordt daarna aangeroepen. In de eerste methode slaat u een achtergrond completionHandler
op, en in de laatste belt u deze om uw gebruikersinterface bij te werken:
- (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(); }}
dit proces in twee fasen is nodig om uw app UI bij te werken als u nog niet op de voorgrond wanneer de achtergrond overdracht voltooid. Bovendien, als de app helemaal niet draait wanneer de achtergrond overdracht is voltooid, iOS zal het starten in de achtergrond, en de voorgaande toepassing en sessie delegeren methoden worden aangeroepen na application:didFinishLaunchingWithOptions:
.
configuratie en beperking
we hebben het kort gehad over de kracht van achtergrondoverdrachten, maar u moet de documentatie bekijken en kijken naar de NSURLSessionConfiguration
opties die het beste uw use case ondersteunen. Bijvoorbeeld, NSURLSessionTasks
ondersteunt resource time-outs via de NSURLSessionConfiguration
’s timeoutIntervalForResource
eigenschap. U kunt dit gebruiken om aan te geven hoe lang u wilt toestaan dat een overdracht wordt voltooid voordat u volledig opgeeft. U kunt dit gebruiken als uw inhoud slechts voor een beperkte tijd beschikbaar is, of als het niet downloaden of uploaden van de bron binnen de gegeven tijdinterval geeft aan dat de gebruiker niet over voldoende Wifi-bandbreedte.
naast downloadtaken ondersteunt NSURLSession
uploadtaken volledig, zodat u mogelijk een video op de achtergrond naar uw server uploadt en uw gebruiker ervan verzekert dat hij of zij de app niet langer draaiende hoeft te laten, zoals mogelijk in iOS 6. Een leuke touch zou zijn om de eigenschap sessionSendsLaunchEvents
van uw NSURLSessionConfiguration
in te stellen op NO
, als uw app niet hoeft te worden gestart op de achtergrond wanneer de overdracht is voltooid. Efficiënt gebruik van systeembronnen houdt zowel iOS als de gebruiker tevreden.
ten slotte zijn er een aantal beperkingen in het gebruik van achtergrondsessies. Aangezien een gedelegeerde vereist is, kunt u de eenvoudige blokgebaseerde callback methoden op NSURLSession
niet gebruiken. De lancering van uw app op de achtergrond is relatief duur, dus HTTP-omleidingen worden altijd genomen. De background transfer-service ondersteunt alleen HTTP en HTTPS en u kunt geen aangepaste protocollen gebruiken. Het systeem optimaliseert overdrachten op basis van beschikbare middelen en u kunt uw overdracht niet te allen tijde op de achtergrond afdwingen.
merk ook op dat NSURLSessionDataTasks
helemaal niet wordt ondersteund in achtergrondsessies, en u dient deze taken alleen te gebruiken voor korte, kleine verzoeken, niet voor downloads of uploads.
samenvatting
de krachtige nieuwe multitasking-en netwerkapi ‘ s in iOS 7 bieden een hele reeks mogelijkheden voor zowel nieuwe als bestaande apps. Denk aan de use cases in uw app die kunnen profiteren van out-of-process netwerkoverdrachten en verse gegevens, en maak het meeste uit deze fantastische nieuwe API ‘ s. In het algemeen, implementeren achtergrond overdrachten alsof uw toepassing wordt uitgevoerd op de voorgrond, het maken van de juiste UI-updates, en het grootste deel van het werk is al voor u gedaan.
-
gebruik de juiste nieuwe API voor de inhoud van je app.
-
wees efficiënt, en call voltooiing handlers zo vroeg mogelijk.
-
voltooiing handlers update UI snapshot van uw app.
verder lezen
-
WWDC 2013 session “Wat is er nieuw met Multitasking”
-
WWDC 2013 sessie “Wat is er nieuw in Foundation Networking”
-
URL Loading System Programming Guide