@screencloud/app v1.2.2
Signage App Runtime
Install
This package is published using semantic-release and available on npm.
To install run
npm install @screencloud/app --save
Usage
The App
-class is the most convinient way of getting your app to run. You can use it in several
ways to best suit your style and handle all lifecycle events with ease.
Note that most of these events are optional, but the overall experience will be best if most events are respected.
Basic
To signalize to the player that your app has loaded successfully you need
to instantiate an App
and call its run
-method.
import {App} from "@screencloud/app";
const app = new App();
app.connect();
connect()
connects to the app-container of your screen and returns a promise. You can use this
promise to kick off your internal app logic.
app.connect().then(() => {
// your app logic goes here!
})
Responding to lifecycle-events
The App and its Container communicate via a defined set of Messages. For each incoming message from the container there
is a matching methods in App
.
The AppContainer
may for instance send a FinishMessage
to your app to announce that your app will be turned off in
favor of the next app. This message comes with a payload specifying your apps remaining duration on screen.
app.onFinish((payload) => {
// app will be turned off in payload.maximumDurationMS
// use this to gracefully fade out in time
});
Note that all lifecycle handlers are chainable, so you can set up your handlers like so:
const app = (new App())
.onInitialize((payload => {
// receive env variables and app data
})
.onPreload((payload) => {
// preload data
})
.onStart(() => {
// the app is live!
})
.onFinish(() => {
// app will turn off, fade out gracefully
})
.connect();
Alternatively you can pass in a collection of handlers into the app's constructor
const app = new App({
initialize: (payload) => {
// receive env variables and app data
},
start: () => {
// the app is live!
},
finish: (payload) => {
// app will turn off, fade out gracefully
},
});
app.connect();
Sending lifecycle events
Your app can send numerous events to the app-container of the screen. For each outgoing message from your app to
the app-container there is an emitter method like emitPreloaded()
. You can call these methods to inform the
app-container about the app's current state or to respond to incoming messages as seen above.
If your app for instance specifies in its manifest.json
that it supports preloading, then the app-container may
send a PreloadMessage
to your app, which you can handle by supplying a callback function to onPreload()
. Once
your app has finished preloading, it should inform the app-container by calling emitPreloaded()
.
const app = new App();
app.onPreload((payload) => {
// preload some data from twitter or any other api
twitter.loadSomeThings().then(() = {
// inform app-container
app.emitPreloaded();
});
})
Requesting resources
The app can utilize some of the app-container's APIs like requesting cached resources.
The available functions are prefixed with request
such as requestResource()
and always return a promise.
TODO: currently there are none of these
List of Lifecycle events
These are all available incoming events, outgoing events and resource requests an app can receive or utilize during its lifetime.
Incoming events
incoming event | handler | description |
---|---|---|
initialize | onInitialize | provides app, environment and related data to the app. Called shortly after a connection has been established. The app should respond with emitInitialized when ready. |
preload | onPreload | instructs the app to preload all required resources to run. The app should emitPreloaded when ready. The event may supply additional data as payload. |
start | onStart | the app is now visible on screen and should start to play animations as well as video and/or audio content |
show | onShow | the app container request to show a specific piece of content. This is used for long-running apps which may receive content updates during their lifetime. |
finish | onFinish | the app will terminate soon and should prepare to be shut down. A maximum duration is provided as payload. The app should respond with emitFiniching with an estimated duration and emitFinished when ready to be shut down. |
Outgoing events
outgoing event | emitter | description |
---|---|---|
initialized | emitInitialized | tells the app-container that the app is loaded and working. Should be sent after receiving an initialize -event. |
preloaded | emitPreloaded | tells the app-container that the app has finished preloading and is ready to start immediately. Should be sent after receiving a preloaded -event. |
started | emitStarted | tell the app-container that the app is visible and running. |
showing | emitShowing | informs the app-container which piece of content is currently shown. This is useful for logs and statistics. |
finishing | emitFinishing | informs the app-container that the app will be ready to shut off soon. An estimated duration should be provided as payload. |
finished | emitFinished | the app is ready to shut down immediately. |
log | emitLog | sends a log entry to be centrally stored. Using payload you can specify the severity from LogLevel.debug to LogLevel.error as well as a message. |
Resource requests
TODO: none defined yet
Debugging and testing
There are special classes provided which should simplify testing and debugging of your app.
Using MockApp
In all testing scenarios you're safe to replace App
with MockApp
. Instead of establishing a connection to a
higher level frame it will mock this connection, but otherwise behave in the exact same way. It does so by using
MockBridge
instead of the default PostMessageBridge
.
MockApp
exposes a method called fakeReceive()
, which accepts a message as the first argument and treat it the same
way it would an incoming message from the app-container.
import { IMessageHandlers, StartMessage, MessageTypes, MockApp } from "@screencloud/app";
// all incoming event handlers
const handlers: IMessageHandlers = {
start: (payload) => {
// your logic here
},
};
// set up mock app
const app = new MockApp(handlers);
// connect the app
app.connect().then(() => {
// and fake receive a start-message to kick of start-handler
app.fakeReceive<StartMessage>({
type: MessageTypes.start
})
});