Webviews

General

Support for window.print

New in version 3.7.0.

Apps support the window.print JavaScript-API. The standard system print dialog is opened if window.print is called.

Support for window.open

Apps support the window.open JavaScript-API. Starting with 3.11 links opened via this API will be opened in the internal App Browser (with title bar, status bar and navigation, as a “new window”) or the same webview, according to the standard browser specifications.

Starting with version 3.10 Action URLs can also be opened via this API on all platforms.

Cookies

Starting with version 3.13.0 cookies are enabled for all webviews in the Android and iOS apps.

JavaScript-Interfaces

Using the Purple JavaScript-API

Web content can access special JavaScript-APIs to get information about the app / issue and trigger actions.

There are two ways to access the JavaScript-APIs: automatic and manual inclusion.

Automatic inclusion (deprecated since 3.9)

Changed in version 3.9.0: Deprecated, replaced with manual inclusion

With automatic inclusion you simply need to have a global onPurpleLoad function which will get called after the APIs have been made available.

This however only works on Android and iOS and is not supported in the Web Kiosk. This method is therefore considered deprecated since Purple Release 3.9 with the support of manual inclusion.

Manual inclusion

New in version 3.9.0.

To manually include the JS-APIs html consumers can add any source ending on scripts/purpleInterface.js or scripts/purpleInterface.min.js to their head element. The web view intercepts this request and returns the purpleInterface.js. It is recommended to use the following URL to assure the API works on all platforms including web.

Example HTML
1
2
3
4
5
6
<html>
  <head>
      <script type="text/javascript" src="https://kiosk.purplemanager.com/scripts/purpleInterface.min.js"></script>
  </head>
  <body></body>
</html>

Note

The old automatic injection mechanism is used as fallback strategy.

When manually embedding the purpleInterface.js source, the use of the onPurpleLoad function is not mandatory. The purple-Object is available instantly after loading the script.

Hint

If the onPurpleLoad function is used anyways, it needs to be defined prior to the above script tag.

Example HTML
<html>
  <head>
      <script type="text/javascript">
          function onPurpleLoad() {
              // the global "purple" object is now available
          }
      </script>
      <script type="text/javascript" src="https://kiosk.purplemanager.com/scripts/purpleInterface.min.js"></script>
  </head>
  <body></body>
</html>
Overview of the JavaScript-Interfaces
window.purple = {
    app: {
        ...
    },
    metadata: {
        ...
    },
    storefront: {
        ...
    },
    store: {
        ...
    },
    issue: {
        ...
    },
    state: {
        ...
    },
    tracking: {
        ...
    },
    media: {
        ...
    }
}

Due to the asynchronous nature of the javascript bridge all api calls that return values require a callback function as a parameter. This function is then called by the native implementation with the value as its parameter. A common usage would look like this:

Sample usage of callback functions
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function callbackFunctionForSomething(valueOfSomething) {
    console.log(valueOfSomething);
}

window.purple.getSomething(callbackFunctionForSomething);

// or inline:

window.purple.getSomething(function(valueOfSomething) {
    console.log(valueOfSomething)
});

App

This interface is for app-wide information such as the device’s connectivity state.

Note

This interface is not available in Web Kiosk.

App JavaScript-Interface
window.purple = {
    /**
     * @public
     * @static
     * @namespace AppController
     */
    app: {
        /**
         * Adds a listener for connection state changes.
         * The listener will be called with a ConnectionState object.
         * This listener will also be called with the current state right after
         * calling this method.
         */
        addConnectionStateListener: function (listener) {
            // Implementation
        },
        /**
         * Removes a listener for connection state changes.
         */
        removeConnectionStateListener: function (listener) {
            // Implementation
        },
        /**
         * Adds a listener for lifecycle changes.
         * The listener will be called with a LifecycleEvent object.
         * This listener will also be called with the current state right after
         * calling this method.
         */
        addLifecycleListener: function (listener) {
            // Implementation
        },
        /**
         * Removes a listener for lifecycle changes.
         */
        removeLifecycleListener: function (listener) {
            // Implementation
        },
        /**
         * Close the onboarding screen. If true is passed as the first parameter
         * the onboarding will be shown again on the next app start.
         */
        closeOnboarding: function (showAgain) {
            // Implementation
        }
    }
}

addConnectionStateListener

New in version (Android): 3.3.0
New in version (iOS): 3.4.0

The addConnectionStateListener method can be used to register a callback function that gets called when the device changes its connection state. The listener will also be called with the current state when this method is called.

This method takes a single parameter: A callback function that gets called with one parameter, a json object.

This json object will consist of a state with the value ONLINE and type of either TYPE_3G during mobile connectivity or TYPE_WLAN when it is connected to wi-fi.

{
  "state": "ONLINE",
  "type": "TYPE_3G|TYPE_WLAN"
}

If the device is offline then there will be only a state with the value OFFLINE.

{
  "state": "OFFLINE"
}

removeConnectionStateListener

New in version (Android): 3.3.0
New in version (iOS): 3.4.0

This method removes the listener that was added with addConnectionStateListener to stop receiving callbacks.

addLifecycleListener

New in version (Android): 3.10.2
New in version (iOS): 3.10.2

