Add Offline Support for Your App UI

Your App UI can function even when it's disconnected from a network. To do this, you use the Oracle Offline Persistence Toolkit which enables your App UI to cache data on the client and serve it back from the cache when your device doesn't have access to the server.

The Offline Persistence Toolkit is a client-side JavaScript library that enables data caching and offline support at the HTTP request layer. This support is transparent to the user and is done through the Fetch API and an XHR adapter. HTTP requests made while the client or client device is offline are captured for replay when the connection to the server is restored.

Using the toolkit, you can configure your App UI to:
  • Download content for offline reading where connectivity isn’t available. For example, an App UI could include product inventory data that a salesperson could download and read at customer sites where connectivity isn’t available.
  • Cache content for improved performance.
  • Perform transactions on the downloaded content where connectivity isn’t available and upload the transactions when connectivity returns. The salesperson, for example, could visit a site with no Internet access and enter an order for some number of product items. When connectivity returns, the App UI can automatically send the transaction to the server.
  • Provide conflict resolution when the offline data can’t merge with the server. If the salesperson’s request exceeds the amount of available inventory, the App UI can configure a message asking the salesperson to cancel the order or place the item on back order.

Note:

It's important to implement offline caching with an understanding of the risks involved. For example, cached data can get stale and out-of-sync with what's on the server. So while caching can improve performance, you might want to use it for data that doesn't change often. Also because data is cached on the client, anybody with access to the client would have access to the data as well. So make sure you're not caching sensitive data.

To use the toolkit in your App UI, you update the App UI’s app.js file to include an OfflineHandler() function that determines the scope of data to cache, what type of caching strategy to use, and so on.

Note:

Adding offline capabilities to your App UI requires JavaScript knowledge and an understanding of the toolkit, so proceed carefully. Also, responses from REST services to your App UI must not include either the no-cache or no-store value in the Cache-Control HTTP header as these values prevent the toolkit from working properly. Work with administrators of the REST services, so that values in the Cache-Control HTTP header are configured appropriately.

The following commented app.js file demonstrates one scenario of how you might implement caching for offline capabilities. It also demonstrates how you enable the toolkit's logging capabilities while you develop the App UI that uses the toolkit. Enabling this type of logging during the development phase will help you understand what data the toolkit caches in your App UI. Disable the logging functionality when you are ready to publish your App UI in a production environment.

define([
    'vbsw/helpers/serviceWorkerHelpers',
    /**
     * Add the following entries to include the toolkit classes that you'll use. More information about these
     * classes can be found in the toolkit's API doc. See the link to the API doc in the paragraph before
     * this sample file.
     *
     */
    'persist/persistenceManager',
    'persist/defaultResponseProxy',
    'persist/fetchStrategies',
    /**
     * Add the following entry to enable console logging while you develop your app with the toolkit.
     */
    'persist/impl/logger'
],
    (ServiceWorkerHelpers, PersistenceManager, DefaultResponseProxy, FetchStrategies, Logger) => {
        'use strict';

        class AppModule {

        }

        var OfflineHandler = function () {

            /**
             * Enable console logging of the toolkit for development testing
             */
            Logger.option('level', Logger.LEVEL_LOG);
            Logger.option('writer', console);

            var options = {
                /**
                 * The following code snippets implements the toolkit's CacheFirstStrategy. This strategy
                 * checks the application's cache for the requested data before it makes a request to cache
                 * data. The code snippet also disables the background fetch of data.
                 */

                fetchStrategy: FetchStrategies.getCacheFirstStrategy({
                    backgroundFetch: 'disabled'
                }),
            };
            this._responseProxy = DefaultResponseProxy.getResponseProxy(options);
        };

        OfflineHandler.prototype.handleRequest = function(request, scope)  {
            /**
             * (Optional). Write output from the OfflineHandler to your browser's console. Useful to help
             * you understand  the code that follows.
             */
            console.log('OfflineHandler.handleRequest() url = ' + request.url + ' cache = ' + request.cache +
                ' mode = ' + request.mode);

            /**
             * Cache requests where the URL matches the scope for which you want data cached.
             */
            if (request.url.match(
                'http://localhost:1988/webApps/ifixitfaster/api')) {

                return this._responseProxy.processRequest(request);
            }
            return PersistenceManager.browserFetch(request);
        };

        OfflineHandler.prototype.beforeSyncRequestListener = (event) => {
            return Promise.resolve();
        };
        OfflineHandler.prototype.afterSyncRequestListener = (event) => {
            return Promise.resolve();
        };
        AppModule.prototype.createOfflineHandler = () => {
            /** Create the OfflineHandler that makes the toolkit cache data URLs */
            return Promise.resolve(new OfflineHandler());
        };
        AppModule.prototype.isOnline = () => {
            return ServiceWorkerHelpers.isOnline();
        };
        AppModule.prototype.forceOffline = (flag) => {
            return ServiceWorkerHelpers.forceOffline(flag).then(function () {
                /** if online, perform a data sync */
                if (!flag) {
                    return ServiceWorkerHelpers.syncOfflineData();
                }
                return Promise.resolve();

            }).catch(function (error) {
                console.error(error);
            });
        };
        return AppModule;
    });

Oracle maintains the offline persistence toolkit as an open-source project. For more information, see the toolkit's README.md and Wiki on Github at https://github.com/oracle/offline-persistence-toolkit. You can also access the API documentation directly at https://oracle.github.io/offline-persistence-toolkit/index.html.