Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for background fetch in iOS 7 #138

Closed
lightandshadow68 opened this issue Sep 25, 2013 · 24 comments
Closed

Support for background fetch in iOS 7 #138

lightandshadow68 opened this issue Sep 25, 2013 · 24 comments

Comments

@lightandshadow68
Copy link

lightandshadow68 commented Sep 25, 2013

I'd love to see CBL support the new background fetch feature in iOS7

@snej
Copy link
Contributor

snej commented Oct 9, 2013

The objc.io blog has a great article about iOS 7 multitasking and background fetching.

It sounds like some of the necessary calls arrive only to the app delegate, which is annoying for a library like Couchbase Lite. We'll probably have to add some new methods that app delegates will have to call in response to these.

@hermanccw
Copy link

I wonder if there is a build-in notification you can observed, just like UIApplicationWillTerminateNotification for applicationWillTerminate.

@snej
Copy link
Contributor

snej commented Oct 9, 2013

On first glance I don't see any. For example, I think we'd need to know about the call application:handleEventsForBackgroundURLSession:completionHandler, but I couldn't find a corresponding notification in UIApplication.h.

@hermanccw
Copy link

haven't look into it myself, but maybe this: UIApplicationBackgroundRefreshStatusDidChangeNotification in here: https://developer.apple.com/library/ios/documentation/uikit/reference/UIApplication_Class/Reference/Reference.html#//apple_ref/c/data/UIApplicationWillTerminateNotification

@lightandshadow68
Copy link
Author

UIApplicationBackgroundRefreshStatusDidChangeNotification indicates the user turned on or off background refresh permissions for the app in System Preferences.

One option would be to echo the app delegate call as a notification, but it would require including the completion callback as part of the info dictionary. And since more than one class can register to observe the same notification, what if more than one observer calls the completion block?

@ntodd
Copy link

ntodd commented Oct 21, 2013

I have been using CBL with background fetch for several weeks now with no issues. The replication consistently completes well under the 30s limit in my case, so that hasn't been a major issue.

- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
{
    __block BOOL newData = NO;
    [[PASync syncClient] syncWithUpdate:^(CBLReplication *replication) {
        if (replication.total > 0) {
            newData = YES;
        }
    } completion:^(NSString *state) {
        if (newData) {
            // Increment the app badge
            application.applicationIconBadgeNumber++;
            completionHandler(UIBackgroundFetchResultNewData);
        } else {
            completionHandler(UIBackgroundFetchResultNoData);
        }
    }];
}

@snej snej added the icebox label Jun 20, 2014
@jessliu jessliu modified the milestones: 1.1.0, Future Sep 10, 2014
@zgramana zgramana added ready and removed icebox labels Apr 10, 2015
@pasin pasin self-assigned this May 1, 2015
@zgramana zgramana added backlog and removed ready labels May 1, 2015
@zgramana zgramana modified the milestones: 1.2, 1.0.4 Jun 12, 2015
@zgramana zgramana added ready and removed backlog labels Jun 12, 2015
@pasin
Copy link
Contributor

pasin commented Jun 19, 2015

@jamiltz posted a blog that uses CBLReplication to fetch data in the background fetch.
http://blog.couchbase.com/ios-background-fetch-to-sync-hacker-news-stories

@pasin
Copy link
Contributor

pasin commented Jun 19, 2015

Currently CBLReplicator (one-shot) can be used in the iOS background fetch without problems.
@zgramana what would be a scope of this feature?

@snej
Copy link
Contributor

snej commented Jun 19, 2015

It looks as though this is something an app developer would need to add, since the hook has to go in the app delegate class. This snippet from James' app is a good example. So maybe this just goes into the iOS documentation, instead of being a change to CBL itself?

Somewhat more complex is background fetch that's triggered by a push notification. Do we have any samples/docs showing how to send iOS push notifications from SG?

@zgramana
Copy link
Contributor

@pasin the big challenge is when NSFileProtectionComplete is set. That will kill any chance (currently) of doing a background fetch successfully, since the cblite files will be encrypted and unusable.

There is at least one way for us to support at pull replications of this kind. First, we'd have to store the SG URL and the last sequence id in NSUserDefaults when the app is suspending (there's a short grace window before we're locked out of the database). When the background fetch delegate fires, we make a direct NSURLRequest to SG with since=[from user defaults]&include_docs=true, and store the results in a new file, which is permitted. When the user unlocks the phone and the app resumes, we can then process the pre-fetched changes feed JSON.

As far as push notification integration with SG, @tleyden used the F/OSS Uniqush service via a changes worker to do that: https://github.com/tleyden/officeradar-appserver. This part is even easier now with webhooks.

@pasin
Copy link
Contributor

pasin commented Jun 22, 2015