The addLifecycleListener method can be used to register a callback function that gets called when the webview or the device changes its lifecycle state. The listener will also be called with the current state when this method is called.

This method takes a single parameter: A callback function that gets called with one parameter of type object.

This object will consist of a type with the following values

  • STARTED if the webview appears
  • RESUMED if the webview is visible and gets focus
  • PAUSED if the webview is visible but loses focus
  • STOPPED if the webview disappears

When the app comes to foreground or background and the webview is presented, the callback will also be called with the specific type.

1
2
3
{
  "type": "STARTED|RESUMED|PAUSED|STOPPED"
}

removeLifecycleListener

New in version (Android): 3.10.2
New in version (iOS): 3.10.2

This method removes the listener that was added with addLifecycleListener to stop receiving callbacks.

closeOnboarding

New in version (Android): 3.10.0
New in version (iOS): 3.10.0

Close the onboarding screen. If true is passed as the first parameter the onboarding will be shown again on the next app start.

This API method is only available on the onboarding screen.

See the onboarding documentation for more information about this feature.

App-Browser

This interface can be used to retrieve information about the configuration of the current webview, e.g. if it’s displayed modally or embedded, has titlebar and controls.

App-Browser JavaScript-Interface
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
window.purple = {
   appBrowser: {
      /**
       * Get the display mode for the current webview.
       */
      getDisplayMode: function (callback) {
          // Implementation
      },
      /**
       * Get the titlebar configuration for the current webview.
       */
      isTitleBarEnabled: function (callback) {
          // Implementation
      },
      /**
       * Get the controls configuration for the current webview.
       */
      isControlsEnabled: function (callback) {
          // Implementation
      },
      /**
       * Get the statusbar configuration for the current webview.
       */
      isStatusBarEnabled: function (callback) {
          // Implementation
      }
   }
}

getDisplayMode

New in version (Android): 3.5.0
New in version (iOS): 3.5.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 3.5.0

Get the display mode for the current webview.

This method has one parameter, a callback function which will get the display mode value in as a single string parameter.

Values can be embedded or modal.

isTitleBarEnabled

New in version (Android): 3.5.0
New in version (iOS): 3.5.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 3.5.0

Get the titlebar configuration for the current webview.

This method has one parameter, a callback function which will get a boolean value in as a single parameter.

isControlsEnabled

New in version (Android): 3.5.0
New in version (iOS): 3.5.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 3.5.0

Get the controls configuration for the current webview.

This method has one parameter, a callback function which will get a boolean value in as a single parameter.

isStatusBarEnabled

New in version (Android): 3.10.0
New in version (iOS): 3.10.0
New in version (Web Kiosk): 3.10.0
New in version (Web Player): 3.10.0

Get the statusbar configuration for the current webview.

This method has one parameter, a callback function which will get a boolean value in as a single parameter.

Metadata

Metadata / information about the app and issue can be accessed through this javascript interface.

Metadata JavaScript-Interface
window.purple = {
    /**
     * @public
     * @static
     * @namespace MetaDataController
     */
    metadata: {
        /**
         * Get metadata values by key. A callback function with a single parameter is required that will be called
         * with the value for the given key.
         *
         * @param {string} key          the metadata key
         * @param {Function} callback   the callback for the value
         */
        getMetadata: function (key, callback) {
            // Implementation
        }
    }
}

getMetadata

New in version (Android): 2.4.0
New in version (iOS): 2.6.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 2.6.0

This method returns the value for a given key. The value will be provided via the callback method.

The following keys are available:


app_id

New in version (Android): 2.4.0
New in version (iOS): 2.4.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 2.6.0
New in version (Composer): 3.1.0
Changed in version: 2.6.0 now globally available in all web views

The id of the app in the Purple Manager.

On macOS this always returns “Preview Publication”.

Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

app_version

New in version (Android): 2.6.0
New in version (iOS): 2.6.0
New in version (Composer): 3.1.0

The version of the app.

Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

preview_app

New in version (Android): 2.6.0
New in version (iOS): 2.6.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 2.6.0
New in version (Composer): 3.1.0

Boolean value indicating if the app is a preview or release app.

On macOS this always returns true.

Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

device_id

New in version (Android): 2.6.0
New in version (iOS): 2.6.0

The unique id of the device. Used for communication with the Purple Manager.

Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

device_model

New in version (Android): 2.6.0
New in version (iOS): 2.6.0
New in version (Composer): 3.1.0

The model of the device.

Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

device_os

New in version (Android): 2.6.0
New in version (iOS): 2.6.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 2.6.0
New in version (Composer): 3.1.0

The os version of the device.

Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

platform

New in version (Android): 2.6.0
New in version (iOS): 2.6.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 2.6.0
New in version (Composer): 3.1.0

