11

In unserer App möchten wir eine kleine Datenmenge als Antwort auf eine Push-Benachrichtigung herunterladen. Bis jetzt funktionieren Push-Benachrichtigungen reibungslos. Sie starten die App im Hintergrund und rufen didReceiveRemoteNotification auf.Asynchroner Code wird erst ausgeführt, wenn die App in der Anwendung aktiviert ist: didReceiveRemoteNotification: fetchCompletionHandler:

Das Problem ist, dass die App nach der Rückkehr dieser Methode keine CPU-Zeit mehr erhält, bis sie wieder im Vordergrund steht, so dass es keine Möglichkeit gibt, diese Daten asynchron im Hintergrund abzurufen.

Wenn ich dies auf den einfachsten Fall reduziere, kann ich immer noch keinen asynchronen Code ausführen.

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { 
    [application setApplicationIconBadgeNumber:1]; 

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     [application setApplicationIconBadgeNumber:9]; 

     completionHandler(UIBackgroundFetchResultNewData); 
    }); 
} 

Als Reaktion auf einen Stoß, startet die App im Hintergrund und das Abzeichen Zahl auf 1 gesetzt, aber die Ausweisnummer ist nicht auf 9 bis die App aus dem Home-Bildschirm gestartet wird.

Sollte iOS nicht weiterhin die App ausführen, bis der Beendigungshandler aufgerufen wird, bis zu 30 Sekunden?

In der Info.plist ist der Remote-Benachrichtigungs-Hintergrundmodus angegeben, die Push-Nutzlast enthält "content-available": "1", und ich beende die App nicht, indem ich im App-Switcher nach oben wische.

hinzuzufügen, wir Parsen mit dieser Push-Benachrichtigung senden folgenden Javascript verwenden:

Parse.Push.send({ 
    where: installationQuery, 
    data: { 
     "content-available": 1, 
    } 
}, { success: function() {}, 
    error: function(error) {} 
}); 
+0

Haben Sie das versucht: http://stackoverflow.com/questions/16295953/dispatch-after-is-limited-to-10-seconds? – anhtu

Antwort

10

zuerst ein here nehmen und sicher, dass Sie ermöglichte Push-Benachrichtigung und hinzugefügt, um den Inhalt verfügbaren Feld machen:

Verwenden von Push-Benachrichtigungen zum Starten eines Downloads Wenn Ihr Server Push-Benachrichtigungen an das Gerät eines Benutzers sendet, wenn neuer Inhalt für Ihre App verfügbar ist, können Sie das System bitten, Ihre App im Hintergrund auszuführen, damit sie mit dem Herunterladen beginnen kann der neue Inhalt sofort. Die Absicht dieses Hintergrundmodus besteht darin, die Zeitspanne zu verkürzen, die verstreicht, wenn ein Benutzer eine Push-Benachrichtigung sieht und die App den zugehörigen Inhalt anzeigen kann. Apps werden in der Regel ungefähr zur gleichen Zeit aktiviert, zu der der Benutzer die Benachrichtigung sieht, die Ihnen jedoch mehr Zeit zur Verfügung stellt, als Sie andernfalls haben könnten. Um diesen Hintergrundmodus zu unterstützen, aktivieren Sie die Option Entfernte Benachrichtigungen im Abschnitt Hintergrundmodi der Registerkarte Funktionen in Ihrem Xcode-Projekt. (Sie können diese Unterstützung auch aktivieren, indem Sie den UIBackgroundModes-Schlüssel mit dem Wert für die Remotebenachrichtigung in die Info.plist-Datei Ihrer App einfügen.) Damit eine Push-Benachrichtigung einen Downloadvorgang auslösen kann, muss die Payload der Benachrichtigung den Inhalt des verfügbaren Schlüssels enthalten Wert auf 1 gesetzt. Wenn dieser Schlüssel vorhanden ist, aktiviert das System die Anwendung im Hintergrund (oder startet sie im Hintergrund) und ruft die Anwendung des Anwendungsdelegaten auf: didReceiveRemoteNotification: fetchCompletionHandler: method. Ihre Implementierung dieser Methode sollte den relevanten Inhalt herunterladen und in Ihre App integrieren. Beim Herunterladen von Inhalten wird empfohlen, dass Sie die NSURLSession-Klasse zum Initiieren und Verwalten Ihrer Downloads verwenden. Informationen zur Verwendung dieser Klasse zum Verwalten von Upload- und Download-Aufgaben finden Sie im Leitfaden zum Programmieren des URL-Lade-Systems.

Als nächstes gibt es einen Grund, warum Sie "dispatch_after" mit 2 Sekunden Verzögerung verwenden?

Es ist möglich, dass Sie da „dispacth_after“ bis zum Ende der Laufschleife iOS nennen „denkt“ es gibt keine anstehende Arbeit, den Prozess zu tun und setzt so durch die Zeit wird der Block niemand hört geschickt schlafen es.

Ersetzen Sie es mit "dispatch_async" könnte dies lösen.

Schließlich, wenn Sie zu verzögern brauchen, sollten Sie iOS sagen Sie einige Zeit im Hintergrund benötigen, wie dies -

UIApplication *application = [UIApplication sharedApplication]; 
UIBackgroundTaskIdentifier __block backgroundTaskId = [application beginBackgroundTaskWithExpirationHandler:^{ 
    if (backgroundTaskId != UIBackgroundTaskInvalid) { 
     [application endBackgroundTask:backgroundTaskId]; 
     backgroundTaskId = UIBackgroundTaskInvalid; 
    } 
}]; 

dann arbeiten Sie Hintergrund tun. Vergessen Sie nicht, die Aufgabe zu beenden, wenn Ihre Arbeit erledigt ist. rufen Sie etwas wie -

if (backgroundTaskId != UIBackgroundTaskInvalid) { 
     [application endBackgroundTask:backgroundTaskId]; 
     backgroundTaskId = UIBackgroundTaskInvalid; 
    } 
+0

Mit einer Hintergrundaufgabe war es! Die Dispatcher_nach 2 Sekunden war nur um das Problem auf das einfachste mögliche Szenario zu reduzieren. In der Praxis verwenden wir eine dispatch_async. Aber das Hauptproblem bestand darin, dass iOS anscheinend davon ausging, dass wir ausgeführt haben, wenn der Haupt-Runloop seinen Zyklus beendet hat, und nicht, wenn der Abwicklungsabwicklungs-Handler aufgerufen wurde. Durch die Verwendung einer Hintergrundaufgabe gab uns iOS die Zeit, die erforderlichen asynchronen Vorgänge auszuführen und auszuführen. – jsmeez

Verwandte Themen