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
)
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.
- 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)
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
)
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.
- Text-based data
- Videos
- Image
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;
});
import sos from '@signageos/front-applet';
sos.onReady(async () => {
const file = await sos.offline.cache.loadOrSaveFile('video.mp4', 'https://demo.signageos.io/docs/video.mp4');
if (!file) {
document.body.innerHTML = 'Failed to load the video.';
return;
}
await sos.video.play(file.filePath, 0, 0, 1920, 1080);
});
import sos from '@signageos/front-applet';
sos.onReady(async () => {
const file = await sos.offline.cache.loadOrSaveFile('image.png', 'https://demo.signageos.io/docs/image.png');
if (!file) {
document.body.innerHTML = 'Failed to load the image.';
return;
}
const image = new Image();
image.src = file.filePath;
document.body.append(image);
});
Storing Files Permanently
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.