# Liquid Gears Platform Documentation

This is the technical documentation for the Liquid Gears Platform which enables the creation of communication solutions that include:

* mobile and web apps
* content management systems
* backend services
* administrative and reporting dashboards
* integration with third-party systems

The Liquid Gears Platform can be used to produce native apps for iOS, Android and Web Apps for desktop browsers.

For more information, please visit <https://liquid-state.com> and <https://liquid-gears.com>


# Platform components

The Liquid Gears Platform is comprised of core components and associated optional services.

The main components of the platform are:

* Carbon Editor for content creation and curating
* Ubiquity Dashboard for content distribution and App User management
* Mobile and Desktop apps to distribute content into
* Integrated Web Apps (a.k.a. IWAs) which comprise the user interface of the apps for end-users
* Admin Dashboards

Other optional components are:

* a document search service
* a Private Information Provider (a.k.a. PIP) to store and retrieve sensitive information

Other features can be delivered through the use of one or more components lissted above:

* localisation
* analytics
* flexible use of content metadata
* etc.


# Mobile Apps

TODO...


# Integrated Web Apps (IWA)

Integrated Web Apps are small web applications. They form parts of a [native app](https://github.com/liquid-state/lg-platform-docs/tree/c45aad3ae70a9fe695486f61f5c7aee8f038cd62/native-apps/README.md) built with the Liquid Gears Platform.

Over time Liquid Gears has developed a framework which revolves around five pillars to enable the rapid creation of quality IWAs:

* core libraries
* helper libraries for React JS
* user interface toolkit
* blueprints
* generators

All components of the framework are open source, free software and available from the [Liquid State Github organisation](https://github.com/liquid-state/).

## Core libraries

The core libraries are agnostic to any particular Javascript framework.

The core libraries are:

* iwa-core
* iwa-router
* iwa-identity

## React helper libraries

Most IWAs created by Liquid Gears and Liquid State are coded using the [React JS](https://reactjs.org/) library (note: React JS not React Native).

These libraries are:

* iwa-react-router

## Liquid State UI Kit

Liquid State has developed a UI Kit based on React and the [Ant Design library](http://ant.design).

## Generator

Generator are templates for [Yeoman](http://yeoman.io) which can be used to set up all the boilerplate code for a brand new project or IWA.

## Blueprints

Blueprints are pre-made IWAs. They can be used as-is or as a starting point to kickstart the creation of an IWA focusing on a particular problematic. Available blueprints are:

* Login
* Registration


# Desktop Web Apps

TODO...


# Ubiquity

TODO...


# Carbon Editor

TODO...


# Admin dashboards

TODO...


# Core libraries

The following libraries comprise the core of the framework and are used in almost every project:

* [iwa-core](/1.1.0/iwa-framework/index/iwa-core)
* [iwa-router](/1.1.0/iwa-framework/index/iwa-router)
* [iwa-identity](/1.1.0/iwa-framework/index/iwa-identity-1)

The following libraries are useful to address partticular needs:

* [iwa-cognito-identity](/1.1.0/iwa-framework/index/iwa-cognito-identity): Support for AWS cognito based identity within IWAs.
* [iwa-keyvalue-store](/1.1.0/iwa-framework/index/iwa-identity-1): Plugin for identity and credentials management in Liquid State IWAs.
* [iwa-desktop](/1.1.0/iwa-framework/index/iwa-desktop): A set of functions and utilities to make it easy to run IWAs in a desktop environment.

## Some example syntax for Gitbook:

Becoming a super hero is a fairly straight forward process:

```
$ give me super-powers
```

{% hint style="info" %}
Super-powers are granted randomly so please submit an issue if you're not happy with yours.
{% endhint %}

Once you're strong enough, save the world:

```
// Ain't no code for that yet, sorry
echo 'You got to trust me on this, I saved the world'
```


# iwa-core

TODO...


# iwa-router

TODO...


# iwa-identity

TODO...


# iwa-cognito-identity

TODO...


# iwa-keyvalue-store

TODO...


# iwa-desktop

TODO...


# React Helpers

TODO...


# UI Kit

TODO...


# Generator

On Github: <https://github.com/liquid-state/generator-ls-iwa>


# Blueprints

## Login

On Github: <https://github.com/liquid-state/blueprint-login-iwa>

## Registration

On Github: <https://github.com/liquid-state/blueprint-registration-iwa>


# Liquid Gears Platform Documentation

{% hint style="info" %}
Please note this documentation is work in progress. We invite you to provide feedback by creating issues in [our Github repo](https://github.com/liquid-state/lg-platform-docs).
{% endhint %}

This is the technical documentation for the Liquid Gears Platform which enables the creation of communication solutions that include:

* mobile and web apps
* content management systems
* backend services
* administrative and reporting dashboards
* integration with third-party systems

The Liquid Gears Platform can be used to produce native apps for iOS, Android and Web Apps for desktop browsers.

For more information, please visit <https://liquid-state.com> and <https://liquid-gears.com>


# Platform components

The Liquid Gears Platform is comprised of core components and associated optional services.

The main components of the platform are:

* Carbon Editor for content creation and curating
* Ubiquity Dashboard for content distribution and App User management
* Mobile and Desktop apps to distribute content into
* Integrated Web Apps (a.k.a. IWAs) which comprise the user interface of the apps for end-users
* Admin Dashboards

Other optional components are:

* a document search service
* a Private Information Provider (a.k.a. PIP) to store and retrieve sensitive information

Other features can be delivered through the use of one or more components lissted above:

* localisation
* analytics
* flexible use of content metadata
* etc.


# Mobile Apps

TODO...


# Integrated Web Apps (IWA)

Integrated Web Apps are small web applications. They form parts of a [native app](https://github.com/liquid-state/lg-platform-docs/tree/c45aad3ae70a9fe695486f61f5c7aee8f038cd62/native-apps/README.md) built with the Liquid Gears Platform.

Over time Liquid Gears has developed a framework which revolves around five pillars to enable the rapid creation of quality IWAs:

* core libraries
* helper libraries for React JS
* user interface toolkit
* blueprints
* generators

All components of the framework are open source, free software and available from the [Liquid State Github organisation](https://github.com/liquid-state/).

## Core libraries

The core libraries are agnostic to any particular Javascript framework.

The core libraries are:

* iwa-core
* iwa-router
* iwa-identity

## React helper libraries

Most IWAs created by Liquid Gears and Liquid State are coded using the [React JS](https://reactjs.org/) library (note: React JS not React Native).

These libraries are:

* iwa-react-router

## Liquid State UI Kit

Liquid State has developed a UI Kit based on React and the [Ant Design library](http://ant.design).

## Generator

Generator are templates for [Yeoman](http://yeoman.io) which can be used to set up all the boilerplate code for a brand new project or IWA.

## Blueprints

Blueprints are pre-made IWAs. They can be used as-is or as a starting point to kickstart the creation of an IWA focusing on a particular problematic. Available blueprints are:

* Login
* Registration


# Desktop Web Apps

TODO...


# Ubiquity

TODO...


# Carbon Editor

TODO...


# Admin dashboards

TODO...


# API documentation

API documentation for all backend services is available via Postman at <https://explore.postman.com/team/liquidgears>


# Core libraries

The following libraries comprise the core of the framework and are used in almost every project:

* [iwa-core](/iwa-framework/libraries/iwa-core)
* [iwa-router](/iwa-framework/libraries/iwa-router)
* [iwa-identity](/iwa-framework/libraries/iwa-identity)

The following libraries are useful to address partticular needs:

* [iwa-cognito-identity](/iwa-framework/libraries/iwa-cognito-identity): Support for AWS cognito based identity within IWAs.
* [iwa-keyvalue-store](https://github.com/liquid-state/lg-platform-docs/tree/b52bdf46713370f91e897e93abedafa4eea8ff58/iwa-framework/core-libraries/iwa-keyvalue-store.md): Plugin for identity and credentials management in Liquid State IWAs.
* [iwa-desktop](/iwa-framework/libraries/iwa-desktop): A set of functions and utilities to make it easy to run IWAs in a desktop environment.


# iwa-core

TODO...


# iwa-router

TODO...


# iwa-identity

TODO...


# iwa-cognito-identity

TODO...


# iwa-keyvalue-store

TODO...


# iwa-desktop

TODO...


# React Helpers

TODO...


# Events

Events are organised in domains:

* [app](/iwa-framework/events/app): app configuration and general state
* [iwa](/iwa-framework/events/iwa): IWA navigation
* [kv](/iwa-framework/events/kv): key-value
* [launch](/iwa-framework/events/launch): launch other IWAs or the Ubiquity Document viewer


# Events overview

## Structure of requests

```
SCHEME (liquidstate)
    DOMAIN (e.g. iwa, iab, kv, user_storage, config, documents)
        EVENT_TYPE (e.g. navigate, get_item, set_item, containers, containers/get)
            DATA = {
                "request_id": "UUID",
                "data": { object depending on event type }
```

Request from webview (IAB, IWA or document page - eventually)

```
liquidstate://DOMAIN/EVENT_TYPE?request=URLENCODED_JSON_DATA
where URLENCODED_JSON_DATA = {
    "id": "REQUEST_ID",
    "data": DATA_OBJECT
}
```

## Structure of responses

```javascript
window.communicate({
    "purpose": "PURPOSE"
    // ... additional properties
})
```

Expected values for PURPOSE are:

* navigate
* response

Additional properties depend on the specified purpose. For example, when PURPOSES is “response”, the additional properties are the following:

* request\_id
* event\_type
* response\_data

Response from webview (IAB, IWA or document page - eventually)

```javascript
window.communicate({
    "purpose": "response",
    "request_id": "UUID",
    "event_type": "get_item",
    "response_data": {
        //...
    }
})
```

Example of ad-hoc communication from native app to IWA to tell it to navigate to a specific route:

```javascript
window.communicate({
    "purpose": "navigate",
    "route": "/page-2",
    "params": {
        "querystringparam1": "value"
    },
    "context": {
        "product_id": "com.example.app123.doc1",
        "page_slug": "page-1"
    }
})
```

## Availability of event domains

Event may or may not be supported depending on the type of the view currently displayed in the app.

Each type of view in the app, or rather each type of area in the app defines which event domains it supports.

When an app area supports a domain, it is assumed that it supports all events in this domain.

| Event domain | IWA views | IAB views | Document library views |
| ------------ | :-------: | :-------: | :--------------------: |
| app          |    Yes    |    Yes    |           Yes          |
| config       |    Yes    |     No    |           Yes          |
| kv           |    Yes    |     No    |           Yes          |
| iwa          |    Yes    |     No    |           No           |
| iab          |     No    |    Yes    |           No           |
| documents    |     No    |     No    |           Yes          |
| launch       |    Yes    |    Yes    |           Yes          |
| userfiles    |    Yes    |     No    |           No           |

Note 1: `kv` and `config` domains are not useful when used from actions (i.e. tapping a button that triggers a “get me this config value” event isn’t very useful).

Note 2: the document library views don’t make use of events from the `kv` and `config` domains but the existing document library code is already able to use the key/value store and app config, it just do this through the event framework.


# app domain

List of event types part of the "app" domain.

## reset

### Stories addressed

* IWA decides that the entire app should be reload, including all its configuration and navigation contexts.

### URL

```
liquidstate://app/reset?request=URLENCODED_REQUEST_OBJECT
```

### Request data

None

### Response data

No response.

## online\_status

### Stories addressed

* IWA or other part of the app needs to know if the device/app is currently online or offline

### URL

```
liquidstate://app/online_status?request=URLENCODED_REQUEST_OBJECT
```

### Request data

None

### Response data

| Property name | Type    | Required |
| ------------- | ------- | -------- |
| status        | Boolean | Yes      |

#### Example response

```javascript
window.communicate({
    "purpose": "response",
    "request_id": "UUID",
    "event_type": "online_status",
    "response_data": {
        "status": true
    }
})
```

## open\_file

### Stories addressed

* IWA or other part of the app needs to open an arbitrary file in the platform-default way.

### Description

On mobile platforms, the file must be at a location accessible to the app.

If the path to the file is a relative one (starts with “./”), the native must compute the absolute path according to the following: - if an IWA is sending the event, the absolute path is relative to the entrypoint file of the IWA - if the native document reading view is sesnding the event, the absolute path is relative to the HTML file being read - if another native part of the app is sending the event, the absolute path is relative to the app bundle’s root

On iOS, the native would open the file in the iOS default documetn viewer (calling NSApplication:openURL). On Android, the native would trigger an intent and let the OS handle opening the file from that intent.

### URL

```
liquidstate://app/open_file?request=URLENCODED_REQUEST_OBJECT
```

### Request data

| Property name | Type   | Required | Description                                                                                                                                                                                              | Default |
| ------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| path          | String | Yes      | <ul><li>a HTTP URL (path starts with “HTTP://” or “HTTPS://”)</li><li>a relative location (path starts with “./”)</li><li>an absolute location (path starts “<a href="file:///">file:///</a>”)</li></ul> |         |

#### Example request data

```javascript
{
    "path": "./files/my_sample_file"
}
```

### Response

No response.

## set\_authentication\_status

### Stories addressed

* IWA logged the user in or out and lets the native app know.

### URL

```
liquidstate://app/set_authentication_status?request=URLENCODED_REQUEST_OBJECT
```

### Request data

| Property name     | Type    | Required | Description |
| ----------------- | ------- | -------- | ----------- |
| is\_authenticated | Boolean | Yes      |             |

**Example request data**

```javascript
{
    "is_authenticated": true
}
```

### Response

No response.

## set\_notification\_presentation\_status

### Stories addressed

* Login IWA needs to let the native app know that a user is ready to have notifications presesented to them.

### Description

The user might not be logged oput and therefore not in a state where they should have notifications,with actions that require being authenticated presented to them.

Similarly, the application logic or UI might be busy and in a state where it isn’t desirable to present the user with notifications.

By default, the native app is in a *not ready* status and therefore won’t present any notification to the user until this call is made.

### URL

```
liquidstate://app/set_notification_presentation_status?request=URLENCODED_REQUEST_OBJECT
```

### Request data

| Property name | Type    | Required |
| ------------- | ------- | -------- |
| is\_ready     | Boolean | Yes      |

#### Example request

```javascript
{
    "is_ready": true
}
```

### Response

No response

## set\_back\_override

### Stories addressed <a href="#stories-addressed-3" id="stories-addressed-3"></a>

* IWA wants to interrupt native back navigation for the current route when the user triggers it.

### URL <a href="#url-3" id="url-3"></a>

```
liquidstate://app/set_back_override?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-3" id="request-data-3"></a>

| Property name | Type    | Required |
| ------------- | ------- | -------- |
| is\_enabled   | Boolean | Yes      |

#### Example request <a href="#example-request" id="example-request"></a>

```javascript
{
    "is_enabled": true
}
```

### Response <a href="#response-2" id="response-2"></a>

No response. When the user triggers native back navigation, the native app will send the following window\.communicate event to the IWA:

```javascript
window.communicate({
    "purpose": "lifecycle",
    "id": "back"
})
```

## user\_location

### Stories addressed

* IWA needs to know the devices current geographic location

### URL

```
liquidstate://app/user_location?request=URLENCODED_REQUEST_OBJECT
```

### Request data

None

### Response

| Property name | Type    | Required                                                                             | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| ------------- | ------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type          | String  | Yes                                                                                  | <p>one of “fine”, “coarse”, “unknown”, “none”</p><p></p><p>“fine” and “coarse” match android terminology where:</p><ul><li>fine = gps location,</li><li>coarse = wifi</li></ul><p>“unknown” means that there is a location but it is unclear how accurate it is (e.g. the platform may not report the accuracy. An example may be the web client or iOS which does not report how it obtained the location)</p><p>“none” means no location could be returned .. see “error” for details</p>                                                                                                                                                                                                                                                                                                                                                           |
| location      | Object  | true if “type” is NOT “none”. If “type” IS “none”, this property will notbe present. | <ul><li><p>latitude</p><ul><li>required : true</li><li>value : numeric string</li></ul></li><li><p>longitude</p><ul><li>required : true</li><li>value : numeric string</li></ul></li><li><p>accuracy</p><ul><li>required : false</li><li>value : numeric string</li><li>comment : accuracy of the location as a radius, units=metres. Confidence: 68% on android, unknown on iOS. Web?</li></ul></li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| error         | Boolean | true if “type” is “none” otherwise not present                                       | <ul><li><p>reason</p><ul><li>required : true</li><li>value : one of “nopermission”, “disabled”, “nolocation”, “unknown”</li></ul></li><li><p>comment :</p><ul><li>“nopermission” means the user has specifically refused location permission for this app (this has a higher priority than disabled)</li><li>“disabled” means that location services are turned off on the device</li><li>“nolocation” means that this device cannot access location information(not expected in practice)</li><li>“unknown” means the system could not access location information due to a system or app error. More descriptive information should be available in the “message” property.</li></ul></li><li><p>message</p><ul><li>required : true</li><li>value : string</li><li>comment : (hopefully) localised message describing the error</li></ul></li></ul> |

#### Example response data

```javascript
window.communicate({
    "purpose": "response",
    "request_id": "UUID",
    "event_type": "user_location",
    "response_data": {
        "type": "fine",
        "location" : {
            "latitude" : "-27.502520099999998"",
            "longitude" : "153.0462454",
            "accuracy" : "7.21"
        }
    }
})

window.communicate({
    "purpose": "response",
    "request_id": "UUID",
    "event_type": "user_location",
    "response_data": {
        "type": "unknown",
        "location" : {
            "latitude" : "-27.502520099999998"",
            "longitude" : "153.0462454",
            "accuracy" : "21.34"
        }
    }
})
window.communicate({
    "purpose": "response",
    "request_id": "UUID",
    "event_type": "user_location",
    "response_data": {
        "type": "none",
        "error" : {
            "reason" : "nopermission",
            "message" :  "You have not granted location permissions for this app. Please goto settings/security and grant location permission for this app"
        }
    }
})
```

## feature\_status

### Stories addressed <a href="#stories-addressed-3" id="stories-addressed-3"></a>

* IWA needs to know whether a device feature is available and any qualifying details that may be relevant

### URL <a href="#url-3" id="url-3"></a>

```
liquidstate://app/feature_status?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-3" id="request-data-3"></a>

| Property name | Type   | Required | Possible values              |
| ------------- | ------ | -------- | ---------------------------- |
| feature       | String | Yes      | <ul><li>biometrics</li></ul> |

#### Example request <a href="#example-request" id="example-request"></a>

```javascript
{
    "feature": "biometrics"
}
```

### Response

| Property name | Type    | Required                       | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| ------------- | ------- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| status        | Boolean | Yes                            | <p>Possible values:</p><ul><li>"unknown" means the requested feature is name not handled by this event</li><li>"not\_present" means the current device cannot provide this feature (ever)</li><li>"disabled" means the feature is present on the device but the user has either disabled it e.g. biometrics are never available if a passcode has not been set</li><li>"not\_configured" means the feature is present and is not disabled, but the user must take some steps to make it usable</li><li>"available" means the feature is present and configured and may be used</li></ul> |
| details       | Object  | Yes is status is not "unknown" | This object will contain feature specific details – See "Feature Details" below                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |

#### Feature details for biometrics

| Property name | Type            | Required                     | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| ------------- | --------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| feature       | String          | Yes                          | The name of the feature that was requested.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| status        | String          | Yes                          | <p>Possible values:</p><ul><li>"not\_present" means the current device does not have fingerprint or face-id authentication capability</li><li>"disabled" means that there is no passcode registered for the device or that biometrics have been explicitly disabled by the user</li><li>"not\_enrolled" means biometrics are not disabled and a passcode has been set but that no fingerprints or face-id have been enrolled</li><li>"available" at least one type of biometric authentication is available and fully configured</li></ul> |
| type          | Array of String | Yes if status is "available" | <p>This lists the available biometric authentication methods. At the time of writing iOS devices will return a single item list containing either "face" or "touch".</p><p>Possible values:</p><ul><li>"touch"</li><li>"face"</li><li>"iris"</li></ul>                                                                                                                                                                                                                                                                                     |
|               |                 |                              | <ul><li></li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |

#### Example response

```javascript
// device does not have biometrics capability
window.communicate({
    "purpose": "response",
    "request_id": "UUID",
    "event_type": "feature_status",
    "response_data": {
        "status": "not_present",
        "detail": {
            feature: "biometrics",
            status: "not_present"
        }
    }
})

// biometrics disabled or passcode/pin not set
window.communicate({
    "purpose": "response",
    "request_id": "UUID",
    "event_type": "feature_status",
    "response_data": {
        "status": "disabled",
        "detail": {
            feature: "biometrics",
            status: "disabled"
        }
    }
})

// biometrics enabled but no fingerprints/face-id enrolled
window.communicate({
    "purpose": "response",
    "request_id": "UUID",
    "event_type": "feature_status",
    "response_data": {
        "status": "not_configured",
        "detail": {
            feature: "biometrics",
            status: "not_enrolled"
        }
    }
})

// biometrics available on iPhone X
window.communicate({
    "purpose": "response",
    "request_id": "UUID",
    "event_type": "feature_status",
    "response_data": {
        "status": "available",
        "detail": {
            feature: "biometrics",
            status: "available"
            type: ["face"]
        }
    }
})

// biometrics available on iPhone 6s
window.communicate({
    "purpose": "response",
    "request_id": "UUID",
    "event_type": "feature_status",
    "response_data": {
        "status": "available",
        "detail": {
            feature: "biometrics",
            status: "available"
            type: ["touch"]
        }
    }
})


// biometrics available on Samsung S8 (with nothing disabled or un-configured)
window.communicate({
    "purpose": "response",
    "request_id": "UUID",
    "event_type": "feature_status",
    "response_data": {
        "status": "available",
        "detail": {
            feature: "biometrics",
            status: "available"
            type: ["touch","face","iris"]
        }
    }
})
```

## clearall

### Stories addressed

* IWA or other part of the app wants to reset the app to its initial launch condition (but not clearing authentication state).

### URL

```
liquidstate://app/clearall?request=URLENCODED_REQUEST_OBJECT
```

### Request data

None

### Response

No response

## switch\_tab

### Stories addressed

* IWA or other part of the app wants to change the current displayed tab (only actioned in a tabbed app)

### Request data <a href="#request-data-3" id="request-data-3"></a>

| Property name | Type    | Required | Description                                                                                                                 |
| ------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------- |
| id            | String  | Yes      | A tab id declared in the app configuration.                                                                                 |
| reset         | Boolean | False    | <p>If true, the tab should be reset to it’s initial launch state before any route is applied.</p><p>Default value: true</p> |
| params        | String  | Yes      | A JSON object of arbitrary parameters to be passed onto the tab that is switched to.                                        |

#### Example request <a href="#example-request" id="example-request"></a>

```javascript
{
    "id": "t1",
    "reset": true,
    "route": "/page1"
}
```

### Response <a href="#response-2" id="response-2"></a>

No response, but...

#### Message for tab being switched to

The native app will issue a window\.communicate call to the tab being switched to, optionally including the "params" property specified in the original event.

```javascript
window.communicate({
    "purpose": "switch_tab",
    "params": {
        "foo1": "bar1",
        "foo2": "bar2"
    }
})
```

## set\_tab\_appearance

### Stories addressed

* IWA or other part of the app wants to modifiy the appearance (icon and/or text) of a tab.
* Although the configuration of the list of tabs and the IWAs loaded in them never changes, this can be used by IWAs to simulate the display of different tabs to different users.

### Request data <a href="#request-data-3" id="request-data-3"></a>

Not all tabs have to be specified in this event and it is possible to update the appearance of one or more tabs at a time.

The request data is an object which has as properties the "id" of the tabs to modify, as configured in the app data.

The value for each of these tab ids is an object with the following properties:

| Property name     | Type             | Required                                                                                                                     | Description                                                                                                                                                         |
| ----------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| title             | String or Object | No                                                                                                                           | The text to be displayed on the tab. This can be a simple string, or an object to support  translations (please refer to the app data configuration documentation). |
| icon\_name        | String           | <p>Yes if you want to change the icon and "icon\_font\_name" and "icon\_code\_point" are not specified.<br>No otherwise.</p> | The name of the icon to be used from the default set of app icons.                                                                                                  |
| icon\_font\_name  | String           | <p>Yes if you want to change the icon and "icon\_name" is not specified.</p><p>No otherwise.</p>                             | The name of the font in the custom fonts configuration.                                                                                                             |
| icon\_code\_point | String           | <p>Yes if you want to change the icon and "icon\_name" is not specified.</p><p>No otherwise.</p>                             | The code point of the glyph in the custom font file.                                                                                                                |
| hidden            | Boolean          | No                                                                                                                           | Specify whether this particular tab should be displayed or ommitted from the tab bar.                                                                               |

#### Example request <a href="#example-request" id="example-request"></a>

```javascript
{
    "tab1": {
        "title": "Favourites",
        "icon_name": "star"
    },
    "tab3": {
        "title": {
            "key": "favourites.tab-title",
            "translations": {
                "en": "Favourite",
                "fr": "Favoris"
            }
        },
        "icon_font_name": "custom",
        "icon_code_point": "\U234"
    }
}
```

### Response <a href="#response-2" id="response-2"></a>

No response


# iwa domain

## set\_ready

### Stories addressed <a href="#stories-addressed-1" id="stories-addressed-1"></a>

* The IWA has finished loading its core code and is declaring to the native app that it is ready to handle window\.communicate events.

### URL <a href="#url-1" id="url-1"></a>

```
liquidstate://iwa/set_ready?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-1" id="request-data-1"></a>

None

### Response <a href="#response-data-1" id="response-data-1"></a>

No response

## navigate <a href="#navigate" id="navigate"></a>

### Stories addressed <a href="#stories-addressed-1" id="stories-addressed-1"></a>

* Navigate from an IWA to another IWA, with a route specified
* Navigate to a different route in the same IWA
* Navigate from a native view to an IWA
* Optionally: change tab before navigation (ignored for linear apps)

### URL <a href="#url-1" id="url-1"></a>

```
liquidstate://iwa/navigate?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-1" id="request-data-1"></a>

| Property name | Type    | Required | Description                                                                                                                                                                                                                                                                                     |
| ------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| webapp\_id    | String  | No       | Default value: current IWA's webapp\_id                                                                                                                                                                                                                                                         |
| entrypoint    | String  | No       | Default value: "default"                                                                                                                                                                                                                                                                        |
| route         | String  | No       | Default value: "/"                                                                                                                                                                                                                                                                              |
| transition    | String  | No       | <p>Possible values:</p><ul><li>push</li><li>replace</li><li>modal</li></ul><p>Default value: "push"</p><p>Specifies how the next view or activity should be presented. The default is “push”, which is equivalent to the platform’s default (e.g. “slide from the right hand side on iOS”).</p> |
| latest        | Boolean | No       | <p>Default value:</p><ul><li>true if navigate to other webapp id or no local copy of the webapp</li><li>false if navigating to the same webapp id</li></ul>                                                                                                                                     |
| tab\_id       | String  | No       | <p>Indicates that the equivalent of a switch\_tab event should be executed prior to this navigate event.</p><p>Not applicable to linear apps.</p><p>The value must be a tab defined in the app config at launch.</p>                                                                            |

#### Example request data <a href="#example-request-data" id="example-request-data"></a>

```javascript
{
    "webapp_id": "login",
    "entrypoint": "default",
    "route": "/",
    "replace": true,
    "latest": true,
}
```

### Response <a href="#response-data-1" id="response-data-1"></a>

No response. Second web app will get window\.communicate call with purpose = navigate.

## navigate\_back <a href="#navigate_back" id="navigate_back"></a>

### Stories addressed

* Navigate from a route back to another route on the navigation stack, with a route id specified
* Navigate from a route back to the previous route

### URL <a href="#url-1" id="url-1"></a>

```
liquidstate://iwa/navigate_back?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-1" id="request-data-1"></a>

| Property name | Type   | Required | Description                                                                                                                                   |
| ------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| webapp\_id    | String | No       | Default value: null (equivalent to "routes belonging to any IWA")                                                                             |
| route\_id     | String | No       | <p>Default value: null</p><p>skip all other routes until a route with a matching id is found. The default is null, meaning any route id".</p> |

A route must match both webapp\_id and route\_id to be navigated to.

#### Example request data <a href="#example-request-data" id="example-request-data"></a>

```javascript
{
    "webapp_id": "myapp",
    "route_id": "home"
}
```

### Response <a href="#response-data-1" id="response-data-1"></a>

No response. When displaying the mathcing route again, the native app will send the original navigate event to the IWA, with all its data, for example:

```javascript
window.communicate({
    "purpose": "navigate",
    "route": "/",
    "params": {
        "querystringparam1": "value"
    },
    "context": {
        "product_id": "com.example.app123.doc1",
        "page_slug": "page-1"
    }
})
```

## trigger\_action <a href="#trigger_action" id="trigger_action"></a>

### Stories addressed <a href="#stories-addressed-1" id="stories-addressed-1"></a>

* An action defined by a web app is triggered within the native UI (presumably toolbar or navabar button was tapped)
* The current IWA wants to initiate a workflow which typically starts with an action

### URL <a href="#url-1" id="url-1"></a>

```
liquidstate://iwa/navigate?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-1" id="request-data-1"></a>

| Property name | Type   | Required | Description                                                                                           | Default |
| ------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------- | ------- |
| id            | String | Yes      | The identifier of the action to be triggered. Note the id is unique per route (see webapp.json file). | ​       |
| params        | Object | No       | An object listing parameter properties and their values which should override default values.         | {}      |

#### Example request data <a href="#example-request-data" id="example-request-data"></a>

```javascript
{
    "id": "edit",
    "params": {
        "edit-mode": "advanced"
    }
}
```

### Response data <a href="#response-data-1" id="response-data-1"></a>

| Property name | Type    | Required | Description                                                                                                                                                                |
| ------------- | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id            | String  | Yes      | the identifier of the action being triggered                                                                                                                               |
| params        | Boolean | No       | An object of key / value properties. The values are the default ones from the action’s definition (see webapp.json file), overridden by the ones specified in the request. |

#### Example response <a href="#example-response-1" id="example-response-1"></a>

```javascript
window.communicate({
    "purpose": "response",
    "request_id": "UUID",
    "event_type": "trigger_action",
    "response_data": {
        "id": "edit",
        "params": {
            "edit-mode": "advanced"
        }
    }
})
```

### Trigger action event initiated by the native app <a href="#trigger-action-event-initiated-by-the-native-app" id="trigger-action-event-initiated-by-the-native-app"></a>

Most of the time, actions are not triggered by the IWA but by the user tapping/clicking on a button which was presented to them within the native UI according to the IWA’s definition.

In this case there is no request/response flow but simply a `window.communicate(...)` event from the native to the IWA, with its `purpose` set to `trigger_action`.

**Comm event data**

Similar to the `response_data` above but at the root of the event object.

**Example comm event**

```javascript
window.communicate({
    "purpose": "trigger_action",
    "id": "edit",
    "params": {
        "edit-mode": "advanced"
    }
})
```

## handle\_share (deprecated) <a href="#handle_share" id="handle_share"></a>

### Note

handle\_share events are deprecated in favour of the upcoming Service IWA feature

### Stories addressed <a href="#stories-addressed-2" id="stories-addressed-2"></a>

* The native app had information shared with it by the OS or another app and passes it on to its default IWA.
* This not a request/response event, so its data sits at the root of the event object.

### Comm event <a href="#comm-event" id="comm-event"></a>

**Comm event data**

| Property name | Type                                      | Required | Description                                                          |
| ------------- | ----------------------------------------- | -------- | -------------------------------------------------------------------- |
| source        | String                                    | Yes      | A string identifying the source of the share (other app id etc.)     |
| files         | array of objects of type File (see below) | No       | ​                                                                    |
| info          | An object of key/value properties         | No       | This information is open-ended and the IWA is left to interprete it. |

File object properties:

| Property name | Type           | Required | Description                                                     |
| ------------- | -------------- | -------- | --------------------------------------------------------------- |
| path          | String         | Yes      | ​                                                               |
| mime\_type    | String         | No       | ​                                                               |
| size          | null or Number | No       | size of the file in bytes. Null if the size cannot be obtained. |

**Example comm event**

```javascript
window.communicate({
    "purpose": "handle_share",
    "source": "com.example.otherapp",
    "files": [
        {
            "path": "file:///path/to/local/file.png",
            "mime_type": "image/png"
        }
    ],
    "info": {
        "datetime": "2017-08-02 13:42:57"
    }
})
```


# kv domain

## event type

Stories addressed

URL

Request data

Response data

| Property name | Type | Required |
| ------------- | ---- | -------- |
|               |      |          |

Example response

```javascript
{}
```

## event type

Stories addressed

URL

Request data

Response data

| Property name | Type | Required |
| ------------- | ---- | -------- |
|               |      |          |

Example response

```javascript
{}
```

## event type

Stories addressed

URL

Request data

Response data

| Property name | Type | Required |
| ------------- | ---- | -------- |
|               |      |          |

Example response

```javascript
{}
```

## event type

Stories addressed

URL

Request data

Response data

| Property name | Type | Required |
| ------------- | ---- | -------- |
|               |      |          |

Example response

```javascript
{}
```

## event type

Stories addressed

URL

Request data

Response data

| Property name | Type | Required |
| ------------- | ---- | -------- |
|               |      |          |

Example response

```javascript
{}
```

## event type

Stories addressed

URL

Request data

Response data

| Property name | Type | Required |
| ------------- | ---- | -------- |
|               |      |          |

Example response

```javascript
{}
```

## event type

Stories addressed

URL

Request data

Response data

| Property name | Type | Required |
| ------------- | ---- | -------- |
|               |      |          |

Example response

```javascript
{}
```

## event type

Stories addressed

URL

Request data

Response data

| Property name | Type | Required |
| ------------- | ---- | -------- |
|               |      |          |

Example response

```javascript
{}
```

## event type

Stories addressed

URL

Request data

Response data

| Property name | Type | Required |
| ------------- | ---- | -------- |
|               |      |          |

Example response

```javascript
{}
```


# launch domain

## iwa

### Stories addressed <a href="#stories-addressed-1" id="stories-addressed-1"></a>

* Open a new instance of an Integrated Web App, optionally at a particular route

### URL <a href="#url-1" id="url-1"></a>

```
liquidstate://launch/iwa?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-1" id="request-data-1"></a>

| Property name | Type    | Required | Description                                                                                                                                                                                                                                                |
| ------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| webapp\_id    | String  | No       | Default value: current webapp id (or null when currently in native view)                                                                                                                                                                                   |
| entrypoint    | String  | No       | Default value: "default"                                                                                                                                                                                                                                   |
| route         | String  | No       | Default value: "/"                                                                                                                                                                                                                                         |
| transition    | String  | No       | <p>Possible values:</p><ul><li>"push"</li><li>"replace"</li></ul><p> Specifies how the next view or activity should be presented. The default is "push", which is equivalent to the platform's default (e.g. "slide from the right hand side on iOS").</p> |
| latest        | Boolean | No       | <p>Default value:</p><ul><li>true if navigate to other webapp id or no local copy of the webapp</li><li>false if navigating to the same webapp id</li></ul>                                                                                                |

### Response <a href="#response-data-1" id="response-data-1"></a>

No response, the native app will simply launch the IWA with the specified transition.

## document

### Stories addressed <a href="#stories-addressed-2" id="stories-addressed-2"></a>

* Navigate from an IWA to open/reading documents

Note: currently, native apps will first check whether a document is locally present on the device and up to date before trying to open it for reading. If it is not, the native app will download the document, presenting to the user a native download progress UI. In an upcoming version of native apps, this will be removed and additional IWA events will be supproted in the "documents" domain to deal with the downloading/updating of documents.

### URL <a href="#url-2" id="url-2"></a>

```
liquidstate://launch/document?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-2" id="request-data-2"></a>

| Property name | Type   | Required | Description                                                         |
| ------------- | ------ | -------- | ------------------------------------------------------------------- |
| product\_id   | String | Yes      | The unique identifier (a.k.a. "product id") of the document to open |
| page\_slug    | String | No       | Default value: first page of the document                           |

#### Example request data <a href="#example-request-data-2" id="example-request-data-2"></a>

```javascript
{
    "product_id": "com.mycompany.awesomedoc",
    "page_slug": "page-4"
}
```

### Response <a href="#response-data-2" id="response-data-2"></a>

No response, the native app will simply launch the document viewer (as noted above it may first download the document if needed).

## email

### Stories addressed <a href="#stories-addressed-3" id="stories-addressed-3"></a>

* Open the device's built-in email composing client, optionally pre-populating fields.

### URL <a href="#url-3" id="url-3"></a>

```
liquidstate://launch/email?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-3" id="request-data-3"></a>

| Property name | Type   | Required | Description                                                     |
| ------------- | ------ | -------- | --------------------------------------------------------------- |
| to            | String | No       | A comma-separated list of email addresses                       |
| cc            | String | No       | A comma-separated list of email addresses                       |
| bcc           | String | No       | A comma-separated list of email addresses                       |
| subject       | String | No       | One line of text to pre-populate the subject of the email       |
| body          | String | No       | One or more lines of text to pre-populate the body of the email |

#### Example request data <a href="#example-request-data-3" id="example-request-data-3"></a>

```javascript
{
    "to": "contact@example.com",
    "subject": "Could you help me out?",
    "body": "Great mobile app!\n\nI just have a few questions..."
}
```

### Response <a href="#response-data-3" id="response-data-3"></a>

No response, the native app will simply launch the device's standard email composing interface. The user should get back to the app after successfully sending an email or dismissing this interface.


# analytics domain

## set\_analytics\_enabled

### Stories addressed <a href="#stories-addressed-1" id="stories-addressed-1"></a>

* Enables or disables the use of analytics. The default state of native apps is to have analytics disabled.&#x20;
* Users need to be uniquely identified for analytics purposes. Note that user identifiers must be not represent or be tied to personal information.

#### Treatment of analytics events before set\_analytics\_enabled is called

* Native apps should "queue" analytics events (for example app launch events) for sending and retain them during the current session until `set_analytics_enabled` is called with an `is_enabled` value of `true`, at which point sending the queued analytics events to backend servers is triggered.

### URL <a href="#url-1" id="url-1"></a>

```
liquidstate://analytics/set_analytics_enabled?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-1" id="request-data-1"></a>

| Property name | Type    | Required | Description                                                                    |
| ------------- | ------- | -------- | ------------------------------------------------------------------------------ |
| is\_enabled   | Boolean | Yes      | Determines whether native apps should initiate analytics event tracking        |
| user\_id      | String  | Yes      | Sets the unique identifier to use for analytics purposes for the current user. |

### Response <a href="#response-data-1" id="response-data-1"></a>

No response, the native app will simply enable or disable the sending of analytics events to backend servers.

## set\_super\_properties

### Stories addressed <a href="#stories-addressed-1" id="stories-addressed-1"></a>

* Set or reset the list of properties that should be automatically added to any analytics event.&#x20;

### URL <a href="#url-1" id="url-1"></a>

```
liquidstate://analytics/set_super_properties?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-1" id="request-data-1"></a>

| Property name | Type   | Required | Description                            |
| ------------- | ------ | -------- | -------------------------------------- |
| properties    | Object | Yes      | JSON object (pairs of keys and values) |

### Response <a href="#response-data-1" id="response-data-1"></a>

No response, the native app will internally update its list of super properties to be used for future analytics events.

## add\_super\_properties

### Stories addressed <a href="#stories-addressed-1" id="stories-addressed-1"></a>

* Augment the list of properties that should be automatically added to any analytics event.&#x20;

### URL <a href="#url-1" id="url-1"></a>

```
liquidstate://analytics/add_super_properties?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-1" id="request-data-1"></a>

| Property name | Type   | Required | Description                            |
| ------------- | ------ | -------- | -------------------------------------- |
| properties    | Object | Yes      | JSON object (pairs of keys and values) |

### Response <a href="#response-data-1" id="response-data-1"></a>

No response, the native app will internally update its list of super properties to be used for future analytics events.

## remove\_super\_properties

### Stories addressed <a href="#stories-addressed-1" id="stories-addressed-1"></a>

* Remove the use of some properties that should be automatically added to any analytics event.&#x20;

### URL <a href="#url-1" id="url-1"></a>

```
liquidstate://analytics/remove_super_properties?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-1" id="request-data-1"></a>

| Property name | Type   | Required | Description                            |
| ------------- | ------ | -------- | -------------------------------------- |
| properties    | Object | Yes      | JSON object (pairs of keys and values) |

### Response <a href="#response-data-1" id="response-data-1"></a>

No response, the native app will internally update its list of super properties to be used for future analytics events.

## post

### Stories addressed <a href="#stories-addressed-1" id="stories-addressed-1"></a>

* Track an analytics event

### URL <a href="#url-1" id="url-1"></a>

```
liquidstate://analytics/post?request=URLENCODED_REQUEST_OBJECT
```

### Request data <a href="#request-data-1" id="request-data-1"></a>

| Property name | Type   | Required | Description                            |
| ------------- | ------ | -------- | -------------------------------------- |
| name          | String | Yes      | The name of the event                  |
| properties    | Object | Yes      | JSON object (pairs of keys and values) |

### Response <a href="#response-data-1" id="response-data-1"></a>

No response, the native app will internally update its list of super properties to be used for future analytics events.


# UI Kit

TODO...


# Generator

On Github: <https://github.com/liquid-state/generator-ls-iwa>


# Blueprints

## Login

On Github: <https://github.com/liquid-state/blueprint-login-iwa>

## Registration

On Github: <https://github.com/liquid-state/blueprint-registration-iwa>


# Simple Mobile App


# Part 1


# Part 2


# Advanced Mobile App


# Part 1


# Part 1


# Linear Mobile Apps

Linear navigation is the default type of navigation for Mobile apps.

When you design a new mobile app, one of the first chocies to make is the type of navigation it should support: linear or tabbed. This page explains all you need to know about linear apps. For more information on tabbed apps, please refer to [the relevant documentation page](/guides/tabbed-mobile-apps).

Linear Mobile Apps have a single navigation stack onto which new routes can be pushed. This stack can be  walked backwards by using common controls to do so on both iOS and Android.

They also have support for an optional toolbar presented at the bottom of their screen, within which secondary actions can be presented to the user. A typical toolbar would include between one and five buttons which can trigger events such as navigation event or iwa/trigger\_action events to, you guessed it, trigger any behaviour in the currently displayed IWA.

## Example configuration

```javascript
{
    // ...
    "navigation": {
        "type": "linear",
        "navigation_options": {
            "linear": {
                "launch_data": {
                    "webapp_id": "main_webapp"
                }
            }
        }
    }
}
```


# Tabbed Mobile Apps

Tabbed apps display a set of pre-configured tabs with each one providing a distinct functionality to the app, by way of an Integrated Web App.

Each tab displays a preconfigured IWA according to the app's configuration data.

## A few facts about tabs in Mobile Apps

### Tabs are fixed for an entire app

The definition of tabs for an app is loaded when the app starts and cannot be dynamically modified.

This means it is impossible to, for example, change which tabs are displayed after a user has logged in.

It is however possible to show and hide tabs (e.g. to show them to users only after they have logged in) by using the "show\_tabs" configuration parameter in app data and webapp.json files. See "The tab bar can be hidden".

It is also possible to display/hide individual tabs. See "Invididuals tabs can be hidden" below.

### Tabs are silos

Tab IWAs will not be able to inter-communicate between tabs, other than via events through the native app container such as:

* Navigate to a document in tab “Calculator”
* Switch to tab “Calculator”
* Fundamentally, each tab will behave as though it was an independent IWA centric app as described above, with the exception that it can call events on the tabbed container.

### Each tab has (and manages) its own navigation stack

*On iOS*: When using the ‘back’ button causes the tab to navigate to the root of it’s stack, the back button will be hidden or disabled and and no further back capability will apply. e.g. Tab changes will not be included in the back stack.

*On Android*: Each tab will handle it’s own backstack BUT, because the back button is ubiquitous on most android versions, Tab changes will also be incorporated into the back stack.

When triggering a "back" navigation, the pattern used is:

* exhaust the entire back stack in the current tab.
* When/If the Tab backstack stack is exhausted – go the the "initial" tab for the app, typically a "Home" tab, and keep walking back through its navigation stack
* When the entry (e.g. "Home") tab exhausts its backstack, triggering another "back" navigation will cause the app to exit back to the device state prior to the app's launch.

### No secondary actions presented

Tabbed apps display a tab bar and do not currently have support for displaying a toolbar, which means they do not support secondary actions. If secondary actions are defined inthe app configuration, they will be ignored.

Primary actions are supported the same way as for Linear apps.

### The tab bar can be hidden

The entire tab bar can be hidden using the "show\_tabs" property in both the app-level App Data and the IWA-level webapp.json file, in which case individual routes can decide to show/hide the entire tab bar. See examples below.

### Individual tabs can be hidden

It is possible to configure tabs which are:

* not displayed by default
* can be displayed/hidden at any time

Typical use-cases for hiding individual tabs are:

* a top-level area of an app which should not be available to users until they perform a particular action
* configuring many tabs for all types of users and displaying select subsets of the tabs based on the type of user once they are identified (e.g. after logging in).

You can display/hide individual tabs at any time by using the [app/set\_tab\_appearance event](/iwa-framework/events/app#set_tab_appearance).

## Tab-related events

### iwa/navigation event

The iwa/navigation event will have an optional “target” property added which will identify the target tab by tab id. This will be ignored in non-tabbed apps.

### app/switchtotab event

The “switchtotab” event includes a mandatory “id” attribute which identifies the target tab.

The “switchtotab” event has the following optional attributes :

* reset: if true, the tab will reload its initial state.

## Showing/hiding tabs

### The tab bar can be hidden

#### By default, in App Data configuration

The entire tab bar can be hidden using the "show\_tabs" property in the app-level App Data.

#### For any route, in IWA configuration

It is also possible to hide/show the tab bar based on the configuration of the currently displayed IWA.

The IWA configuration data can indicate whether an IWA will hide/show the tab bar by default.

Individual IWA route definitions may also override the hide/show state of the entire tab bar.

A practical example of this may be for authentication purposes. The first tab (we’ll call it "Home") may launch as a login screen and then transition to the main app ("Main") screen once authentication has occurred. The Login IWA that is first launched may indicate that the tab bar should be hidden. The "Main" IWA may indicate that it should be shown. Once authentication is completed, the tab bar with all associated tabs will appear as the tab transitions to display the Main IWA. Going "back" to the Login IWA will cause the tabbar to be hidden again.

### Individual tabs can be hidden

It is possible to configure individual tabs which are:

* not displayed by default
* can be displayed/hidden at any time

Typical use-cases for hiding individual tabs are:

* a top-level area of an app which should not be available to users until they perform a particular action
* configuring many tabs for all types of users and displaying select subsets of the tabs based on the type of user once they are identified (e.g. after logging in).

You can display/hide individual tabs at any time by using the [app/set\_tab\_appearance event](/iwa-framework/events/app#set_tab_appearance).

Note: when tabs are hidden, they are destroyed from the app's UI hierarchy and removed from memory. As a tab provides a navigational context for one or more IWAs, the associated IWAs are also destroyed and removed from memory. If a tab has been re-displayed after being hidden, the tab's lifecycle is recreated: the default IWA for this tab as per the app's configuration will be loaded upon the tab being selected.

## Example configurations

### App Data configuration

```javascript
{
    // ...
    "navigation" : {
        "type" : "tabbed",
        "navigation_options" : {
            "tabbed" : {
                "show_tabs": false,
                "launch_tab_id" : "t1",
                "tabs" : {
                    "t1" : {
                        "presentation" : {
                            "icon_name": "pencil",
                            "title": {
                                "key": "tab-t1-title",
                                "translations": {
                                     "en": "Main"
                                }
                            }
                        },
                        "launch_data" : { "webapp_id" : "main_webapp" }
                    },
                    "t2" : {
                        "presentation" : {
                            "icon_name": "clock-o",
                            "title": {
                                "key": "tab-t2-title",
                                "translations": {
                                     "en": "2nd"
                                }
                            }
                        },
                        "hidden": true,
                        "launch_data" : { "webapp_id" : "2nd_webapp" }
                    }
                },
                "order" : [ "t1", "t2" ]
            }
        }
    }
}
```

### IWA configuration (webapp.json file)

```javascript
{
    "id": "login",
    "show_tabs": true,
    "routes": {
        "/": {
            "show_tabs": false,
            "actions": {
                "primary": []
            }
        },
        "/menu": {
            "actions": {
                "primary": []
            }
        }
    }
}
```


# Working with PIP


# Localisation

TODO...


# Analytics

TODO...


# Testing Mobile Apps

TODO...