The platform (android, kindle, ios, web` or ``macOS) on which this app is running on.


Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

locale

New in version (Android): 2.6.0
New in version (iOS): 2.6.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 2.6.0
New in version (Composer): 3.1.0

The current locale of the system.

Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

manager_base_url

New in version (Android): 2.6.0
New in version (iOS): 2.6.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 2.6.0

The base url for communicating with the delivery service of the Purple Manager.

Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

push_registration_token

New in version (Android): 3.0.0
New in version (iOS): 3.0.0

The push registration token. This can be used to send pushes to the app.

Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

entitlement_login

New in version (Android): 2.4.0
New in version (iOS): 2.4.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 2.6.0
Changed in version: 2.6.0 now globally available in all web views

The entitlement username of the user if he is logged in.

Available contexts

  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

entitlement_token

New in version (Android): 2.4.0
New in version (iOS): 2.4.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 2.6.0
Changed in version: 2.6.0 now globally available in all web views

The entitlement access token of the user if he is logged in.

Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

entitlement_forced_login_enabled

New in version (Android): 2.6.0
New in version (iOS): 2.6.0

The configuration parameter for forced entitlement login on app start.

Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

entitlement_login_mode

New in version (Android): 2.6.0
New in version (iOS): 2.6.0

Can be either login or relogin indicating the current mode / reason why the login screen has been opened. relogin will be returned if the server responded with an error that the access token is invalid during subscription validation.

Available contexts

  • Html-Entitlement Login

entitlement_mode

New in version (Android): 3.11.0
New in version (iOS): 3.11.0

Can be either entitlement, oauth or none indicating the mode of the first entitlement server that is configured for the app.


Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

entitlement_refresh_token

New in version (Android): 3.11.0
New in version (iOS): 3.11.0

The refresh token that is being used to request a new access token for the entitlement api calls. This value is only available if oauth is being used as entitlement server.


Available contexts

  • Entitlement HTML Login
  • Dynamic HTML-Content
  • In-App-Browser
  • Storytelling Content

issue_id

New in version (Android): 2.4.0
New in version (iOS): 2.4.0
New in version (Web Player): 2.6.0
New in version (Composer): 3.1.0

The id of the currently viewed issue.

Available contexts

  • Storytelling Content

issue_name

New in version (Android): 2.4.0
New in version (iOS): 2.4.0
New in version (Web Player): 2.6.0
New in version (Composer): 3.1.0

The name of the currently viewed issue.

On macOS this always returns “Preview Publication”.

Available contexts

  • Storytelling Content

publication_id

New in version (Android): 2.4.0
New in version (iOS): 2.4.0
New in version (Web Player): 2.6.0
New in version (Composer): 3.1.0

The id of the publication of the currently viewed issue.

On macOS this always returns “Preview Publication”.

Available contexts

  • Storytelling Content

publication_name

New in version (Android): 2.4.0
New in version (iOS): 2.4.0
New in version (Web Player): 2.6.0
New in version (Composer): 3.1.0

The name of the publication of the currently viewed issue.

On macOS this always returns “Preview Publication”.

Available contexts

  • Storytelling Content

page_id

New in version (Android): 2.4.0
New in version (iOS): 2.4.0
New in version (Web Player): 2.6.0
New in version (Composer): 3.1.0

The id of the currently viewed content page.

Available contexts

  • Storytelling Content

page_alias

New in version (Android): 2.4.0
New in version (iOS): 2.4.0
New in version (Composer): 3.1.0

The alias of the currently viewed content page.

Available contexts

  • Storytelling Content

page_title

New in version (Android): 2.4.0
New in version (iOS): 2.4.0
New in version (Web Player): 2.6.0
New in version (Composer): 3.1.0

The title of the currently viewed content page.

Available contexts

  • Storytelling Content

page_index

New in version (Android): 2.4.0
New in version (iOS): 2.4.0
New in version (Web Player): 2.6.0
New in version (Composer): 3.1.0

The index of the currently viewed content page.

Available contexts

  • Storytelling Content

page_filename

New in version (Android): 2.4.0
New in version (iOS): 2.4.0
New in version (Web Player): 2.6.0
New in version (Composer): 3.1.0

The filename of the current page (not the webview page, but the storytelling content page)

Available contexts

  • Storytelling Content

onboarding_mode

New in version (Android): 3.10.1
New in version (iOS): 3.10.1

The mode for the onboarding screen. Can be appstart when opened during app start or manual when opened via action url.


Available contexts

  • HTML onboarding screen

Storefront

Web content can access storefront data through a javascript interface.

Note

This interface is not available in Composer Native Preview.

Storefront JavaScript-Interface
window.purple = {
    /**
     * @public
     * @static
     * @namespace StorefrontController
     */
    storefront: {
        /**
         * Get subscriptions.
         *
         * @param {Function} callback     the callback for the subscriptions
         */
        getSubscriptions: function (callback) {
            // Implementation
        },
        /**
         * Gets a list of all publications. Callback will be called with a
         * JSONArray of Publication objects.
         */
        getPublications: function (callback) {
            // Implementation
        },
        /**
         * Gets a list of all issues for the publication with the given
         * publicationId. Callback will be called with a JSONArray of Issue
         * objects.
         */
        getIssues: function (publicationId, callback) {
            // Implementation
        },
        /**
         * Gets a list of all issue states for the given issueIds. Callback
         * will be called with a JSONArray of IssueState objects without a
         * progress value.
         */
        getIssueStates: function (issueIds, callback) {
            // Implementation
        },
        /**
         * Starts the download of the issue with the given issueId.
         * This can also be a preview issue.
         */
        startDownload: function (issueId) {
            // Implementation
        },
        /**
         * Pauses the download of the issue with the given issueId.
         * This can also be a preview issue.
         */
        pauseDownload: function (issueId) {
            // Implementation
        },
        /**
         * Deletes the content of the issue with the given issueId.
         * This includes the preview content and temporary downloaded data.
         * The callback will be called with the current IssueState object.
         */
        deleteIssue: function (issueId, callback) {
            // Implementation
        },
        /**
         * Adds a listener for issue state changes.
         * The listener will be called with an IssueState object with a
         * progress value.
         */
        addIssueStateListener: function (listener) {
            // Implementation
        },
        /**
         * Removes a listener for issue state changes.
         */
        removeIssueStateListener: function (listener) {
            // Implementation
        },
        /**
         * Loads the new storefront.
         * The callback will be called with the StorefrontUpdateResult object.
         */
        updateStorefront: function (callback) {
            // Implementation
        },
        /**
         * Adds a listener for newsstand and newsfeed changes.
         */
        addUpdateListener: function (listener) {
            // Implementation
        },
        /**
         * Removes a listener for newsstand and newsfeed changes.
         */
        removeUpdateListener: function (listener) {
            // Implementation
        }
        /**
         * Returns the base url for the files of the given issueId.
         */
        getIssueBaseUrl: function (issueId, callback) {
            // Implementation
        },
        /**
         * Returns the pages information for the given issueId.
         */
        getIssuePages: function (issueId, callback) {
            // Implementation
        },
        /**
         * Returns the toc information for the given issueId.
         */
        getIssueToc: function (issueId, callback) {
            // Implementation
        },
        /**
         * Open a list of articles in a pager.
         */
        openArticles: function (articleIds, initialArticleId, callback) {
            // Implementation
        },
        /**
         * Get a list of all categories. The callback will be called with a
         * JSONArray of Category objects.
         */
        getCategories: function (callback) {
            // Implementation
        }
    }
}

getSubscriptions

New in version (Android): 3.0.0
New in version (iOS): 3.0.0
Changed in version: 3.4.0 moved from :code:`kiosk` to :code:`storefront` API. The method in the :code:`kiosk` is still available but deprecated.

Subscriptions can be accessed through the getSubscriptions method. It takes one parameter, a callback function, which is called with an array of subscriptions.


Subscription model
{
  "name": "One Month Subscription",
  "productId": "com.sprylab.onemonth",
  "duration": "one_month",
  "hidden": false,
  "unlocksAllContentDuringPeriod": true,
  "index": 1,
  "publicationIds": ["aabbcc", "1233456"],
  "formattedPrice": "13.37€",
  "price": 13.37,
  "currency": "EUR",
  "properties": [
      {
          "name": "testproperty",
          "value": "testvalue"
      }
  ],
  "state": "NONE|PURCHASING|VALIDATING|PURCHASED"
}

getPublications

New in version (Android): 3.4.0
New in version (iOS): 3.4.0
New in version (Web Kiosk): 3.7.0

This method lists all publications in the storefront. It takes one parameter, a callback function, which is called with an array of publications.


Publications model
{
  "publicationId": "aabbcc",
  "displayName": "Publication A",
  "displayDescription": "Fancy publication description",
  "properties": [
    {
      "name": "testproperty",
      "value": "testvalue"
    }
  ],
  "index": 0,
  "type": "KIOSK|CHANNEL",
  "thumbnails": {
    "default": "url",
    "kind1": "url"
  }
}

getIssues

New in version (Android): 3.4.0
New in version (iOS): 3.4.0
New in version (Web Kiosk): 3.7.0

This method needs to be called to obtain a list of issues for a specific publication. It takes two parameters: A publicationId and a callback function which then will be called with an array of issues. The publicationId can be acquired from a publication model that is obtained through the getPublications method.


Issue model
{
  "issueId": "aabbcc",
  "displayName": "Issue A",
  "displayDescription": "Fancy issue description",
  "properties": [
    {
      "name": "testproperty",
      "value": "testvalue"
    }
  ],
  "index": 0,
  "pubDate": 123,
  "contentLength": 1337,
  "numberOfPages": 42,
  "comingSoon": true,
  "previewIssue": {
    "id": "ddeeff",
    "contentLength": 1337,
    "numberOfPages": 42
  },
  "productId": "com.sprylab.issue1",
  "thumbnails": {
    "default": "url",
    "kind1": "url"
  },
  "tags": ["tag1", "tag2", "tag3"],
  "categories": ["categoryId1", "categoryId2"]
}

The pubDate is a UNIX timestamp in ms. If the issue has a preview issue then previewIssue is a jsonObject with the preview issue’s id, its content size and the number of pages otherwise it is null. The productId can be used to purchase the issue through the store api. It can be null if the issue is not purchasable through in app payments.

getIssueStates

New in version (Android): 3.4.0
New in version (iOS): 3.4.0
New in version (Web Kiosk): 3.7.0

To obtain the state of specific issues this method can be used. It takes two parameters. The first is an array of issue ids and the second a callback function which returns an array of issue state objects for the requested issue ids.


Issue state model
{
  "issueId": "aabbcc",
  "state": "<STATE>"
}

The following table describes the possible issue states.

State Description
LOCKED locked through entitlement -> not visible for the user
COMING_SOON coming soon enabled -> visible, but not downloadable
PURCHASABLE not purchased
AVAILABLE download possible -> purchased, or no paid content
DOWNLOAD_PAUSED download started and paused
DOWNLOADING downloading
INSTALLING extracting, post processing
INSTALLED downloaded, extracted, available for reading
UPDATE downloaded and new version available (=local version does not match remote version)

startDownload

New in version (Android): 3.4.0
New in version (iOS): 3.4.0

With this method it is possible to start the download of an issue with the given issueId.

pauseDownload

New in version (Android): 3.4.0
New in version (iOS): 3.4.0

With this method it is possible to pause the download of the issue with the given issueId.

deleteIssue

New in version (Android): 3.4.0
New in version (iOS): 3.4.0

This method allows the deletion of an issue. It takes two parameters. The first is the issueId of the issue that will be removed and the other is a callback function that will be called with an issue state object after the delete process completed.

addIssueStateListener

New in version (Android): 3.4.0
New in version (iOS): 3.4.0

The addIssueStateListener method allows the registration of a listener that will be called each time when the state of an issue changes. This method takes a single parameter which is a callback function. It will be called with issue state objects which contain an additional progress value. This progress can be a value between 0 and 100. It is always 0 except for the DOWNLOADING and INSTALLING state. The progress for the INSTALLING state is currently only implemented in Android apps. For a description of the states see the table in getIssueStates.


Issue state model (with progress, for possible states see getIssueStates)
{
  "issueId": "aabbcc",
  "state": "<STATE>",
  "progress": 0
}

removeIssueStateListener

New in version (Android): 3.4.0
New in version (iOS): 3.4.0

This method removes a listener that was set with addIssueStateListener to stop receiving issue state updates.

updateStorefront

New in version (Android): 3.4.0
New in version (iOS): 3.4.0
New in version (Web Kiosk): 3.7.0

This method starts a synchronization of the storefront with the Purple Manager. The result of this process will then be called on the given callback function.

For a successful synchronization it will be a simple json object:

{
  "success": true
}

For failures it will be json object which may contain an error code:

{
  "success": false,
  "error_code": "[OFFLINE|UNKNOWN]"
}

addUpdateListener

New in version (Android): 3.11.0
New in version (iOS): 3.11.0

The addUpdateListener method allows the registration of a listener that will be called each time the kiosk has been updated. This method takes a single parameter which is a callback function which itself takes no parameters.

removeUpdateListener

New in version (Android): 3.11.0
New in version (iOS): 3.11.0

This method removes a listener that was previously added with addUpdateListener to stop receiving kiosk updates.

getIssueBaseUrl

New in version (Android): 3.13.0
New in version (iOS): 3.13.0

This method can be used to retrieve the base url for the given issueId. If the issue is not downloaded yet, the callback is called with null. With this base url it is possible to request files of an issue. Requests to the pages.xml and TOC.xml will return 404 Not Found. To request the contents of these files, the storefront.getIssuePages() and storefront.getIssueToc() methods should be used.

getIssuePages

New in version (Android): 3.13.0
New in version (iOS): 3.13.0

This method works the same as issue.getPages() except that it takes an issueId as parameter and returns the data for that issue. See issue.getPages() for details regarding the page model.

getIssueToc

New in version (Android): 3.13.0
New in version (iOS): 3.13.0

This method works the same as issue.getToc() except that it takes an issueId as parameter and returns the data for that issue. See issue.getToc() for details regarding the toc model.

openArticles

New in version (Android): 3.14.0
New in version (iOS): 3.14.0

Opens a list of articles by their issue ID in a native pager. Invalid issues, e.g. paid issues, non-channel issues, will be filtered. If no issues remain to be opened, the callback will be called with the error_code NO_ISSUES_FOUND.

The second parameter may be an issue ID from the list of issue IDs which will be the initially opened issue. If the issue ID is invalid, the first valid issue will be shown.

When the articles have been successfully opened the callback function will be called with a simple json object:

1
2
3
{
  "success": true
}

For failures it will be a json object which may contain an error code:

1
2
3
4
{
  "success": false,
  "error_code": "[NO_ISSUES_FOUND|UNKNOWN]"
}

getCategories

New in version (Android): 3.15.0
New in version (iOS): 3.15.0

Gets a list of all categories. The callback will be called with a JSONArray like the following example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[
  {
    "id": "categoryId1",
    "name": "Category name",
    "thumbnailURL": "http://",
    "properties": { "name": "value" },
    "categories": [
      {
        "id": "categoryId2",
        "name": "Category name 2",
        "thumbnailURL": "http://",
        "properties": { "name": "value" },
        "categories": []
      }
    ]
  },
  {
    "id": "categoryId3",
    "name": "Category name",
    "thumbnailURL": "http://",
    "properties": { "name": "value" },
    "categories": []
  }
]

Store

It is also possible to start purchases and manage the subscription codes through a javascript interface.

Note

This interface is not available in Web Kiosk and Composer Native Preview.

Store JavaScript-Interface
  window.purple = {
      /**
       * @public
       * @static
       * @namespace StoreController
       */
      store: {
          /**
           * Purchase a product
           *
           * @param {string} productId
           * @param {Function} callback
           */
          purchase: function (productId, callback) {
              // Implementation
          },
          /**
           * Subscribe to a subscription
           *
           * @param {string} productId
           * @param {Function} callback
           */
          subscribe: function (productId, callback) {
              // Implementation
          },
          /**
           * Restores purchases on device. Only available on iOS
           * (Android will call callback immediately).
           *
           * @param {Function} callback
           */
          restorePurchases: function (callback) {
              // Implementation
          },
          /**
           * Set a function as a listener which should be called when
           * the purchase state of a subscription product did change.
           * @param {Function} listener
           */
          setPurchaseStateListener: function (listener) {
              // Implementation
          },
          /**
           * Get the current subscription codes
           *
           * @param {Function} callback
           */
          getSubscriptionCodes: function (callback) {
              // Implementation
          },
          /**
           * Add subscription codes
           *
           * @param {String[]} codes
           * @param {Function} callback
           */
          addSubscriptionCodes: function (codes, callback) {
              // Implementation
          },
          /**
           * Remove the subscription codes
           *
           * @param {String[]} codes
           * @param {Function} callback
           */
          removeSubscriptionCodes: function (codes, callback) {
              // Implementation
          },
          /**
           * Gets the price information for the given productIds.
           * The callback will be called with a JSONArray of ProductInfo objects.
           */
          getPrices: function (productIds, callback) {
              // Implementation
          }
      }
  }

purchase

New in version (Android): 3.0.0
New in version (iOS): 3.0.0

The purchase method can be used to purchase a single product, e.g. an issue.

It takes two parameters: the product id and a callback function.

The callback function gets called with one parameter.

For successful purchases it will be a simple json object:

{
  "success": true
}

For failures it will be a json object which may contain an error code:

{
  "success": false,
  "error_code": "CANCELLED"
}

subscribe

New in version (Android): 3.0.0
New in version (iOS): 3.0.0

The subscribe method can be used to purchase a subscription.

It takes two parameters: the product id and a callback function.

The callback function gets called with one parameter.

For successful purchases it will be a simple json object:

{
  "success": true
}

For failures it will be a json object which may contain an error code:

{
  "success": false,
  "error_code": "CANCELLED"
}

restorePurchases

New in version (Android): 3.0.0
New in version (iOS): 3.0.0

Previously purchased products and subscriptions can be restored using the restorePurchases method.

It takes one parameter, a callback function, which gets called when the restore has finished.

The callback function gets called with one parameter: a success or failure result object. See purchase / subscribe for details about this object.

Note

This call is only available on iOS. It will do nothing on Android and call the callback function immediately with a success-object.

setPurchaseStateListener

New in version (Android): 3.0.0
New in version (iOS): 3.0.0

Set a function as a listener which will be called when the purchase state of a subscription product changed.

Note

This call is only available on iOS. It will do nothing on Android.

getSubscriptionCodes

New in version (Android): 3.0.0
New in version (iOS): 3.0.0

Get the current subscription codes.

It takes one parameter, a callback function, which gets called with the subscription codes in a string array as the only parameter.

addSubscriptionCodes

New in version (Android): 3.0.0
New in version (iOS): 3.0.0

Add and activate (multiple) subscription codes.

It takes two parameters: the codes as a string array and a callback function, which gets called with a success or failure result object. See purchase / subscribe for details about this object.

removeSubscriptionCodes

New in version (Android): 3.0.0
New in version (iOS): 3.0.0

Remove and deactivate (multiple) subscription codes.

It takes two parameters: the codes as a string array and a callback function, which gets called with a success or failure result object. See purchase / subscribe for details about this object.

getPrices

New in version (Android): 3.3.0
New in version (iOS): 3.4.0

This method requests the price information for given product ids. It takes two parameters: The first is an array of product ids and the second a callback method that will be called with an array of product info objects.

{
  "productId": "some.product.id",
  "formattedPrice": "13.37€",
  "price": 13.37,
  "currency": "EUR"
}

Issue

This API can be used to retrieve information (e.g. pages and toc from the pages.xml and TOC.xml) of the current issue.

Issue JavaScript-Interface
window.purple = {
    issue: {
        getPages: function (callback) {
            // Implementation
        },
        getToc: function (callback) {
            // Implementation
        }
    }
}

getPages

New in version (Android): 3.3.0
New in version (iOS): 3.3.0
New in version (Web Player): 3.2.0
New in version (Composer): 3.1.0
Changed in version: 3.13 :code:`targetURL` has been added to the response. :code:`targetURL` and :code:`thumbnailURL` do not have a scheme such as :code:`pkmedia://` anymore and are now relative to the content root.

The getPages method can be used to retrieve all pages.

It takes one parameter: a callback function.

The callback function gets called with one parameter: an array of page model objects.


Page model
{
  "id": "",
  "pageIndex": 1,
  "pageNumber": 1,
  "pageLabel": "Seite 1",
  "title": "Seite 1",
  "shortTitle": "Seite 1",
  "alias": "Seite 1",
  "showPurchaseSuggestion": true,
  "placeholder": false,
  "excludeFromPaging": true,
  "targetURL": "page-id.stxml",
  "thumbnailURL": "thumbs/thumb-page123.jpg",
  "sharingEnabled": true,
  "sharingText": "Text",
  "sharingURL": "http://example.com",
  "customData": "tag1,tag2"
}

getToc

New in version (Android): 3.4.0
New in version (iOS): 3.4.0
New in version (Web Player): 3.3.0
New in version (Composer): TODO
Changed in version: 3.13 :code:`thumbnailURL` does not have a scheme such as :code:`pkmedia://` anymore and is now relative to the content root.

The getToc method can be used to retrieve all toc pages.

It takes one parameter: a callback function.

The callback function gets called with one parameter: an array of toc page model objects.


Toc page model
{
  "pageId": "<page-id>",
  "pageAlias": "Page Alias",
  "title": "Title 123",
  "section": "Section",
  "shortTitle": "Old Content Short-Title",
  "teaser": "Old Content Only",
  "thumbnailURL": "pkmedia://thumbs/thumb-page123.jpg"
}

State

This API can be used to store custom state for usage in different webviews. It can only store string values.

State JavaScript-Interface
window.purple = {
    state: {
        setState: function (key, value) {
            // Implementation
        },
        getState: function (key, callback) {
            // Implementation
        }
    }
}

Note

On macOS the state is stored on a per document bases inside the users defaults. This means that the state data is not part of the Purple-Project files.

setState

New in version (Android): 3.3.0
New in version (iOS): 3.3.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 3.1.4
New in version (Composer): 3.1.0

The setState method can be used to store a string value for a string key.

It takes two parameters: the key and a value.

If the value is null the key gets deleted.

Hint

The key is case-sensitive.

getState

New in version (Android): 3.3.0
New in version (iOS): 3.3.0
New in version (Web Kiosk): 3.7.0
New in version (Web Player): 3.1.4
New in version (Composer): 3.1.0

The getState method can be used to retrieve a string value for a string key.

It takes two parameters: the key and a callback function.

The callback function gets called with two parameters: the key and the value. If there is no value for the given key, the value will be null.

Hint

The key is case-sensitive.

Tracking

This API can be used to track custom events in web views (e.g. purchase over an external entitlement or custom view like read mode). There are three different types of events:

  1. Actions
  2. Views
  3. Purchases

The events are forwarded to the app’s enabled tracking services. The same configuration mechanism like in the apps is used.

Note

User Attributes are currently not supported.

Tracking JavaScript-Interface
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
window.purple = {
    tracking: {
        trackAction: function (key, optionalParams) {
            // Implementation
        },
        trackView: function (key, optionalParams) {
            // Implementation
        },
        trackPurchase: function (key, productId, price, currencyCode, transactionId, optionalParams) {
            // Implementation
        }
    }
}

Note

The optionalParams (key-value pairs) can be sent with each event if the tracking service supports this. Every key will be included in the event. The values can contain all placeholders supported for the event and will be evaluated (see app tracking) when sending the event to the service.

trackAction

New in version (Android): 3.10.3
New in version (iOS): 3.10.5
New in version (Web Kiosk): 3.11.0
New in version (Web Player): 3.11.0

The trackAction method can be used to track a custom action event.

It takes two parameters: key and optionalParams.

trackView

New in version (Android): 3.10.3
New in version (iOS): 3.10.5
New in version (Web Kiosk): 3.11.0
New in version (Web Player): 3.11.0

The trackView method can be used to track a custom view event.

It takes two parameters: key and optionalParams.

trackPurchase

New in version (Android): 3.10.3
New in version (iOS): 3.10.5
New in version (Web Kiosk): 3.11.0
New in version (Web Player): 3.11.0

The trackPurchase method can be used to track a custom purchase event.

It takes six parameters: key, productId, price, currencyCode, transactionId and optionalParams.

Media

This API can be used to play remote audio streams and files. The audio will continue playing even if the user puts the app to the background.

Media JavaScript-Interface
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
window.purple = {
  media: {
    startAudio: function (displayName, url) {
        // Implementation
    },
    pauseAudio: function () {
        // Implementation
    },
    resumeAudio: function () {
        // Implementation
    },
    stopAudio: function () {
        // Implementation
    },
    seekTo: function(time) {
        // Implementation
    },
    addStatusListener: function (statusListener) {
        // Implementation
    },
    removeStatusListener: function (statusListener) {
        // Implementation
    },
    addProgressListener: function (progressListener) {
       // Implementation
    },
    removeProgressListener: function (progressListener) {
        // Implementation
    }
  }
};

startAudio

New in version (Android): 3.11.0
New in version (iOS): 3.11.0

Starts a remote audio stream or file. This method takes two parameters: a display name used for notification and player UI and the URL to play.

pauseAudio

New in version (Android): 3.11.0
New in version (iOS): 3.11.0

Pauses the current audio playback.

resumeAudio

New in version (Android): 3.11.0
New in version (iOS): 3.11.0

Resumes the current audio playback.

stopAudio

New in version (Android): 3.11.0
New in version (iOS): 3.11.0

Stops the current audio playback.

seekTo

New in version (Android): 3.11.0
New in version (iOS): 3.11.0

Seeks to the given time in the current audio playback. This method takes the desired time in milliseconds.

addStatusListener

New in version (Android): 3.11.0
New in version (iOS): 3.11.0

Adds a listener for playback state changes.

removeStatusListener

New in version (Android): 3.11.0
New in version (iOS): 3.11.0

Removes a listener for playback state changes.

addProgressListener

New in version (Android): 3.11.0
New in version (iOS): 3.11.0

Adds a listener for playback progress changes.

removeProgressListener

New in version (Android): 3.11.0
New in version (iOS): 3.11.0

Removes listener for playback progress changes.

Web Player specifics

Due to WebViews being implemented using iframes in Web Player and Web Newsstand, JavaScript injection works different in this context.

The global purple object can be made available by including purpleInterface.js in the embedded page. An interface for the Purple Object is re-implemented in the child page. When a function of the purple object is called, a HTML5 PostMessage will be sent to the parent window (Web Player / Web Newsstand). This will invoke the actual call on the Purple Object. The Web Player / Web Newsstand will then respond with another HTML 5 PostMessage which the child window (iframe) will process.

From V 3.0.0 purpleInterface.js is included in the Web Player repository. The latest version is delivered via Purple DS | Web Newsstand. It is recommended to include the script from one of the following URLs to assure to always use the latest version:

https://kiosk.purplemanager.com/scripts/purpleInterface.js

https://kiosk.purplemanager.com/scripts/purpleInterface.min.js

Note

Please be aware that only sites can be displayed which have the X-FRAME-OPTIONS header set correctly. Read here for details: https://developer.mozilla.org/en/docs/Web/HTTP/Headers/X-Frame-Options

purpleInterface.js (excerpt)

window.purpleInterface = {
callbacks: {},
util: {
    receiveMessage: function (event) {
        try {
            // get response data
            var responseData = JSON.parse(event.data);
            var value = responseData.value;
            var callbackId = responseData.callbackId;
            var key = responseData.key;

            if (callbackId) {
                // call callback function from callback map
                if(key) {
                    window.purpleInterface.callbacks[callbackId](key, value);
                } else {
                    window.purpleInterface.callbacks[callbackId](value);
                }
                // delete callback
                window.purpleInterface.callbacks[callbackId] = null;
            } else if(key === 'RELOAD'){
                window.document.location.reload();
            } else if(key === 'HISTORY_BACK') {
                window.history.back();
            } else if(key === 'HISTORY_FORWARD') {
                window.history.forward();
            } else if(key === 'DOCUMENT_TITLE') {
                window.purpleInterface.util.postMessage('DOCUMENT_TITLE', 'DOCUMENT_TITLE', document.title);
            }

        } catch (e) {
        }
    },
    postMessage: function (type, key, value, callback) {

        if (window !== window.parent) {

            // create requestData
            var requestData = {
                type: type,
                key: key
            };
            if (value) {
                requestData.value = value;
            }
            if (callback) {
                // create id = index in callback array
                var callbackId = window.purpleInterface.util.generateUUID();
                requestData.callbackId = callbackId;
                // add callback to callback array
                window.purpleInterface.callbacks[callbackId] = callback;
            }

            // call postMessage
            window.parent.postMessage(JSON.stringify(requestData), '*');
        }

    },
    generateUUID: function () {
        var d = new Date().getTime();
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            var r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
        });
    }
  }
};

