Licensing

If you like to charge customers for your app, you need to implement some kind of software licensing mechanism and sell the licenses. This article describes the different options that you have.

If you distribute your app on the innovaphone App Store, you need to specify which option your app uses.

Content

innovaphone licensing model
Paid apps that use the same per-user licenses as the innovaphone apps. The licenses are sold by innovaphone.
Your own licensing model
Paid apps using your own licenses.
Free apps
Free apps that do not require a license.

innovaphone licensing model

Overview

License types App and Service

In most cases a license of type App can be used to implement a per user licensing scheme - an App License for specific App can be enabled on a PBX user and a check in the App Service and in the App running in the myApps cleint can be performed.

The license of a type Service can be used to assign some specific number of licenses to an App Service via the parameter Licenses on the App Object. A check of the amout of licenses granted can be performed in the App Service.

Naming scheme

A license refers to a single app. If your app service provides multiple apps, they are licensed individually.

The license name contains the name of the HTML file of the app without the extension. So your HTML file name must be unique and follow the scheme manufacturer-appname.htm.

Example: Switchbard by innovaphone

HTML file: innovaphone-switchboard.htm
License name: App(innovaphone-switchboard)

Example: Calculator by ACME

HTML file: acme-calculator.htm
License name: App(acme-calculator)

Example: Conference by ACME

HTML file: acme-monitoring.htm
License name: Service(acme-monitoring)

Example XML file with licenses:

<?xml version="1.0" encoding="utf-8"?>
    <licenses>
    <license amount='10' type='PBX-App(innovaphone-switchboard)13' mac='00-90-33-01-02-ab' var='PBX0'>038df...</license>
    <license amount='10' type='PBX-App(acme-calculator)13' mac='00-90-33-01-02-ab' var='PBX0'>038df...</license>
    <license amount='10' type='PBX-Service(acme-monitoring)13' mac='00-90-33-01-02-ab' var='PBX0' >8d0ea1...</license>
    <license amount='20' type='PBX-Port13' mac='00-90-33-01-02-ab' var='PBX0'>8d0ea...</license>
</licenses>

Head Matching for License Names

The verification of a license for an app is based on a head-match of the string of the license against the app name string. For example a license example-app would be valid for the app example-app and example-app-light. This must be considered while defining the strings of the app names.

Checking the license

The actual license check for the license type App is done by the PBX when a user requests a login for your app. The following conditions must be met that the PBX marks the login as licensed:

The information if the user got a license is then transmitted to the app as part of the login. This is done using the unlicensed property in the info object of the AppLogin message. The structure is protected by the login digest.

In the client JavaScript code of your app, you can check the App license after an AppWebsocket connection is established by accessing the property unlicensed (no check for Service license available here):

var app = new innovaphone.appwebsocket.Connection(start.url, start.name);
app.onconnected = app_connected;

function app_connected(domain, user, dn, appdomain) {
    if (app.logindata.info.unlicensed) {
        // unlicensed mode
    }
    else {
        // licensed mode
    }
}

In the C++ code of an app service, you can do the same check on incoming AppWebsocket connections. Note that you might need to distinguish between the connections from different apps.

bool NewApp1Session::AppWebsocketConnectComplete(class json_io & msg, word info)
{
    bool unlicensed = msg.get_bool(info, "unlicensed");

    if (app && !strcmp(app, "manufacturer-newapp1")) {
        if (unlicensed) {
            // unlicensed mode
        }
        else {
            // licensed mode
        }
    }
    else if (app && !strcmp(app, "manufacturer-newapp1admin") {
        // no license needed
    }
    
    // amount of Service licenses 
    int licenses = msg.get_int(info, "lics");
    
    return true;
}

In the JavaScript code of an app service you can check the JsonApiConnection.unlicensed attribute of the AppWebsocket connection from the myApps client to the app service. Note that you might need to distinguish between the connections from different apps.

new JsonApi("test").onconnected(function(conn) {
    if (conn.app === "manufacturer-newapp1") {
        if (conn.unlicensed) {
            // unlicensed mode
        }
        else {
            // licensed mode
        }
    }
    else if (conn.app === "manufacturer-newapp1admin") {
        // no license needed
    }

    // amount of Service licenses
    var licenses = conn.lics;
});

It is also possible to check if a specific user object has a valid specific app license assigned. This check require access to the PbxAdminApi in order to use message CheckAppLic for this purpose. This must be done on the AppWebsocket connection from the PBX to the app service, therefore PbxApi library of the JavaScript environment is used.

new PbxApi("PbxAdminApi").onconnected(function (conn) {
    conn.send(JSON.stringify({ api: "PbxAdminApi", mt: "CheckAppLic", cn: "Atlantis", lic: "App(manufacturer-newapp1)" }));

    conn.onmessage(function (msg) {
        var obj = JSON.parse(msg);

        if (obj.mt === "CheckAppLicResult") {
            if (obj.ok === true) {
                // licensed mode
            } else {
                // unlicensed mode
            }
        }
    }

});

Unlicensed mode

It's up to you, what your app does without a license. Some ideas:

Other license checks

Depending on license requirements other license information available form the PBX can be used, like overall number of Port Licenses. The messages GetPbxLicenses and GetAppLics are a good starting point to implement a custom license requirement.

Example App

A Visual Studio project jslicenseexample for an example App implementing various license check mechanisms can be used as a reference.

Test Mode for Licenses

An innovaphone gateway or an IPVA running the PBX can be put into a so called Test-Mode which can be used to figure out which licenses are required for the proper functionality of the PBX and Apps. In this mode all license checks for Apps are positive, even if no licenses for particular App or Service are installed.

It is possible to detect if a PBX connecting to the App Service is running in the Test-Mode. The property testmode of the info object in the AppLogin message is set to true in this case.

new JsonApi("test").onconnected(function(conn) {
    var info = JSON.parse(conn.info);
    if ("testmode" in info) log("Test-Mode: " + info.testmode);
});

Dummy Licenses

A dummy licenses issued for the App(example-app) and the Service(example-service) are valid on any innovaphone gateway or an IPVA running the PBX. The dummy licenses are not bound to any MAC address and can be used to test license checking implementation for the App in case Test-Mode is not suitable for your scenario.

An innovaphone gateway or IPVA equipped with a dummy license will start a 99 hours test mode that can be prolonged any time. This test mode is not visible for the application and the behaviour of the license is the same as for real licenses.

The dummy license file is available for download here.

Your own licensing model

If you don't want to use the innovaphone licensing model, you can use your own one. In that case you need to sell and check the licenses yourself.

Note: Your app must ignore the unlicensed attribute in the info object of the AppLogin message. It will always be true, as the PBX does not find an innovaphone app license for the user.

Free apps

If your app is for free, you don't need to do something special.

Note: Your app must ignore the unlicensed attribute in the info object of the AppLogin message. It will always be true, as the PBX does not find an innovaphone app license for the user.