11 Data Offline and Sync
Mobile app developers can use the Data Offline and Sync features to build a client app that enables the users to perform critical tasks when offline.
You can use the following APIs to build applications that cache REST resources for offline use and then synchronize all offline changes with the server when the device goes online again.
API | Platforms | Features |
---|---|---|
Sync Express |
|
|
Synchronization |
|
|
Building Apps that Work Offline Using Sync Express
The Javascript and Cordova client SDKs feature Sync Express, which enables you to easily and quickly make your application work offline using your existing REST requests. You can use this library for REST APIs where the resource name alternates between plural nouns and singular resource identifiers (rid), such as /items/{rid}/subitems/{rid
}.
Add Sync Express to Your App
Install the cordova-plugin-file
When an application attempts to store more REST resources than the device’s cache size allows, Sync Express throws a QUOTA_EXCEEDED_ERR
exception. With Cordova apps, you can install the cordova-plugin-file to increase the device’s cache size. This plugin isn’t available for JavaScript web apps.
Configure Your App to Use Sync Express
To enable Sync Express, add a syncExpress
entry to oracle_mobile_cloud_config.js
, and use path
elements in the policies
array to identify the endpoints that you want to activate Sync Express for. The name that you use for a path parameter must exactly match the name of the property that uniquely identifies a returned object. Use a colon to identify the path parameter, such as :deptId
. Note that a configuration file can have a syncExpress
entry for Sync Express or a sync
entry for the Synchronization library, but it can’t have both.
Note:
Synchronization is not fully supported by the Cordova SDK or the JavaScript SDK. It is only fully supported in the Android and Java SDKs.
Let’s say, for example, that you want to activate Sync Express for all calls to these endpoints:
-
/departments
-
/departments/{deptId}
The department database object has these properties:
deptId: number
name: string
The response object for a department collection looks like this:
[
{
"deptId": 1,
"name": "Department 1"
},
{
"deptId": 2,
"name": "Department 2"
}
]
The corresponding syncExpress
entry would look like this. Notice that you need only one entry in the configuration file to activate Sync Express for both endpoints.
var mcs_config = {
"logLevel": mcs.LOG_LEVEL.INFO,
"mobileBackend": {
"name": "myBackend",
...
}
"syncExpress": {
"policies": [
{
"path": '/mobile/custom/myApi/departments/:deptId(\\d+)?'
}
]
}
};
Now let’s say, for example, that you want to include calls to endpoints with subcollections (nested entities), such as an employees within a department:
-
/departments
-
/departments/{deptId}
-
/departments/{deptId}/employees
-
/departments/{deptId}/employees/{empId}
The employee database object has these properties:
deptId: number
empId: number
name: string
The response object for an employee collection looks like this:
[
{
"empId": 1,
"name": "John Doe"
},
{
"empId": 2,
"name": "Jane Doe"
}
]
The corresponding syncExpress
entry would look like this. Notice that you need only one entry in the configuration file to activate Sync Express for all the endpoints.
var mcs_config = {
"logLevel": mcs.LOG_LEVEL.INFO,
"mobileBackend": {
"name": "myBackend",
...
}
"syncExpress": {
"policies": [
{
"path": '/mobile/custom/myApi/departments/:deptId(\\d+)/:_employees?/:empId(\\d+)?'
}
]
}
};
Sync Express provides some regular expressions for formulating the path specification:
-
Use a colon (:) plus the property name to indicate either a path parameter or the name of the property that uniquely identifies each returned object (or both). For example, for the
/departments
endpoint, you must include:deptId(\\d+)
in the path specification to indicate the unique identifier for a department resource, even if the API didn’t have a/mobile/custom/myAPI/departments/{deptId}
endpoint. -
Use a question mark (
?
) to indicate that the path parameter is optional. -
When a path segment represents a collection of children resources (a subcollection), then you must precede the parameter name with a colon and an underscore (
:_
) so that Sync Express stores the response objects in the client cache as children objects that are associated with the parent object. -
By default, Sync Express assumes that the path parameter is a string. Use
(\\d+)
to indicate that the path parameter must be a numeric value.
For example, given the /mobile/custom/myApi/departments/:deptId(\\d+)/:_employees?/:empId(\\d+)?
path specification:
-
:deptId
specifies a path parameter and also provides the name of the property in the department object that uniquely identifies a department. -
The
?
after:deptId(\\d+)
indicates that this and subsequent parameters are not required. Thus, the path specification applies to these endpoints:-
/mobile/custom/myApi/departments
-
/mobile/custom/myApi/departments/{deptId}
-
/mobile/custom/myApi/departments/{deptId}/employees
-
/mobile/custom/myApi/departments/{deptId}/employees/{empId}
-
-
(\\d+)
indicates that the path parameter value must be numeric. If the object’sdeptId
property is a string, then you’d use/mobile/custom/myApi/departments/:deptId?
instead. -
(:_employees)
identifies a subcollection and indicates that all response objects must be stored in the client cache as children of the specifieddeptId
.
Configure Your App to Handle items Arrays
If any response bodies wrap a collection in an items
property, such as "items":[{"id:":33},{"id:":34}]
, then you must add the Oracle REST handler to the syncExpress
entry in the configuration file, as shown in the following example:
var mcs_config = {
"logLevel": mcs.LOG_LEVEL.INFO,
"mobileBackend": {
"name": "myBackend",
...
}
"syncExpress": {
"handler": "OracleRestHandler",
"policies": [
{
"path": '/mobile/custom/myApi/departments/:deptId(\\d+)?'
}
]
}
};
Building Apps that Work Offline Using the Synchronization Library
Use the Synchronization library from Android and iOS mobile apps to enable the app users to continue to use the app when offline.
What Can I Do with the Synchronization Library?
When developing Android and iOS client apps, you, as a mobile app developer, might often take these goals into consideration:
-
Enable updates to app data on mobile devices when connectivity is intermittent or non-existent.
-
Improve performance by minimizing the amount of calls and data transported over the wire.
The client SDK’s Synchronization library, with its data caching, support for offline operations, and automated synchronization, enables you to achieve these goals when you access custom API resources. In addition, through declarative policies, you can design caching and synchronization policies for your custom APIs that you can apply across your apps, and adjust without having to modify code.
Enable Edits to App Data When the Mobile Device Is Offline
As an example of how you can use the Synchronization library to enable app users to read, create, update, and delete data when the mobile device is offline, consider some apps that are designed for the Fix it Fast (FiF) company, which maintains in-house appliances. The mobile app developer wants to ensure that the apps continue to work even when there is no internet connection. For example:
-
A customer uses an FiF mobile app to fill out the details for an incident report regarding a basement furnace. She then goes to the basement to take a picture of the furnace's barcode, attaches it to the report, and taps Send. Even though there’s no internet connection in the basement, the app should enable the customer to access, change, and send the incident report. As soon as the device reconnects to the internet, the app should transmit the report and the attached photo to the server.
-
During the day, a technician reviews her job list, sorts the jobs by priority, driving distance, and issue type, and adjusts the priorities as needed. As she completes a job, she attaches notes to the incident report, and she updates the job status. She expects to be able to do all these tasks even when she doesn't have access to the internet. When her device is connected, she expects the app to synchronize her offline modifications with the server, first synchronizing the essential information, such as job status, and then synchronizing the less essential information, such as her notes.
-
After an unexpectedly long repair, the technician lowers the priority for customer that is the furthest away, John Doe. Because she is offline, her modifications are stored in the offline edits in the local cache. During the time she was offline, John Doe called the office to report that his water heater was now leaking, and the office changed his priority to high. When the technician goes back on line, the app synchronizes the updates, and sees that there is a conflict. The app pops up a notice about the conflict and asks the technician if she still wants to lower the priority.
To implement these data offline requirements, the mobile app developer uses the Synchronization library to fetch and update data, and sets the appropriate fetch, update, and conflict resolution policies in the configuration file.
-
To ensure that incident reports from the
/incidents
resource are always available, that they can be modified while offline, and that the server is updated with queued offline modifications as soon as the device resumes access, the mobile app developer sets the following policies for the resource:-
Fetch policy: Fetch resources from the server when the client application is online, and fetch them from the local cache when the app is offline (
FETCH_FROM_SERVICE_IF_ONLINE
). -
Update policy: Queue updates if offline and synchronize automatically when the client app is back online (
QUEUE_IF_OFFLINE)
).
-
-
To ensure that two technicians don't inadvertently update the same status or priority for an
/incidentstatus
resource due to queued offline updates, the mobile app developer sets the following policy:-
Conflict resolution policy: Don’t overwrite the server’s version with the local version if there’s a conflict. The edited local version is kept in the offline edits in the local cache, and the mobile app handles the conflict (
PRESERVE_CONFLICT
).
This assumes that the code for this custom API returns the ETag that is used to detect conflicts, and uses the
sync.setItem
andsync.addItem
custom code SDK methods to build the response. -
Improve Performance
As an example of how you can use the Synchronization library to improve performance, consider the FiF apps that we discussed previously.
-
Before leaving the office every morning, the technicians start an FiF app on their tablets, and pull a list of their jobs for the day. Because the customer information such as name, phone, and address is static, the app can cache that data upon startup and not re-retrieve it during the day to improve performance. Other information, such as incident status and priority, must be kept current.
-
Expired data needs to be cleared whenever the app is restarted.
-
The finance department designed an API that supplies a customer's default credit card information. Because the information is fairly static, mobile apps might consider caching that information to improve performance. However, the finance department wants to ensure that mobile apps never cache that information.
To implement these performance requirements, the mobile app developer uses the Synchronization library to fetch and update data, and sets the appropriate fetch, expiration, and eviction policies in the configuration file.
-
To cache the information from the
/customer
resource so that it's retrieved from the server on startup, and, after that from the local cache only, the mobile app developer sets the following policies:-
Expiration policy: Mark resources as expired when the client application restarts (
EXPIRE_ON_RESTART
). -
Eviction policy: Delete expired resources from the local cache when the client application restarts (
EVICT_ON_EXPIRY_AT_STARTUP
). -
Fetch policy: Fetch resource from the server only if it isn’t in the local cache or is expired (
FETCH_FROM_SERVICE_ON_CACHE_MISS_OR_EXPIRY
).
-
-
To ensure that the priority and status from the
/incidentstatus
resource is always available, but stays as current as possible:-
Fetch policy: Fetch resources from the server when the client application is online, and fetch them from the local cache when the app is offline (
FETCH_FROM_SERVICE_IF_ONLINE
). -
Eviction policy: Delete expired resources from the local cache when the client application restarts (
EVICT_ON_EXPIRY_AT_STARTUP
). -
Expiration policy: Mark a resource as expired when the client application restarts. Update the local cache with the latest version from the server the next time the client application calls the resource (
EXPIRE_ON_RESTART
).
-
-
To ensure that none of the information from the
/creditcards
resource is cached, the custom code that implements this API makes sure that all HTTP responses include theOracle-Mobile-Sync-No-Store
header set totrue
.
Synchronization Library Process Flow
To help you understand how the parts fit together, here’s an explanation of how the Synchronization library does the following:
-
Manages objects in the local cache
-
Uses synchronization policies to retrieve resources from either the local cache or the server
-
Handles object updates
When the mobile app makes a request through the Synchronization library to get data from a custom API, the Synchronization library looks at the fetch policy setting to determine whether to get the objects from the server or the local cache. Whenever the Synchronization library fetches objects from the server, it refreshes the local cache with the newly fetched objects.
Depending on the policy settings, the Synchronization library might also periodically refresh expired items in the local cache using a background process.
When the user edits an object, the following occurs depending on whether the mobile device is online or offline:
-
Online edit: An update request is sent to the server.
-
Offline edit: The edited object is stored in the offline edits in the local cache. When the app goes online, a background process sends a request to update the resource on the server.
If the conflict resolution policy is CLIENT_WINS
, the update request includes an If-Match
header of *
so that the server updates the resource without conflict. Otherwise the request includes an If-Match
header that is set to the ETag that was last returned by the server.
Video: Overview of the Data Offline & Synchronization API
To learn more about how the Synchronization library uses caching to enable a client app to work offline as well as improve performance, take a look at this video:
Android Synchronization Library
This section shows how to use the Synchronization library to implement several of the common data offline tasks for working with a custom API’s resources.
For detailed information about the library, see Oracle Mobile Hub's Android SDK Reference.
Tip:
The client SDK download page contains anexamples
zip, which contains the source code for the SalesPlus app. This app illustrates many of the synchronization features that are described in this section.
Fetch Resources
After you set up your app to work with data offline, you use the mobile endpoint class to open endpoints to custom code API resources, and you use fetch builders to synchronize data retrieval and modifications with the local cache automatically. A fetch builder enables you to specify how to fetch the data, and then enables you to execute the fetch.
Fetch Filtered Resources
You might have an app that filters which items it displays. For example, an FiF app might want to display all incidents with a status of new
. When the device is online, your code can fetch the items as mobileResource
objects, convert the objects to JSON objects, and then filter the items. However, when the device is offline, your app can’t filter the mobileResource
objects in the local cache because the objects are just blobs of data. The solution is to use a custom MobileObject
. When you do this, the local cache stores the data in a table with a column for each of the custom object’s fields, which enables your mobile app to query data in the local cache based on field values. We’ll use the incident list in the FiF example to illustrate how to do this. In this example, the users must be able to filter the incident list by status.
When you open a mobile endpoint on a custom MobileObject
class, you can use the fetch builder’s queryFor
method to specify the filter to use in the local cache. Note that this method is for filtering JSON objects from the local cache. It doesn’t affect the way that the Synchronization library retrieves results from the server. Whenever you execute the fetch builder, the library first looks at the fetch policy setting to determine whether to refresh the local cache. If the policy specifies that it must refresh the local cache from the server, then it retrieves all the objects, regardless of the filter that you specify using the queryFor
method. Regardless of the fetch policy and whether it refreshed the local cache, the library then uses the queryFor
method to filter the data in the local cache, and return the filtered results. That is, regardless of whether the device is online or offline, and regardless of whether the library fetches data from the server or uses the local cache, the queryFor
method filters the results based on the query property and value.
Specify Which Resources to Synchronize First
When a mobile app reconnects with the internet, the library synchronizes the local cache with the server. If you want the library to synchronize some resources before others, such as statuses before images, then pin the resources with the applicable priorities.
MobileResource
class’ pinResource
method to set a resource’s priority (MobileFile
, MobileObject
, and MobileObjectCollection
inherit from this class). builder.execute(new MobileEndpointCallback(){
@Override
public void onComplete(Exception exception, MobileResource mobileResource) {
mobileResource.pinResource(PinPriority.High);
}
});
Change a Resource’s Synchronization Policies
When you fetch a resource, the Synchronization library saves with the resource object the synchronization policies that are specified in the configuration file. These saved policies are associated with that resource object for its lifetime. You can change these saved policies when you fetch the data and before you add, update, or delete a resource.
Change a Fetch Builder’s Synchronization Policy
You can use the fetch builder’s synchronization policy to override an endpoint’s configured policies. When the library fetches the resource from the server, it saves the fetch builder’s policy settings with the resource.
Change a Resource Object’s Synchronization Policy
Sometimes, you’ll need to change the synchronization policy for a mobile resource object (such as a mobile object, mobile collection, or mobile file) before you send an add, update, or delete to the server. This example sets the mobile resource object’s conflict resolution policy to CONFLICT_RESOLUTION_POLICY_CLIENT_WINS
.
Detect and Handle Conflicts
When the conflict resolution policy that is in affect for a resource is PRESERVE_CONFLICT
, the Synchronization library doesn’t overwrite the server’s version with the local version if there’s a conflict. Instead, an edited version is kept in the offline edits in the local cache, and the mobile app is responsible for handling the conflict, such as programmatically merging the two versions.
A conflict occurs when the object on the server was updated after you retrieved it, and thus is no longer the version that you tried to update. For example, Mary uses her app to change an incident status at 4:00 p.m. However, her device is offline, so the change is stored in the offline edits in the local cache. At 4:30, Tom updates the same incident. At 5:00, Mary’s device reconnects with the internet, and the Synchronization library automatically sends Mary’s offline edit to the server. The server responds with a 412 Precondition Failed
status to indicate the conflict.
When a conflict happens, the library marks the modified object as having conflicts, and it makes available both the modified object (from the offline edits in the local cache), and the current server version to enable you to handle the conflict in your code.
If the device is online when the library sends an update or delete to the server, then the mobile app can handle the conflict as soon as it receives the response. However, when the user makes edits when the device is offline, there’s no way to know if there are conflicts. You can't check for conflicts until the device reconnects and the library synchronizes the offline edits with the server. There are two ways to detect and handle conflicts that occur when a device reconnects:
- Detect and handle conflicts after the library finishes synchronizing offline edits with the server.
- Detect and handle conflicts when the library sends the offline edit to the server (when the device is online).
Detect Conflicts After the Library Completes Synchronization
You can detect and handle conflicts after the library finishes synchronizing offline edits with the server. After the library finishes synchronizing all offline edits, it calls this method for each offline edit that it synchronized.
-
Use the
offlineResourceSynchronized
method, as shown here. In this example, the only mobile endpoint that the mobile app accesses is theincidents
endpoint. The example shows how to handle both custom and genericMobileObject
objects.synchronization.offlineResourceSynchronized(new SyncResourceUpdatedCallback() { @Override public void onResourceUpdated(String uri, MobileResource mobileResource) { if (mobileResource == null) { Log.i("offlineResourceSync", "Resource for " + uri + "deleted from cache after offline synchronization"); return; } String result = null; if (mobileResource.hasConflict()) { result = "with conflicts"; } else if (mobileResource.hasOfflineUpdates()) { result = "with offline update"; } else if (mobileResource.hasOfflineCommitError()) { result = "with error"; } else { result = "successfully"; } // If you created a custom MobileObject class, you can access properties directly if (mobileResource instanceof IncidentCustomMobileObject) { IncidentCustomMobileObject anIncident = (IncidentCustomMobileObject) mobileResource; Log.i("offlineResourceSync", "Offline edits for " + anIncident.getTitle() + " finished with result :" + result); // Incident has been synchronized with the service object. // You can show a pop up or reload the resources in the UI, // such as in the main thread. } else { // Process has finished. // MobileObject/MobileFile has been synchronized with the service object. // You can show a pop up or reload the resources in the UI, // such as in the main thread. } } });
Detect Conflicts When the Library Updates the Cache
You can detect and handle conflicts when the library sends the offline edit to the server (when the device is online).
-
Use the
Synchronization
cachedResourceChanged
method to listen for online updates and deletes, as shown here. The callback for this method is called for each resource that the library updates or deletes. Typically, you use this method to detect any resource change during a background cache refresh so that you can refresh the UI with the change. However, you also can use this method to detect and handle conflicts when the library synchronizes the offline edits. Note that the callback is not called when the library adds a new resource to the local cache.Don’t initialize
CachedResourceChanged
more than once during the lifetime of the application.In this example, the only mobile endpoint that the mobile app accesses is the
incidents
endpoint. The example shows how to handle both custom and genericMobileObject
objects.synchronization.cachedResourceChanged(new SyncResourceUpdatedCallback() { @Override public void onResourceUpdated(String uri, MobileResource mobileResource) { if (mobileResource == null) { Log.i("cachedResourceChanged", "Resource for " + uri + "deleted from cache"); return; } String result = null; if (mobileResource.hasConflict()) { result = "with conflicts"; } else if (mobileResource.hasOfflineUpdates()) { result = "with offline update"; } else if (mobileResource.hasOfflineCommitError()) { result = "with error"; } else { result = "successfully"; } // If you created a custom MobileObject class, you can access properties directly if (mobileResource instanceof IncidentCustomMobileObject) { IncidentCustomMobileObject anIncident = (IncidentCustomMobileObject) mobileResource; Log.i("cachedResourceChanged", "Cache changes for " + anIncident.getTitle() + " finished with result :" + result); // Custom object changed in local cache. You can show a pop up // or reload the resources in the UI, such as in the main thread. } else { Log.i("cachedResourceChanged", "Cache changes finished with result :" + result); // OMCMobileObject, OMCMobileFile, or OMCMobileObjectCollection // object changed in local cache. // You can show a pop up or reload the resources in the UI, // such as in the main thread. } } });
Review and Discard Offline Edits
You might want to enable a mobile user to work offline while they make their changes, and then switch back to working online when the user has completed making changes, is satisfied with the end result, and is ready for the Synchronization library to synchronize with the server. The code examples in this section show how to:
-
Switch the app to work-offline mode and switch back to work-online mode.
-
List the resources that have been changed while offline.
-
Discard all offline edits.
-
Discard a resource’s offline edits.
The Synchronization
class provides the methods for reviewing and discarding offline edits. As shown in the following steps, you use its getNetworkStatus
and setOfflineMode
methods, along with the SyncNetworkStatus
enumeration to switch the work-offline mode on and off. You use its loadOfflineResources
method to get all the offline edits that haven’t been synchronized with the server, and its discardOfflineUpdates
method to discard all offline edits.
iOS Synchronization Library
This section shows how to use the Synchronization library to implement several of the common data offline tasks for working with a custom API’s resources.
For detailed information about the library, see Oracle Mobile Hub's iOS SDK Reference.
Tip:
The client SDK download page contains anexamples
zip, which contains the source code for the SalesPlus app. This app illustrates many of the synchronization features that are described in this section.
Fetch Resources
After you set up your app to work with data offline, you use the mobile endpoint class to open endpoints to custom code API resources, and you use fetch builders to synchronize data retrieval and modifications with the local cache automatically. A fetch builder enables you to specify how to fetch the data, and then enables you to execute the fetch.
Fetch Filtered Resources
You might have an app that filters which items it displays. For example, an FiF app might want to display all incidents with a status of new
. When the device is online, your code can fetch the items as mobileResource
objects, convert the objects to JSON objects, and then filter the items. However, when the device is offline, your app can’t filter the mobileResource
objects in the local cache because the objects are just blobs of data. The solution is to use a custom MobileObject
. When you do this, the local cache stores the data in a table with a column for each of the custom object’s fields, which enables your mobile app to query data in the local cache based on field values. We’ll use the incident list in the FiF example to illustrate how to do this. In this example, the users must be able to filter the incident list by status.
When you open a mobile endpoint on a custom MobileObject
class, you can use the fetch builder’s queryForProperty
method to specify the filter to use in the local cache. Note that this method is for filtering JSON objects from the local cache. It doesn’t affect the way that the Synchronization library retrieves results from the server. Whenever you execute the fetch builder, the library first looks at the fetch policy setting to determine whether to refresh the local cache. If the policy specifies that it must refresh the local cache from the server, then it retrieves all the objects, regardless of the filter that you specify using the queryForProperty
method. Regardless of the fetch policy and whether it refreshed the local cache, the library then uses the queryForProperty
method to filter the data in the local cache, and return the filtered results. That is, regardless of whether the device is online or offline, and regardless of whether the library fetches data from the server or uses the local cache, the queryForProperty
method filters the results based on the query property and value.
Specify Which Resources To Synchronize First
When a mobile app reconnects with the internet, the library synchronizes the local cache with the server. If you want the library to synchronize some resources before others, such as statuses before images, then pin the resources with the applicable priorities.
OMCMobileResource
class’ pinResource
method to set a resource’s priority (OMCMobileFile
, OMCMobileObject
, and OMCMobileObjectCollection
inherit from this class). [builder executeFetchOnSuccess:^(OMCMobileObjectCollection *mobileObjectCollection) {
[mobileObjectCollection pinResource:High];
// Get all the objects from the collection
NSArray* objects = [mobileObjectCollection getMobileObjects];
} OnError:^(NSError *error) {
// This function is called when the request finishes with an error
}];
Change a Resource’s Synchronization Policies
When you fetch a resource, the Synchronization library saves with the resource object the synchronization policies that are specified in the configuration file. These saved policies are associated with that resource object for its lifetime. You can change these saved policies when you fetch the data and before you add, update, or delete a resource.
Change a Fetch Builder’s Synchronization Policy
You can use the fetch builder’s synchronization policy to override an endpoint’s configured policies. When the library fetches the resource from the server, it saves the fetch builder’s policy settings with the resource.
Change a Resource Object’s Synchronization Policy
Sometimes, you’ll need to change the synchronization policy for a mobile resource object (such as a mobile object, mobile collection, or mobile file) before you send an add, update, or delete to the server. This example sets the mobile resource object’s conflict resolution policy to CONFLICT_RESOLUTION_POLICY_CLIENT_WINS
.
Detect and Handle Conflicts
When the resource's conflict resolution policy is PRESERVE_CONFLICT
, the Synchronization library doesn’t overwrite the server’s version with the local version if there’s a conflict. Instead, it keeps an edited version in the offline edits in the local cache, and the mobile app is responsible for handling the conflict, such as programmatically merging the two versions.
A conflict occurs when the object on the server was updated after you retrieved it, and thus is no longer the version that you tried to update. For example, Mary uses her app to change an incident status at 4:00 p.m. However, her device is offline, so the change is stored in the offline edits in the local cache. At 4:30, Tom updates the same incident. At 5:00, Mary’s device reconnects with the internet, and the library automatically sends Mary’s offline edit to the server. The server responds with a 412 Precondition Failed
status to indicate the conflict.
When a conflict happens, the library marks the modified object as having conflicts, and the library makes available both the modified object (from the offline edits in the local cache), and the current server version to enable you to handle the conflict in your code.
If the device is online when the library sends an update or delete to the server, then the mobile app can handle the conflict as soon as it receives the response. However, when the user makes edits when the device is offline, there’s no way to know if there are conflicts. You can't check for conflicts until the device reconnects and the library synchronizes the offline edits with the server. There are two ways to detect and handle that occur when a device reconnects:
- Detect and handle the conflicts after the library finishes synchronizing offline edits with the server.
- Detect and handle conflicts when the library sends the offline edit to the server (when the device is online).
Review and Discard Offline Edits
You might want to enable a mobile user to work offline while they make their changes, and then switch back to working online when the user has completed making changes, is satisfied with the end result, and is ready for the Synchronization library to synchronize with the server. The code examples in this section show how to:
-
Switch the app to work-offline mode and switch back to work-online mode.
-
List the resources that have been changed while offline.
-
Discard all offline edits.
-
Discard a resource’s offline edits.
The OMCSynchronization
class provides the methods for working offline, and for reviewing and discarding offline edits. As shown in the following steps, you use its GetNetworkStatus
and setOfflineMode
methods, along with the SyncNetworkStatus
constants to switch the work-offline mode on and off. You use its loadOfflineResourcesOnSuccess
method to get all the offline edits that haven’t been synchronized with the server, and its discardOfflineUpdatesOnError
method to discard all offline edits. You also can discard a specific resource’s offline updates by calling the resource’s reloadResource
method.
Make Custom APIs Synchronizable
If your mobile app uses the Synchronization library to access a custom API offline, then that API should follow the sync-compatibility guidelines and should return data in a sync-compatible format. You also need to consider whether to configure synchronization policies for some or all of its resources.
The steps to design and implement a synchronization-compatible custom API are summarized in the next sections. For more detailed information, see:
Design a Synchronization-Compatible API
When you use the API Designer to create your custom API, follow these guidelines to ensure that your API is synchronization compatible.
-
The resource name should alternate between plural nouns and singular resource identifiers (rid). For example:
/items/{rid}/subitems/{rid}/
. -
For pagination, use the
limit
andoffset
query parameters so that the Synchronization library uses paged downloads correctly. If you don’t need to support pagination, then you don’t need to specify these parameters. -
Use the
orderBy
query parameter to specify sorting. For example:orderBy=propA,propB:desc,propC:asc
. -
The API must contain all the necessary endpoints to support data synchronization. For example, if you have an endpoint that returns a collection, then you must also have an endpoint that returns a specific item in the collection.
Implement a Synchronization-Compatible API
When you use implement your custom API, follow these guidelines to ensure that your API us synchronization compatible.
-
For
GET
requests, use the custom code SDK’ssetItem
andaddItem
methods in your API’s custom code to return data in a format that enables the Synchronization library to more easily cache and synchronize the data in the client’s local cache. Responses must include theOracle-Mobile-Sync-Resource-Type
header, and, for single items, theETag
header. -
For
PUT
andDELETE
requests, your code must honor theIf-Match
header as follows:-
If the header contains an ETag value, and that value doesn’t match the ETag on the server, then the code must not update or delete the item and must return a
412
HTTP response status (precondition failed) to indicate that the ETag does not match the server-side object’s ETag. -
If the header contains a value of
*
(asterisk), then the server-side's object must be replaced by the request object (or deleted for aDELETE
request).
-
-
For
PUT
requests, responses must include theOracle-Mobile-Sync-Resource-Type
andETag
headers. If the item was added, then it must include theLocation
header. For exampleLocation: /mobile/custom/incidentreport/incidents/1
. -
For
POST
requests, responses must include theOracle-Mobile-Sync-Resource-Type
,Location
, andETag
headers. -
When you need to control data caching from the server side, use the
Oracle-Mobile-Sync-Evict
,Oracle-Mobile-Sync-Expires
, andOracle-Mobile-Sync-No-Store
headers to override client side configuration.
Configure Synchronization Policies for the Custom API
When you define the synchronization policies in the configuration file, consider the custom API’s resources that you’ll access, and determine which, if any, need special synchronization policy configuration.
Say, for example, that your default fetch policy is FETCH_FROM_SERVICE_ON_CACHE_MISS
. The custom API might have a resource for which the mobile app always needs the most current data. In that case, you can use the configuration file to specify the FETCH_FROM_SERVICE_IF_ONLINE
fetch policy for that specific resource. Note that you can define synchronization policies at the default level and the resource level, and that you can override these programmatically.
Synchronization Policies
The Synchronization library uses several types of synchronization policies:
-
Conflict Resolution Policies define how to handle offline edits if the server’s version changed after the initial data was fetched from the server. For example, if another client updated a resource, you might want the app’s updates to overwrite the other client’s update.
-
Eviction Policies designate when to delete expired resources in the local cache. For example, you might want the app to delete all expired resources when the app starts. Expiration and eviction policies work together to keep stale resources from cluttering the cache. You can also use them to prevent users seeing out-of-date data and, by inference, potentially harmful data. Note that these policies apply only to resources in the local cache, not to server-side resources.
-
Expiration Policies define how and when the Synchronization library marks resources stored in the local cache as out-dated or stale. For example, you might want all the resources to expire when the app is restarted so that the app fetches the latest version of a resource from the server the first time the app uses it in that session. The expiration policy only marks data, allowing you the option to display stale data if the app is offline. To delete data, use the eviction policy.
-
Fetch Policies define how the Synchronization library determines whether to retrieve resources from the local cache or from the server. For example, if the resource changes frequently, you might choose to always retrieve it from the server unless the client is offline.
-
Update Policies define what to do if the app modifies resources when the device is offline. For example, you might want the app to put all changes that are made while the device is offline in a queue and then synchronize the changes with the server when the device goes online again.
In addition to configuring the synchronization policies, you also can configure the cache settings for a mobile backend. You can configure the maximum size of the cache and you can specify when and how to perform background cache refreshes. See Synchronization Configuration Elements.
You can specify synchronization policies for custom API resources at several levels:
-
In the app’s configuration file, you can specify default synchronization policies for all custom API endpoints that the library accesses through a specific mobile backend.
-
In the app’s configuration file, you can specify synchronization policies for specific custom API endpoints.
-
In the custom API implementation, you can specify a resource’s synchronization policies in a response header.
-
In the app, you can specify a resource’s synchronization policies when you fetch the data.
-
In the app, you can specify a resource’s synchronization policies when you add, update, or delete the resource.
When the Synchronization library fetches a resource from the server, it sets the resource's synchronization policies according to your configuration, and then saves those policies with the resource. When you configure a policy at more than one level, the library uses precedence rules to determine which policy level to use. For example, a response-header policy setting takes precedence over a fetch builder’s policy setting. If a policy isn’t set at the response header or fetch builder level, then the library uses the policy’s setting from the configuration file. First, the library looks for the policy setting for the path that matches the fetch builder's endpoint. When there isn’t a policy for the endpoint, then it uses the configuration file’s default policy. If a policy isn’t specified at any level, then the Synchronization library’s hard-coded default policy is used. The actual rules are somewhat more complex than summarized here. For complete details see Synchronization Policy Levels and Precedence.
When the library does an automatic refresh, it always uses the FETCH_POLICY_FETCH_FROM_SERVICE
fetch policy. For all other policies, the refresh process honors the response header values, if present, and, when not present, it uses the policies that were saved with the resource.
When you fetch a resource and the library uses the resource from the cache instead of from the server, then the resource's policies are not necessarily the policies that you configured for the object's endpoint. For example, if the resource was fetched using a fetch collection builder, then the resource's policies are the collection endpoint’s policies and not the object’s endpoint policies. Thus, you can't be sure what the resource's policies are. A cached resource’s policies depend on whether it was originally fetched from the server as part of a collection, as an object, or as part of a refresh.
Define Synchronization Policies and Cache Settings in the Configuration File shows how to configure default policies for the mobile backend and for endpoints (paths). Define Synchronization Policies and Cache Settings in a Response Header shows how a custom API can use headers to control whether the response is cached, when it should expire in the local cache, and when it should be evicted. The following platform-specific topics show how to get and change a fetch builder’s policies and get and change a mobile resource’s policies programmatically:
Video: Introduction to the Data Offline & Sync Policies
If you want a high-level understanding of how to use synchronization policies to drive data offline and synchronization capabilities, take a look at this video:
Synchronization Policy Options
Here are the Synchronization library’s policy options for each policy type.
Conflict Resolution Policies
Conflict resolution policies define what to do if, when updating a resource, it’s discovered that the server version was updated after it was last requested. Say, for example, that the client app retrieved a resource on startup. Soon after, someone else updated the resource on the server. If the resource is then updated on the client app, you might want the client updates to overwrite the updates made by someone else.
Policy | Description |
---|---|
|
Instructs the Synchronization library to overwrite the server’s version with the local version regardless of whether there is a conflict. |
|
Instructs the Synchronization library to not overwrite the server’s version with the local version if there’s a conflict. The edited version is kept in the offline edits in the local cache, and the mobile app is responsible for handling the conflict, such as programmatically merging the two versions. |
SERVER_WINS |
Instructs the Synchronization library to not overwrite the server’s version with the local version if there’s a conflict. The edited version is removed from the offline edits in the local cache. |
Eviction Policies
Eviction policies designate when expired resources in the local cache will be deleted. For example, you could set the eviction policy to EVICT_ON_EXPIRY_AT_STARTUP
so expired items are deleted when the app starts. Keep in mind that if a user didn’t use the app for several days and it’s offline when it starts, the local cache could get cleared.
These policies apply to resources in the local cache only, not to server-side resources.
Policy | Description |
---|---|
|
Instructs the Synchronization library to delete expired resources from the local cache when the client application restarts, and update the local cache with the server copy the next time it's called by the client application. This can result in an empty cache, but this is appropriate if the latest resource is required. |
|
Instructs the Synchronization library that resources can’t be deleted from the local cache automatically. To evict resources manually, use an API. |
Expiration Policies
Expiration policies define how and when the Synchronization library marks resources stored in the local cache as out-dated or stale. For example, if your resources change frequently, then you can set the policy to EXPIRE_ON_RESTART
to ensure that the local cache gets cleared periodically, and thus does not become too large.
Policy | Description |
---|---|
|
Instructs the Synchronization library to mark a resource as expired when the client application restarts. The Synchronization library updates the local cache with the latest version from the server the next time it's called by the client application. |
|
Instructs the Synchronization library to mark resources as expired after the specified time (in seconds) set for the |
|
Instructs the Synchronization library that resources in the local cache can’t be marked as expired. |
Fetch Policies
Fetch policies define how the Synchronization library determines whether to retrieve resources from the local cache or from the server. For example:
-
If your data doesn’t change often, like a contact’s photo, then a good choice for the fetch policy is
FETCH_FROM_SERVICE_ON_CACHE_MISS_OR_EXPIRY
with anEXPIRE_AFTER
expiration policy set to a suitable timeout. -
If data will change very frequently and you always want the most current data, but cached data is acceptable if the user is offline, then use
FETCH_FROM_SERVICE_IF_ONLINE
.
Note that setting the noCache
property to true
in the configuration file, as described in Synchronization Configuration Elements, tells the Synchronization library to ignore fetch policies and to not add data to the local cache.
Policy | Description |
---|---|
|
Instructs the Synchronization library to fetch resources from the local cache only, not from the server. Because the Synchronization library retrieves resources directly from the cache, this policy can be carried out whether the client application is online or offline. If a resource is not in the local cache, then the Synchronization library returns null. |
|
Instructs the Synchronization library to always fetch resources directly from the server, not from the local cache. The library can only apply this policy when the client application is online. If the app is offline, the Synchronization library returns null. |
|
Instructs the Synchronization library to fetch resources from the server when the client application is online, and to fetch them from the local cache when the app is offline. |
|
Instructs the Synchronization library to fetch resources from the local cache if it is present. If a collection is empty, or if the requested object isn’t in the local cache, then the Synchronization library fetches it from the server. If the app is offline, then the Synchronization library returns null. |
|
Instructs the Synchronization library to fetch resources from the local cache if they are present and not expired. Make sure to set If a collection is empty or has expired, or if the resource isn’t in the local cache or has expired, then the Synchronization library fetches it from the server. If the app is offline, then it returns null. |
|
Instructs the Synchronization library to fetch resources from the local cache and schedule a background refresh to update the cache with the latest version from the server. If a resource is not in the local cache, then the Synchronization library returns null. |
|
Instructs the Synchronization library to fetch resources from the local cache if they exist and are not expired, and schedule a background refresh to update the cache with the latest version from the server. If a resource is not in the local cache or has expired, then the Synchronization library fetches it directly from the server. If the app is offline, then it returns null. |
Update Policies
Update policies define what the app should do if a resource is updated when the client app is offline.
Policy | Description |
---|---|
|
If the client app is offline when the update request is sent, then the Synchronization library returns an error. |
|
If the client app is offline when the update request is sent, then the Synchronization library queues the operation and updates the local cache when the client app is back online. |
Video: Deep-Dive into the Data Offline & Sync Policies
If you want an overview of the ways you can configure synchronization policies, which methods take precedence, and the outcomes of the various policies, take a look at this video:
Synchronization Policy Levels and Precedence
As described in Synchronization Policy Options, there are several policy types that you can configure for custom APIs. You can configure these at the following levels, which are listed in order of precedence, from highest to lowest. Note that the order of precedence applies to both fetch and save calls to a mobile endpoint and requestWithURI
calls to a synchronization object.
-
Response-level policies: The server can use HTTP response headers to transmit expiration and eviction policies, as described in Define Synchronization Policies and Cache Settings in a Response Header. The server also can use a header to instruct the client to not cache a response. These policies take precedence over policies set for all other levels.
-
Request-level policies: For requests made through an
OMCMobileEndpoint
, you can call the fetch builder’ssetPolicy
method to set a policy at the request level. For requests made using therequestWithURI
method, you can use theSyncPolicy
object to set policies. Request-level policies take precedence over policies set at the resource and mobile-backend levels. -
Resource-level policies: In the configuration file, you can define a set of policies and associate the set with a resource path (URL). You can associate the set with a specific endpoint, or you can use wildcard characters to associate the set with a resource hierarchy (
When a policy type is defined for more than one resource level, then the precedence is:/*
applies to all resources at the same level, and/**
applies to all resources at the same level and any nested levels), as described later in this section. These policies take precedence over policies that are set at the mobile-backend level.-
A synchronization policy type that is defined for a specific endpoint takes precedence over the same policy type setting for a path that has wildcard characters. For example, if the URL is
www.baseuri.com/mobile/custom/incidentreport/incidents
, and an eviction policy is set for both/mobile/custom/incidentreport/incidents
and/mobile/custom/incidentreport/incidents/*
, then the eviction policy for/mobile/custom/incidentreport/incidents
takes precedence. -
Policies that are defined for a path that has the
/*
wildcard take precedence over policies for a path with the/**
wildcard. For example, if the URL is/mobile/custom/incidentreport/incidents/1
, and an eviction policy is set for both/mobile/custom/incidentreport/incidents/*
and/mobile/custom/incidentreport/incidents/**
, then the eviction policy for/mobile/custom/incidentreport/incidents/*
takes precedence.For information about setting resource-level policies, see Synchronization Configuration Elements.
-
-
Mobile backend-level default policies. You can override the default policies at the request, response, and resource levels. These settings take precedence over the Synchronization library default settings. For information about setting mobile backend-level default policies, see Synchronization Configuration Elements.
-
Synchronization library default settings: For custom APIs, if a policy is not set at the request, resource, or mobile-backend level, then the Synchronization library default setting is used.
Here are the default policy settings:
Setting Synchronization Library Default Value conflictResolutionPolicy
PRESERVE_CONFLICT
evictionPolicy
MANUAL_EVICTION
expirationPolicy
EXPIRE_ON_RESTART
expireAfter
Maximum integer value fetchPolicy
FETCH_FROM_SERVICE_IF_ONLINE
noCache
false
updatePolicy
QUEUE_IF_OFFLINE
Define Synchronization Policies and Cache Settings in the Configuration File
You can define the synchronization policies and cache settings programmatically, or you can use a configuration file. You typically define the policies and cache settings in the configuration file for the following reasons:
-
You can change a policy without needing to change code.
-
You can view all your policies in one place.
-
If you access the same resource from several places in your code, you can ensure that all accesses use the same policies.
The name of the configuration file differs by platform:
-
Android:
/assets/oracle_mobile_cloud_config.xml
-
iOS:
OMC.plist
- To configure the Synchronization library for the custom API resources that the backend accesses, add the elements described in the the next section to the backend's
synchronization
element in the configuration file.
Synchronization Configuration Elements
There are two types of backend synchronization
elements that you can add to a configuration file: cache settings and synchronization policy settings. You can configure the policy settings at the resource level and the backend level (default level).
Here's an example of the synchronization
section from an OMC.plist
file for iOS.
Cache Settings
To configure the cache settings for the mobile backend, add these elements in any order directly under the mobile backend’s synchronization
element. These settings affect both custom API and storage resources.
Key | Description | Default |
---|---|---|
maxStoreSize |
The maximum size of the local cache in megabytes. The Synchronization library stops storing resources when it reaches this limit. |
100 |
periodicRefreshPolicy
|
Names the policy that instructs the Synchronization library when to refresh cached resources. Use this attribute for background refreshes. You can set this to one of the following options:
|
PERIODIC_REFRESH_POLICY_REFRESH_NONE |
periodicRefreshInterval
|
Sets the interval, in seconds, for refreshing cached resources in the background. The interval should be appropriate to the policy named by the |
When the periodicRefreshPolicy is PERIODIC_REFRESH_POLICY_PERIODICALLY_REFRESH_EXPIRED_ITEMS , then the default is 120 .
|
Synchronization Policy Settings
You can add the following synchronization policy settings to the configuration file at the resource and backend default levels.
-
conflictResolutionPolicy
-
expirationPolicy
-
expireAfter
-
evictionPolicy
-
fetchPolicy
-
noCache
Resource-Level Configuration
Resource-level synchronization policies affect the resources that match the paths you configure in the policies
node (array) for the sychronization
element.
You use the path
element to identify the resource to associate the policy set with. You can begin your path with or without the forward slash (/
). You can use the path to specify a policy set for a specific endpoint, or you can use wildcard characters to associate the policy set with a hierarchy of resources:
-
If there are no wildcard characters, then the request URL must match the string exactly. For example, if
<path>
is set to/mobile/custom/incidentreport/incident
thenwww.baseuri.com/mobile/custom/incidentreport/incident
matches, butwww.baseuri.com/mobile/custom/incidentreport/incidents
does not. -
/*
matches 0 or more characters after the value in<Path>
but does not include lower resources in the hierarchy in the wildcard matching. For example, if<Path>
is set to/mobile/custom/incidentreport/incidents/*
then bothwww.baseuri.com/mobile/custom/incidentreport/incidents/report
andwww.baseuri.com/mobile/custom/incidentreport/incidents/id
match, butwww.baseuri.com/incidentreport/incidents/id/attachments
does not. -
/** matches 0 or more characters after the value in
<Path>
including resources lower in the hierarchy. For example, if<Path>
is set to/mobile/custom/incidentreport/incidents/**
, then the following match:-
www.baseuri.com/mobile/custom/incidentreport/incidents
-
www.baseuri.com/mobile/custom/incidentreport/incidents/id
-
www.baseuri.com/mobile/custom/incidentreport/incidents/id/attachments
-
Here’s an example of setting resource-level policies in an OMC.plist
file.
<key>synchronization</key>
<dict>
...
<key>policies</key>
<array>
<dict>
<key>path</key>
<string>/mobile/custom/incidentreport/technicians/**</string>
<key>fetchPolicy</key>
<string>FETCH_FROM_SERVICE_IF_ONLINE</string>
<key>expirationPolicy</key>
<string>EXPIRE_ON_RESTART</string>
<key>evictionPolicy</key>
<string>MANUAL_EVICTION</string>
<key>conflictResolutionPolicy</key>
<string>SERVER_WINS</string>
</dict>
...
</dict>
Backend-Level Configuration
Backend-level configurations set the backend's default synchronization policies, and are configured in the defaultPolicy
node (array) for the synchronization
element. You should configure a default for each policy type.
Android Example Configuration File
This Android example is an excerpt from the oracle_mobile_cloud_config.xml
file.
<mobileBackends>
<mobileBackend>
...
<synchronization>
<maxStoreSize>100</maxStoreSize>
<periodicRefreshPolicy>PERIODIC_REFRESH_POLICY_PERIODICALLY_REFRESH_EXPIRED_ITEMS</periodicRefreshPolicy>
<periodicRefreshInterval>120</periodicRefreshInterval>
<policies>
<policy>
<path>/mobile/custom/incidentreport/technicians/**</path>
<fetchPolicy>FETCH_FROM_SERVICE_IF_ONLINE</fetchPolicy>
<expirationPolicy>EXPIRE_ON_RESTART</expirationPolicy>
<evictionPolicy>MANUAL_EVICTION</evictionPolicy>
<conflictResolutionPolicy>SERVER_WINS</conflictResolutionPolicy>
</policy>
<policy>
<path>/mobile/custom/incidentreport/incidents</path>
<fetchPolicy>FETCH_FROM_SERVICE_ON_CACHE_MISS_OR_EXPIRY</fetchPolicy>
<expirationPolicy>EXPIRE_ON_RESTART</expirationPolicy>
<evictionPolicy>EVICT_ON_EXPIRY_AT_STARTUP</evictionPolicy>
<conflictResolutionPolicy>SERVER_WINS</conflictResolutionPolicy>
<updatePolicy>QUEUE_IF_OFFLINE</updatePolicy>
<expireAfter>300</expireAfter>
</policy>
</policies>
<defaultPolicy>
<fetchPolicy>FETCH_FROM_SERVICE_ON_CACHE_MISS</fetchPolicy>
<evictionPolicy>EVICT_ON_EXPIRY_AT_STARTUP</evictionPolicy>
<expirationPolicy>EXPIRE_AFTER</expirationPolicy>
<expireAfter>600</expireAfter>
<conflictResolutionPolicy>CLIENT_WINS</conflictResolutionPolicy>
<noCache>false</noCache>
</defaultPolicy>
</synchronization>
</mobileBackend>
</mobileBackends>
iOS Example Configuration File
This iOS example is an excerpt from the OMC.plist
file.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>mobileBackends</key>
<dict>
<key>myBackend/1.0</key>
<dict>
<key>synchronization</key>
<dict>
<key>maxStoreSize</key>
<integer>100</integer>
<key>periodicRefreshPolicy</key>
<string>PERIODIC_REFRESH_POLICY_PERIODICALLY_REFRESH_EXPIRED_ITEMS</string>
<key>periodicRefreshInterval</key>
<integer>120</integer>
<key>policies</key>
<array>
<dict>
<key>path</key>
<string>/mobile/custom/incidentreport/technicians/**</string>
<key>fetchPolicy</key>
<string>FETCH_FROM_SERVICE_IF_ONLINE</string>
<key>expirationPolicy</key>
<string>EXPIRE_ON_RESTART</string>
<key>evictionPolicy</key>
<string>MANUAL_EVICTION</string>
<key>conflictResolutionPolicy</key>
<string>SERVER_WINS</string>
</dict>
<dict>
<key>path</key>
<string>/mobile/custom/incidentreport/incidents</string>
<key>fetchPolicy</key>
<string>FETCH_FROM_SERVICE_ON_CACHE_MISS_OR_EXPIRY</string>
<key>expirationPolicy</key>
<string>EXPIRE_ON_RESTART</string>
<key>evictionPolicy</key>
<string>EVICT_ON_EXPIRY_AT_STARTUP</string>
<key>conflictResolutionPolicy</key>
<string>PRESERVE_CONFLICT</string>
<key>updatePolicy</key>
<string>QUEUE_IF_OFFLINE</string>
</dict>
</array>
<key>defaultPolicy</key>
<dict>
<key>fetchPolicy</key>
<string>FETCH_FROM_SERVICE_ON_CACHE_MISS</string>
<key>evictionPolicy</key>
<string>EVICT_ON_EXPIRY_AT_STARTUP</string>
<key>expirationPolicy</key>
<string>EXPIRE_AFTER</string>
<key>expireAfter</key>
<integer>600</integer>
<key>conflictResolutionPolicy</key>
<string>CLIENT_WINS</string>
<key>updatePolicy</key>
<false/>
</dict>
</dict>
...
</dict>
</plist>
Define Synchronization Policies and Cache Settings in a Response Header
When you implement a custom API, you can fine tune caching for a response by defining synchronization policies or basic cache settings in response headers.
To specify the basic synchronization and cache settings for a REST resource use the following optional HTTP headers: :
Header | Description |
---|---|
|
If set to |
|
Specifies the date and time after which the expired resource should be deleted from the local cache. Uses RFC 1123 format, for example The following synchronization policies are set for the resource object that is created from the response:
|
|
Specifies when the returned resource will be marked as expired. Uses RFC 1123 format, for example |
Get Cache Hits and Misses
The Synchronization library tracks cache hits and detects if the returned result came from the cache. Use these OMCSynchronization
methods to get data about cache hits and misses:
-
cacheHitCount
: Returns the number of cache hits. -
cacheMissCount
: Returns the number of cache misses.
How Synchronization Works with the Storage APIs
When your mobile app accesses the Storage APIs, the client SDK automatically works with the Storage library to refresh and synchronize the storage objects in the local cache. You don’t need to add any code to enable synchronization with storage.
The client SDK enforces the following synchronization policies for the Storage APIs:
-
Conflict resolution policy:
SERVER_WINS
-
Eviction policy:
EVICT_ON_EXPIRY_AT_STARTUP
-
Expiration policy:
EXPIRE_AFTER
86400
seconds (24 hours).You can use the
Sync_CollectionTimeToLive
environment policy to override the number of seconds after which a Storage object expires. This value is conveyed to the Storage library through theOracle-Mobile-Sync-Expires
response header. -
Fetch policy:
FETCH_FROM_SERVICE_IF_ONLINE
-
Update policy:
QUEUE_IF_OFFLINE
Just as with the custom API resources, you can use the configuration file to override the default cache settings for storage resources on a mobile backend basis.
The default cache settings are:
-
Maximum storage size in the local cache:
100
MB -
Periodic refresh policy: Don’t automatically refresh cached resources periodically