document.addEventListener('DOMContentLoaded', function () {
    window.addEventListener('message', window.purpleInterface.util.receiveMessage);

    window.purpleInterface.util.postMessage('LOAD', 'LOAD', null, function () {

        if (!window.purple) {

            window.purple = {};

            var links = document.querySelectorAll('a[href^="purple://"], a[ ^="pkapp://"], a[href^="pkitem://"]');
            for (var i = 0; i < links.length; i++) {
                links[i].addEventListener('click', function (e) {
                    window.purpleInterface.util.postMessage('ACTION_URL', 1, this.href);
                    e.preventDefault();
                });
            }

            // purple object
            window.purple.metadata = {
                getMetadata: function (key, callback) {
                    window.purpleInterface.util.postMessage('META', key, null, callback);
                }
            };

            window.purple.state = {
                setState: function (key, value) {
                    window.purpleInterface.util.postMessage('STATE', key, value, null);
                },
                getState: function (key, callback) {
                    window.purpleInterface.util.postMessage('STATE', key, null, callback);
                }

            };

            window.purple.issue = {
                getPages: function (callback) {
                    window.purpleInterface.util.postMessage('PAGES', 'PAGES', null, callback);
                },
                getToc: function (callback) {
                    window.purpleInterface.util.postMessage('TOC', 'TOC', null, callback);
                }
            };

            window.purple.closeView = function() {
                window.purpleInterface.util.postMessage('CLOSE_VIEW', 'CLOSE_VIEW');
            };

            if ('onPurpleLoad' in window && typeof onPurpleLoad === 'function') {
                onPurpleLoad();
            }

            var search = window.location.search;
            if (document.referrer){
                if (search) {
                    search += '&' + document.referrer.split('?')[1];
                } else {
                    search = '?' + document.referrer.split('?')[1];
                }
            }
            history.replaceState({}, document.title, window.location.origin + window.location.pathname + search);
        }

    });
});