@zgramana, I think we would need to discuss more about the solutions, and your comment above is a good starting point for discussion.

  1. A couple of few things that are not included in the changes feeds but are required for replication so we may need to prefetch them also:
    • Revision history
    • Attachments
  2. Mapping between last sequence and the remote URL might not be enough. For example, if an application having two pull replication to the same URL but different channels would have two last sequences mapped to the same URL. Currently a last sequence id is mapped to a remote checkpoint id which is calculated from the database local UUID, remote URL, and some other sync parameters.

@zgramana zgramana added backlog and removed ready labels Jul 20, 2015
@zgramana zgramana added this to the 1.3 milestone Nov 6, 2015
@zgramana zgramana removed this from the 1.2 milestone Nov 6, 2015
@zgramana zgramana added icebox and removed backlog labels Nov 6, 2015
@snej snej modified the milestones: 1.3, 1.4 May 26, 2016
@skela
Copy link

skela commented Jun 28, 2016

Is there a way to achieve this in the current lite versions of couchbase-lite? Or any guides to that effect?
Basically hoping to get it to pull and push stuff. @ntodd 's looks cool, but I dont recognise the classes there.

@snej
Copy link
Contributor

snej commented Jun 28, 2016

The example ntodd posted just uses the regular iOS background-task API to perform replication inside the app. It's not using background networking.

In general, we can't do replication with background networking because it's much more than just a single HTTP operation. The protocol is pretty interactive and uses a series of requests/responses, so it can't run very long without the app having to run to interpret server responses.

One area where we could make use of background networking is to download individual large attachments, so if you're pulling a 300MB video the app doesn't have to stay active the whole time. But the app does have to be running to kick off each attachment download.

@skela
Copy link

skela commented Jun 28, 2016

Thanks @snej . I was specifically referring to [PASync syncClient], didn't really know what thats all about. But just to clarify, I'm just talking about uploading document changes / download document changes, not actually downloading or dealing with attachments. I'm finding that often my users make a change to something, then they immediately go to the Home screen, and my app never syncs the changes, as it looks like the replicators go to sleep immediately. Is there away to get the replicators to kick in again in the - (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
{ call ?

@ntodd
Copy link

ntodd commented Jun 28, 2016

@skela PASyncClient is just a custom class I wrote to encapsulate syncing functionality in my app. You could start and manage syncs however makes sense for you.

@skela
Copy link

skela commented Jun 28, 2016

Right, I'm basically interested in trying something like that, so just trying to figure out what yer doing inside those classes/functions. Are your replicators continous ? And do you start them up in the syncWithUpdate method, and then kill them after 30 seconds?

@snej
Copy link
Contributor

snej commented Jun 28, 2016

users make a change to something, then they immediately go to the Home screen, and my app never syncs the changes, as it looks like the replicators go to sleep immediately.

If the replicator is active when the app goes into the background, it will start an iOS background-task to let the app get CPU time until it completes. It sounds like this isn't working for your app. Please file a new issue and we'll investigate it.

@skela
Copy link

skela commented Jun 29, 2016

@snej, so you are saying that the couchbase library already uses the background-task stuff? And that if its not working, this is an issue? (I was under the assumption that all background syncing via couchbase-lite was impossible).

@snej
Copy link
Contributor

snej commented Jun 29, 2016

Yes, that’s what I’m saying.

However, CBL will not initiate syncing in the background. It only keeps the process running long enough to finish a currently-active replication.

@skela
Copy link

skela commented Jun 29, 2016

@snej, thanks again for the clarification.

@pasin pasin removed this from the 1.4.0 milestone Dec 19, 2016
@pasin pasin removed their assignment Jan 17, 2017
@djpongh djpongh added this to the 1.4.2 milestone Nov 29, 2017
@djpongh djpongh modified the milestones: 1.4.2, 1.4.x Dec 7, 2017
@lightandshadow68
Copy link
Author

Finally got back round to this while implementing badging. Used a solution similar to ntodd, in which the app delegate method calls triggers a background sync on the user's sync session object. This spins up a one-shot pull replication just for the background fetch, which operates in addition to the continuous push and pull replications that are paused when the app went into the background.

@srinadh-k
Copy link

is it working in CBL latest version? can you please provide documentation related to this?

@pasin
Copy link
Contributor

pasin commented Jan 2, 2019

@srinadh-k

What we have supported is that the replicator takes care of setting up a iOS background task automatically when the app was brought into background. When the replicator is done or the background got expired, the single shot replicator will stop and the continuous replicator will go into suspended mode. The continuous replicator will resume itself after the app is brought up foregrounded.

To implement a custom background fetch, you can just start a single shot replication when getting a push notification. To handle a push notification is out of scope of CBL. You could look at the article from Apple.

@pasin
Copy link
Contributor

pasin commented Jan 2, 2019

Regarding this issue, I don't think we will implement any features further on top of what we currently support. I'm closing this issue.

@pasin pasin closed this as completed Jan 2, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants