User Profile Sample: Background App Refresh

      +

      Introduction

      The ability for a mobile app to run in the background is an important element of the life cycle of a mobile application. The ability to sync data while in the background would be useful in several scenarios. Background support is platform specific and is hence not built into Couchbase Lite. However, one can easily leverage the various platform specific backgrounding capabilities to perform data sync over Couchbase Mobile.

      This tutorial will demonstrate how to -

      • Configure your iOS app for Background Fetch support

      • Setup your app to do a one-shot sync with Couchbase Sync Gateway while in the background

      We will be usiing a Swift App as an example of a Couchbase Lite enabled client.

      You can learn more about the Sync Gateway here

      Prerequisites

      This tutorial assumes familiarity with building swift apps with Xcode and with Couchbase Lite.

      • You must have completed the "user profile" tutorial on sync. If you haven’t already done so, please complete the following tutorial first

      • iOS (Xcode 11+)

        • Download latest version from the Mac App Store

        • NOTE: If you are on an older version of Xcode that you must retain for your other development needs, you can make a copy of your existing version of Xcode and install Xcode 10. So you can have multiple versions of Xcode on your Mac.

      • git (Optional) This is required if you would prefer to pull the source code from GitHub repo.

      • curl HTTP client

        • You could use any HTTP client of your choice. But we will use curl in our tutorial. Download latest version from curl website

      System Overview

      We will be working with a simple "User Profile" app which we introduced in the Fundamentals Tutorial and extended to support data sync capabilities in the Sync Tutorial.

      In this tutorial, we will be extending that app to support data sync when in the background.

      The app does the following

      • Allows users to log in and create or update his/her user profile information. The user profile view is automatically updated everytime the profile information changes in the underlying database

      • The user profile information is synced with a remote Sync Gateway which then syncs it to other devices (subject to access control and routing configurations specified in the sync function)

      • When the app is woken up in the background, it does a one-shot replication with the remote Sync Gateway

      App Installation

      Fetching App Source Code

      You have two options

      Option 1 : Git Clone

      • Clone the backgroundfetch branch of the User Profile Demo project from GitHub. Type the following command in your terminal

          git clone -b backgroundfetch https://github.com/couchbaselabs/userprofile-couchbase-mobile.git

      Option 2 : Download .zip

      • Download the User Profile Demo project from here

      Installing Couchbase Lite Framework

      • Next, we will download the latest version of Couchbase Lite 2.x framework. The Couchbase Lite iOS framework is distributed via Cocoapods, Carthage or you can download the pre-built framework. In our example, we will be downloading the pre-built version of the framework. For this, type the following in the command terminal

          cd /path/to/UserProfileDemo/content/modules/userprofile/examples
        
          sh install_11.sh

      let’s verify the installation

      Try it Out

      • Open the UserProfileDemo.xcodeproj. The project would be located at /path/to/UserProfileDemo/content/modules/userprofile/examples

        open UserProfileDemo.xcodeproj
      • Build and run the project in the simulator using Xcode

      • Verify that you see the login screen

        User Profile Login Screen Image

      Sync Gateway 2.x Installation

      Follow the steps outlined in the Sync Tutorial to install the Sync Gateway on localhost running in walrus mode.

      Note that the walrus must is a development-only mode used for testing/demonstration purposes. It must be never used in production.

      Now, let’s verify the installation

      Try it Out

      • Open a browser and enter http://localhost:4984 in the address bar

      • You should see a message similar one below

        {"couchdb":"Welcome","vendor":{"name":"Couchbase Sync Gateway","version":"2.0"},"version":"Couchbase Sync Gateway/2.0.0(832;2d8a6c0)"}

      Data Model

      There are two documents - the "user profile" type document and "university" type document. We will use the same data model as discussed in data model section of the Sync tutorial.

      Configuring App for Background App Refresh

      iOS supports several backgrounding models. One such option is Background App Refresh. According to Apple docs, Background App Refresh lets your app run periodically in the background so that it can update its content. The iOS system uses its discretion to determine when to wake up and run your app, typically by learning your app usage over time. In other words, there is no guarantee that your app will have an opportunity to run in the background. Even when provided with the opportunity, the app gets a finite amount of time to run.

      • Open the "capabilities" tab in the UserProfileDemo.xcodeproj file. Note that "Background Fetch" is enabled under the "Background models" tab

        Background Modes
      • Open the AppDelegate.swift file and locate the application:didFinishLaunchingWithOptions() function.

        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
            // Override point for customization after application launch.
            self.loadLoginViewController()
        UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
            return true
        }
      • Here we specify the periodicity at which the app should be woken up. We use a value of UIApplicationBackgroundFetchIntervalMinimum which is the smallest fetch interval supported by the system

      Implementing the Background Fetch callback

      • Open the AppDelegate.swift file and locate the application:performFetchWithCompletionHandler() function. This callback function is invoked by the system everything the app is launched in the background.

        // Support for background fetch
        func application( _ application: UIApplication,
                          performFetchWithCompletionHandler
            completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
            print(#function)
            
            // Do a one shot replication
            self.cbMgr.startOneShotPullReplicationForCurrentUser { (status) in
                completionHandler(.newData) (1)
                
            }
            
        }
        1 Invoke function on to do a one-shot replication with the Sync Gateway. Everytime the app is launched, all pending changes with the remote Sync Gateway will be synched up

      Implementing the One-shot replication

      Setting up the app for one-shot replication is very similar to continuous replication that was discussed in the Sync tutorial.

      • Open the DatabaseManager.swift file and locate the startOneShotPullReplicationForCurrentUser() function.

        func startOneShotPullReplicationForCurrentUser(completionHandler:@escaping(_ doneStatus:Bool)->Void) {
      • Let’s examine the replicator configuration

        let dbUrl = remoteUrl.appendingPathComponent(kDBName)
        let config = ReplicatorConfiguration.init(database: db, target: URLEndpoint.init(url:dbUrl))
        config.continuous =  false (1)
        config.replicatorType = .pull (2)
        config.authenticator =  BasicAuthenticator(username: user, password: password) 
        1 The"continuous" mode is set to "false" in the Replicator configuration indicating that this is a one-shot replication. In one-shot mode, the replicator goes into idle state once all pending changes are synced
        2 The "replicationType" is set to pull-only in the Replicator configuration indicating that the app will only pull changes from remote client when in the background.

      The rest of the configuration is as in the continuous replication case.

      Exercises

      Before proceeding with the exercises in this section, complete the exercises in the Sync tutorial to verify that you can sync changes between the app and Sync Gateway with the app in the foreground.

      In the following exercise, we will observe how changes made on Sync Gateway are fetched by the iOS app in the background

      • The app must be running in the simulator with the xcode debugger attached. This is important as we will use the xcode debugger for simulating background fetches.

      • Push the app in the simulator to the background. Typically you can do it with the Shift-Cmd-H key combination

      • Clear the debug console logs in xcode. This will make it easier to identify what goes on when the app is launched in the background

      • Open the command terminal and issue the following curl command to get the user profile document on the Sync Gateway via GET Document REST API

        curl -X GET \
          http://localhost:4985/userprofile/user::demo@example.com \
          -H 'Accept: application/json' \
          -H 'Cache-Control: no-cache' \
          -H 'Content-Type: application/json'
      • Your response should look something like the response below. The exact contents depends on the user profile that you provided via your mobile app.

        {
          "_attachments": {
            "blob_/image": {
              "content_type": "image/jpeg",
              "digest": "sha1-9OHO0QIk+kREiOaoMlrEg/jU4zU=",
              "length": 15110,
              "revpos": 1,
              "stub": true
            }
          },
          "_id": "user::demo@example.com",
          "_rev": "1-0b9e3efa5ec1b1596564c4db34ba28d4e618f9c5",
          "address": "",
          "email": "demo@example.com",
          "image": {
            "@type": "blob",
            "content_type": "image/jpeg",
            "digest": "sha1-9OHO0QIk+kREiOaoMlrEg/jU4zU=",
            "length": 15110
          },
          "name": "",
          "type": "user"
        }
      • In the command terminal, issue the following command to update the user profile document on the Sync Gateway via PUT Document REST API

        curl -X PUT \
          'http://localhost:4985/userprofile/user::demo@example.com?rev=1-0b9e3efa5ec1b1596564c4db34ba28d4e618f9c5' \
          -H 'Accept: application/json' \
          -H 'Cache-Control: no-cache' \
          -H 'Content-Type: application/json' \
          -d '{
          "address": "101 Main Street",
          "email": "demo@example.com",
          "image": {
            "@type": "blob",
            "content_type": "image/jpeg",
            "digest": "sha1-S8asPSgzA+F+fp8/2DdIy4K+0U8=",
            "length": 14989
          },
          "name": "priya Rajagopal",
          "type": "user",
          "university": "British Institute in Paris, University of London"
        }'
      • Launch the iOS app in the background. You will simulate this through the Xcode Debug menu to "Simulate Background Fetch"

        Simulate Background Fetch
      • Observe the console logs. You would see a set of messages indicating that the app has pulled the latest changes from the Sync Gateway

        Background Fetch Logs
      • Stop the Sync Gateway

      • Launch the app in the foreground. The user profile doc that was synced in the background will be displayed.

        App Launched into foreground

      Learn More

      Congratulations on completing this tutorial!

      This tutorial walked you through an example of how to synchronize data between Sync Gateway and Couchbase Lite enabled mobile app running in the background.

      Check out the following links for further details