Core Concepts¶
Lifecycle of a Mini App¶
Since your mini app is running in a hosted environment, it is important to understand the lifecycle in order for proper integration to occur. The following image illustrates this lifecycle in general.
Events generated by the Host App¶
There are certain events that are generated by the host app that are necessary to be handled by your mini app:
onData- This event occurs once after your mini app has loaded and when the AQ Host app sends additional information that is relevant in the current invocation of your mini app. (ex. the current user). Most of the time, the data passed by this event is necessary for the setup of your mini app (ex. different setup depending on the type of user invoking your mini app). Data with the following JSON schema is passed when this event is invoked:
{ "$schema": "http://json-schema.org/draft-04/schema#", "definitions": { "userInfo": { "type": "object", "properties": { "id": { "type": "string" }, "displayName": { "type": "string" }, "avatarBig": { "type": "string", "format": "uri" }, "avatarSmall": { "type": "string", "format": "uri" } }, "required": [ "id", "displayName", "avatarBig", "avatarSmall" ] } }, "type": "object", "properties": { "source": { "$ref": "#/definitions/userInfo" }, "engagementSource": { "$ref": "#/definitions/userInfo" }, "engagementInfo": { "type": "object" }, "opponent": { "$ref": "#/definitions/userInfo" }, "isSinglePlayer": { "type": "boolean" }, "isSoundMuted": { "type": "boolean" }, "hasTargetScore": { "type": "boolean" }, "difficultyLevel": { "type": "integer", "minimum": 1, "maximum": 5 } }, "required": [ "shouldWin", "source", "engagementSource", "isSinglePlayer", "isSoundMuted", "hasTargetScore", "difficultyLevel" ] }Fields are described as follows:
source- User info of current user playing the mini appengagementSource- User info of user who created the instance of the mini appengagementInfo- Variable data specific to the mini app.opponent- User info of the opponent.hasTargetScore- Instructs the mini app whether to ignore whatever target score array is passed in theengagementInfofield of the JSON data.isSinglePlayer- If true, mini app should setup game play for single player mode, otherwise mini app should setup the game in multiplayer mode.isSoundMuted- Initial sound state of your mini app. If true, mini app should mute all sounds at start of game play. The sound state can change within the lifetime of the mini app through theonAppStateChangeevent.difficultyLevel- The difficulty level of game play ranging from 1 (easiest) to 5 (hardest). Normally, there are arrays in theengagementInfofield which usually corresponds to a particular difficulty level (ex. target core, speed, etc.) which should be treated as parameters in defining how difficult a level should be.An example of the data passed by
onDatais as follows:{ "source": { "id": "some_id", "displayName": "Bob", "avatarBig": "http://example.com/example.jpg", "avatarSmall": "http://example.com/example.jpg" }, "engagementSource": { "id": "some_id", "displayName": "Alice", "avatarBig": "http://example.com/example.jpg", "avatarSmall": "http://example.com/example.jpg" }, "engagementInfo": { "choice": 0, "betAmount": 5, "targetScore": [10, 20, 40, 80, 100] }, "opponent": { "id": "some_id", "displayName": "Carol", "avatarBig": "http://example.com/example.jpg", "avatarSmall": "http://example.com/example.jpg" }, "hasTargetScore": true, "isSinglePlayer": true, "isSoundMuted": false, "difficultyLevel": 3 }
In this example, the difficultyLevel passed is 3, so the corresponding target score to use should be the third item in the targetScore array, which is 40.
onReset- This event is triggered when the AQ Host app requests that your mini app reset to the initial game state with data of the same schema asonDatais passed.Unlike
onData, which is only called right after your mini app is loaded,onResetmay be called several times during the lifetime of your mini app.Note
Although it is possible that the same data as one on
onDatamay be passed, it is not safe to assume that this is always the case. Always treat the data passed inonResetas new data for the new invocation of game play.onAppStateChange- This event is triggered when the AQ Host app’s state changes. The current state, such as whether the app entered the foreground or background state, as well as if the user chooses to mute the sound or not, is propagated to your mini app through this event. The state object passed by this event are as follows:state- Current Host app state. Can either beactiveorinactive.isSoundMuted- Boolean value that informs your mini app whether to mute the game sounds or not.
An example of the data passed by
onAppStateChangeis as follows:
{ "state": "active", "isSoundMuted": false }
Setting Callback Handlers¶
In order to receive events generated by the host app, you need to setup certain callback functions.
This can be achieved by calling several LifeCycle methods. You usually call these methods
as early as possible, primarily in your init or constructor of your main function.
LifeCycle.setCallback(Events.ON_APP_STATE_CHANGE, callback)- Sets the handler for the onAppStateChange event. This function accepts a callback function as a parameter.LifeCycle.setOnDataCallback()- Sets the handler for theonDataevent. This function accepts a callback function as a parameter.LifeCycle.setOnResetCallback()- Sets the handler for theonResetevent. This function accepts a callback function as a parameter.
Example usage:
var LifeCycle = AQCore.LifeCycle;
var Events = AQCore.Events;
var onData = function(data) {
// Do something with the data
}
var onReset = function(newData) {
// Do something with the new data
// and reset app to initial state
}
var onAppStateChange = function(payload) {
// Do something with the new application state
// such as muting the sounds, etc.
}
LifeCycle.setCallback(Events.ON_APP_STATE_CHANGE, onAppStateChange);
LifeCycle.setOnDataCallback(onData);
LifeCycle.setOnResetCallback(onReset);
// Call informLoaded after setting up the callback handlers
LifeCycle.informLoaded();
// ES6 syntax
import { LifeCycle, Events } from 'aq-miniapp-core';
class MyGame {
constructor() {
LifeCycle.setCallback(Events.ON_APP_STATE_CHANGE, this.onAppStateChange.bind(this));
LifeCycle.setOnDataCallback(this.onData.bind(this));
LifeCycle.setOnDataCallback(this.onReset.bind(this));
// Call informLoaded after setting up the callback handlers
LifeCycle.informLoaded();
}
onAppStateChange(payload) {
// Do something with the new application state
// such as muting the sounds, etc.
}
onData(data) {
// Do something with the data
}
onReset(newData) {
// Do something with the new data
// and reset app to initial state
}
}
Information needed by the Host App¶
The Host app will need several information from your mini app in every invocation. It needs to know:
- A URL of an image that it can use as a background - The Host app also shows certain screens with customized background which is relevant to the current mini app being run. You should give this information the Host app in a form of a valid image URL, otherwise, no background will be used.
- When your app has already setup the callback handlers - When the Host App loads your mini app, it needs to know whether
the necessary callbacks are already in place. This ensures that the host app will know that it is safe to invoke the
onDataandonResetevents. - When your app is ready to be displayed - When the Host App loads your mini app, it doesn’t immediately show it. It shows a preloader screen while waiting for it to finish any necessary setup (like loading of assets such as images our sound files), so it is necessary for your mini app to tell the Host app that it is safe to remove the preloader screen and show it to the user.
- When the result from your mini app is already available and your gameplay is about to end - The result from your mini app (such as the score, or the player won or not)
- When your app should end - Once the game play of your app has ended, you should inform the Host app about this, so it can display succeeding screens.
You can achieve these by calling several LifeCycle functions.
LifeCycle.setAppData()- This function expects a JSON object that the Host app will receive and process accordingly. Currently, the schema only allows passing the URL of the image to be used by the Host app as a background. You normally will call this during the initialization of your mini app. The JSON schema is as follows:{ "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "backgroundImage": { "type": "string", "format": "uri" } }, "required": [ "backgroundImage" ] }
Example usage:
var LifeCycle = AQCore.LifeCycle; function init() { LifeCycle.setAppData({ backgroundImage: 'http://example.com/example.jpg' }); }// ES6 syntax import { LifeCycle } from 'aq-miniapp-core'; class MyGame { constructor() { LifeCycle.setAppData({ backgroundImage: 'http://example.com/example.jpg' }); } }
LifeCycle.informLoaded()- This function tells the Host app that the callback handlers are in place and that it is safe to trigger theonDataandonResetevents.informLoadedshould only be called once in the entire lifecycle of your mini app.Example usage:
var LifeCycle = AQCore.LifeCycle; var onData = function(data) { // Do something with the data } var onReset = function(newData) { // Do something with the new data // and reset app to initial state } LifeCycle.setOnDataCallback(onData); LifeCycle.setOnResetCallback(onReset); // Call informLoaded after setting up the callback handlers LifeCycle.informLoaded();
// ES6 syntax import { LifeCycle } from 'aq-miniapp-core'; class MyGame { constructor() { LifeCycle.setOnDataCallback(this.onData.bind(this)); LifeCycle.setOnDataCallback(this.onReset.bind(this)); // Call informLoaded after setting up the callback handlers LifeCycle.informLoaded(); } onData(data) { // Do something with the data } onReset(newData) { // Do something with the new data // and reset app to initial state } }
LifeCycle.informReady()- This function tells the Host app to display the mini app immediately. Call this when you already have setup your resources based on the data passed duringonDataevent and your mini app is ready to be displayed.informReadyshould only be called once in the entire lifecycle of your mini app.Example usage:
var LifeCycle = AQCore.LifeCycle; // An example function that is called after all the assets has been loaded function onLoadAssets() { LifeCycle.informReady(); }
// ES6 syntax import { LifeCycle } from 'aq-miniapp-core'; class MyGame { // An example function that is called after all the assets has been loaded onLoadAssets() { LifeCycle.informReady(); } }
LifeCycle.setResult()- This function tells the Host app that the result for the current invocation of your mini app is available, but the mini app itself has not yet ended. The host app needs the following information:- Whether the current game invocation is a win, lose, or draw. Can be one of the following constants exposed by
AQCore:WIN_CRITERIA_WINor (WinCriteriaEnum.Winfor ES6)WIN_CRITERIA_LOSEor (WinCriteriaEnum.Losefor ES6)WIN_CRITERIA_DRAWor (WinCriteriaEnum.Drawfor ES6)
- The final game score either as a constant or a actual-target component (e.g. 10 out of 20).
- An image result for your gameplay (e.g. a screenshot with the score) as a valid URL.
Example usage:
var AQCore = window.AQCore; var LifeCycle = AQCore.LifeCycle; // An example function that is called when your game (mini app)'s result is available function onScoreAvailable(score) { var param = { // General game result winCriteria: AQCore.WIN_CRITERIA_WIN, // Score of the game. This field is optional if it is // not logical for the game to have a score score: { value: score }, // A valid image url, (usually a screenshot) of the game result resultImageUrl: 'http://example.com/example.jpg' } // You can also specify the score as an actual-target value like this: // // score: { // value: 10, // target: 20 // } // LifeCycle.setResult(param); }
// ES6 syntax import { LifeCycle, WinCriteriaEnum } from 'aq-miniapp-core'; class MyGame { // An example function that is called when your game (mini app)'s result is available onScoreAvailable(score) { var param = { // General game result winCriteria: WinCriteriaEnum.Win, // Score of the game. This field is optional if it is // not logical for the game to have a score score: { value: score }, // A valid image url, (usually a screenshot) of the game result resultImageUrl: 'http://example.com/example.jpg' } // You can also specify the score as an actual-target value like this: // // score: { // value: 10, // target: 20 // } // LifeCycle.setResult(param); } }
- Whether the current game invocation is a win, lose, or draw. Can be one of the following constants exposed by
LifeCycle.end()- This function tells the Host app that the current invocation of your mini app has ended, usually when your game is over. When this is called, you signal the Host app that it can already display succeeding screens relevant to the current game play. Moreover, your mini app should ensure that no sound is playing after this method is called. The only time where the game sounds can be played again is when theonResetevent is triggered.Example usage:
var LifeCycle = AQCore.LifeCycle; // An example function that is called when your game (mini app) has ended function onGameEnd() { LifeCycle.end(); // Ensure game sounds are disabled at this point }
// ES6 syntax import { LifeCycle } from 'aq-miniapp-core'; class MyGame { // An example function that is called when your game (mini app) has ended onGameEnd() { LifeCycle.end(); // Ensure game sounds are disabled at this point } }