Skip to main content

Offline Content Storage

This section describes how to use:

Web-based applications often require additional assets to function, but downloading them every time is undesirable. The JS Applet SDK offers a wide range of APIs for storing different kinds of assets.

Generally, there are four types of assets:

  • CSS & JavaScript files
  • Fonts
  • Audio-visual content (image, video, and audio files)
  • Arbitrary data (e.g., JSON files, plain text, binary data)

And the SDK also provides two different APIs:

  • sos.offline & sos.offline.cache: A file system abstraction for caching files that are removed when the applet configuration is changed or the applet is reloaded. This method is usually preferred if the files can be re-downloaded.
  • sos.fileSystem: Direct access to the file system. All files are stored permanently and are not removed when the applet configuration changes.

Using the sos.offline and sos.offline.cache APIs allows you to ship an applet without content, including only basic bootstrapping code, and load the content dynamically. The content will then be available even when the device is offline.

Caching CSS & JavaScript (sos.offline)

info

Complete API reference can be found on sos.offline

CSS and JavaScript files are specific because they must be loaded with an HTML tag. The sos.offline API methods download, save, and append the resource to the web page. When adding a file, choose a unique identifier (uid) that should not change for the resource. The file will be overwritten if another file is added with the same uid.

Loading a CSS file

import sos from '@signageos/front-applet';

sos.onReady(async () => {
await sos.offline.addFile({
// Source URL
uri: 'https://unpkg.com/normalize.css@8.0.1/normalize.css',
// Unique identifier of the resource
uid: 'normalize.css',
// Indicate that the downloaded file is a CSS file
type: sos.offline.types.css,
// After the file is downloaded, it will be appended to document.head
flags: [sos.offline.flags.append(document.head)],
});
});

Loading a JS file

import sos from '@signageos/front-applet';

sos.onReady(async () => {
await sos.offline.addFile({
// Source URL
uri: 'https://code.jquery.com/jquery-3.7.1.slim.min.js',
// Unique identifier of the resource
uid: 'jquery-3.7.1.slim.min.js',
// Indicate that the downloaded file is a JavaScript file
type: sos.offline.types.javascript,
// After the file is downloaded, it will be appended to document.body
flags: [sos.offline.flags.append(document.body)],
});
});

You can also use the headers property to add special headers that will be used to download the file.

info
  • The file URL must point to a file. If your URI leads to a redirect (e.g. from http to https), the API will not work.
  • There are some limitations for Emulator.

Loading Fonts (sos.offline)

info

Complete API reference can be found on sos.offline

Another use case (similar to CSS and JavaScript files) are fonts, as they also need to be embedded in a web page. However, fonts are special because they are not inserted using HTML tags, but using the @font-face CSS directive. Because older browsers implement this directive differently, the SDK applet set provides a unifying method that simplifies the loading of fonts.

import sos from '@signageos/front-applet';

sos.onReady(async () => {
await sos.offline.addFont({
uid: 'my-tondo-font',
fontFamily: 'tondo',
fontStretch: 'normal',
fontStyle: 'normal',
fontWeight: 'bold',
unicodeRange: 'U+0-10FFFF',
formats: {
woff2: 'https://mycms.signageos.io/fonts/tondo-woff2',
eot: 'https://mycms.signageos.io/fonts/tondo-eot',
ttf: 'https://mycms.signageos.io/fonts/tondo-ttf',
svg: 'https://mycms.signageos.io/fonts/tondo-svg',
woff: 'https://mycms.signageos.io/fonts/tondo-woff',
},
append: document.body,
});
});

Caching Audio-Visual Content or Arbitrary Data (sos.offline.cache)

info

Complete API reference can be found on sos.offline.cache

Another common use case is to download content for the applet to play while offline. The sos.offline.cache exposes a more low-level API that is reset whenever the applet is updated. This allows you to cache any assets your application needs.

import sos from '@signageos/front-applet';

sos.onReady(async () => {
const file = await sos.offline.cache.loadOrSaveFile('menu.html', 'https://demo.signageos.io/docs/menu.html');

if (!file) {
document.body.innerHTML = 'Unable to display our menu.';
return;
}

// Fetch contents of the local file
const content = await fetch(file.filePath).then((res) => res.text());

// Use the data
document.body.innerHTML = content;
});

Storing Files Permanently

info

Complete API reference can be found on sos.fileSystem

To allow more low-level file operations, the applet SDK exposes the File System API. Files created using this API are permanent and are only removed on a factory reset or file system wipeout. The file system is also shared between all applets, which means you cannot rely on any file system structure on startup because a different applet on the device could have saved files you didn't expect. To mitigate this issue, create a directory for your applet and save all files inside it.

import sos from '@signageos/front-applet';

sos.onReady(async () => {
const storageUnits = await sos.fileSystem.listStorageUnits();
const rootPath = {
filePath: '', // Empty string is used as an absolute path instead of "/"
storageUnit: storageUnits.find((s) => !s.removable), // Find internal storage
};

// This will return files previous applets saved to the device
const files = await sos.fileSystem.listFiles(rootPath);
});

File paths

interface IFilePath {
storageUnit: IStorageUnit;
filePath: string;
}

Complete file path are represented by the IFilePath interface, which specifies storageUnit and filePath. Storage unit is a object which can be retrieved from listStorageUnits() and identifies the storage unit. It also contains useful information about the unit.

interface IStorageUnit {
type: string;
capacity: number;
freeSpace: number;
usableSpace: number;
removable: boolean;
}

All devices always contain one internal storage unit (with removable: false) and zero or more external units (with removable: true).

The filePath property is an absolute path to the file, but absolute paths in applet SDK do not start with /. This means that 'content/image.png' is a valid path, while '/content/image.png' is NOT. Also the applet SDK does not support relative paths and all paths stem from the root of the file system.