Tutorial: Client APIs

In this tutorial you will learn how to use Client APIs in an app. Those APIs are used for communication with the myApps client and other apps.

We will build a small app that allows entering a SIP URI and will then display the profile picture and presence of the corresponding user. Clicking the profile picture shall start a phone call.

The client APIs used in this tutorial, like com.innovaphone.phone or com.innovaphone.client, are published by innovaphone Phone App or innovaphone myApps client. In case you want to use an own API published by your App, please refer to the AppWebsocket App Platform Library documentation or JavaScript Runtime config documentation.

Conventions

The used file and class names in this example are based on a newly created App with the name NewApp1 and the company name innovaphone. For testing we use the user admin. Your filenames might be different according to your settings.

Step by step

Preparations

Starting with the app template we open NewApp1/apps/innovaphone-newapp1.js and remove all pre-defined functionality, so it looks like follows.

var innovaphone = innovaphone || {};
innovaphone.NewApp1 = innovaphone.NewApp1 || function (start, args) {
    this.createNode("body");
    
    var that = this;
    var colorSchemes = {
        dark: {
            "--bg": "#191919",
            "--button": "#303030",
            "--text-standard": "#f2f5f6",
        },
        light: {
            "--bg": "white",
            "--button": "#e0e0e0",
            "--text-standard": "#4a4a49",
        }
    };
    
    var schemes = new innovaphone.ui1.CssVariables(colorSchemes, start.scheme);
    start.onschemechanged.attach(function () { schemes.activate(start.scheme) });
    
    var texts = new innovaphone.lib1.Languages(innovaphone.NewApp1Texts, start.lang);
    start.onlangchanged.attach(function () { texts.activate(start.lang) });
    
    var app = new innovaphone.appwebsocket.Connection(start.url, start.name);
    app.checkBuild = true;
    app.onconnected = app_connected;
    
    function app_connected(domain, user, dn, appdomain) {
    
    }
}

In our example we want to use an additional library com.innovaphone.avatar that is not included in the template. For that we need to include it in our innovaphone-newapp1.htm.

<script src="web/com.innovaphone.avatar/com.innovaphone.avatar.js" type="text/javascript"></script>

Additionally it needs to be included in NewApp1.mak in order to link the library to our app binary.

include web1/com.innovaphone.avatar/com.innovaphone.avatar.mak

Because we want to display a profile picture in our app make sure that your test user has set one. You can do that in myApps in the hamburger menu in "Edit Profile". Also make sure your test user has at least one phone app to do phone calls.

Display a profile picture

We start by initializing the avatar library. As this needs a few parameters that are provided by the app websocket connection, it's best to do that in our app_connected function. Note that app_connected is called each time the connection comes up - also after a reconnect. So we need to make sure that we only initialize the avatar library once.

    var avatarApi;
    
    function app_connected(domain, user, dn, appdomain) {
        if (!avatarApi) avatarApi = new innovaphone.Avatar(start, user, domain, appdomain);
    }

Then let's add an input field for entering the SIP URI and a DIV for displaying the profile picture.

    var input = this.add(new innovaphone.ui1.Input("margin: 5px; background-color: var(--button); color: var(--text-standard); font-size: 16px; border: none;"));
    var avatar = this.add(new innovaphone.ui1.Div("width: 150px; height: 150px; margin: 10px; background-size: cover;"));

Next we need to load the profile picture when the content of the input field has changed. For that we add a "change" handler that uses the avata library to get the corresponding URL and use it as the background image of our div.

    var sip;

    input.addEvent("change", function () {
        sip = input.getValue();
        avatar.container.style.backgroundImage = "url('" + avatarApi.url(sip, 150, sip) + "')";
    });

Now run your app and try if you can display the profile picture of your test user. :-)

Starting a phone call

In the previous chapter we used a library that does all the communication with the Client API framework. Now let's take look at the core API functionality. Some first hints:

So we first need to create a phone API consumer object in our app.

    var phoneApi = start.consumeApi("com.innovaphone.phone");

When the profile picture is clicked a phone call shall be started to the displayed user. So we add a "click" handler that sends the API message "StartCall" to the default phone API provider.

    avatar.addEvent("click", function () {
        if (sip) phoneApi.send({ mt: "StartCall", sip: sip });
    });

That's it. You can also start phone calls to numbers in your apps. In this case the message looks like that: { mt: "StartCall", num: "123" }

Presence monitoring

Finally we want to display the presence of the user next to the profile picture. For that we need to consume the API com.innovaphone.client that is provided by myApps.

    var clientApi = start.consumeApi("com.innovaphone.client");

For starting a subscription the message SubscribePresence is used. The message UnsubscribePresence removes the subscription. We can use that in the "change" handler of our input field.

    input.addEvent("change", function () {
        if (sip) clientApi.send({ mt: "UnsubscribePresence", sip: sip }); // added this line
        sip = input.getValue();
        avatar.container.style.backgroundImage = "url('" + avatarApi.url(sip, 150, sip) + "')";
        clientApi.send({ mt: "SubscribePresence", sip: sip }); // added this line
    });

To receive the updates for our subscription we need to register for the incoming API messages. We are interested for the message "PresenceUpdated" for our SIP URI. Our app shall display a color strip next to the profile picture that shows the current activity (available - green, away - yellow, busy - red, dnd - purple).

    var presenceColors = { "": "#badb8c", "away": "#ffd063", "busy": "#ff918f", "dnd": "#cb8cdb" };
    clientApi.onmessage.attach(function (sender, obj) {
        if (obj.msg.mt == "PresenceUpdated" && obj.msg.sip == sip) {
            avatar.container.style.borderRight = "10px solid " + presenceColors[obj.msg.presence[0].activity];
        }
    });

Start the new version of you app and see if the displayed presence follows the presence you set on your myApps home screen. :)

User Infos

The API com.innovaphone.client provides also access to the information of a current logged in user, like display name, phone number or GUID. If not already done, start to consume the API first:

    var clientApi = start.consumeApi("com.innovaphone.client");

Add an event listener for the incoming API messages:

    window.addEventListener("message", onwindowmessage);

The messages of type ApiUpdate are delivered by the PBX and are containing user model object (please refer to the com.innovaphone.client documentation):

function onwindowmessage(msg) {
    const obj = JSON.parse(msg.data);
    
    if (obj.mt === "ApiUpdate") {
        console.log(obj);

        console.warn(obj.apis["com.innovaphone.client"]["@client"]["model"]["user"]["num"]);
        console.warn(obj.apis["com.innovaphone.client"]["@client"]["model"]["user"]["dn"]);
    }
}

Conclusion

Here is the code of the full example app.

var innovaphone = innovaphone || {};
innovaphone.NewApp1 = innovaphone.NewApp1 || function (start, args) {
    this.createNode("body");
    var that = this;
    var colorSchemes = {
        dark: {
            "--bg": "#191919",
            "--button": "#303030",
            "--text-standard": "#f2f5f6",
        },
        light: {
            "--bg": "white",
            "--button": "#e0e0e0",
            "--text-standard": "#4a4a49",
        }
    };

    var schemes = new innovaphone.ui1.CssVariables(colorSchemes, start.scheme);
    start.onschemechanged.attach(function () { schemes.activate(start.scheme) });

    var texts = new innovaphone.lib1.Languages(innovaphone.NewApp1Texts, start.lang);
    start.onlangchanged.attach(function () { texts.activate(start.lang) });

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

    var avatarApi;

    function app_connected(domain, user, dn, appdomain) {
        if (!avatarApi) avatarApi = new innovaphone.Avatar(start, user, domain, appdomain);
    }

    var phoneApi = start.consumeApi("com.innovaphone.phone");
    var clientApi = start.consumeApi("com.innovaphone.client");
    var sip;

    var input = this.add(new innovaphone.ui1.Input("margin: 5px; background-color: var(--button); color: var(--text-standard); font-size: 16px; border: none;"));
    var avatar = this.add(new innovaphone.ui1.Div("width: 150px; height: 150px; margin: 10px; background-size: cover;"));

    input.addEvent("change", function () {
        if (sip) clientApi.send({ mt: "UnsubscribePresence", sip: sip });
        sip = input.getValue();
        avatar.container.style.backgroundImage = "url('" + avatarApi.url(sip, 150, sip) + "')";
        clientApi.send({ mt: "SubscribePresence", sip: sip });
    });

    avatar.addEvent("click", function () {
        if (sip) phoneApi.send({ mt: "StartCall", sip: sip });
    });

    var presenceColors = { "": "#badb8c", "away": "#ffd063", "busy": "#ff918f", "dnd": "#cb8cdb" };
    
    clientApi.onmessage.attach(function (sender, obj) {
        if (obj.msg.mt == "PresenceUpdated" && obj.msg.sip == sip) {
            avatar.container.style.borderRight = "10px solid " + presenceColors[obj.msg.presence[0].activity];
        }
    });
}
innovaphone.NewApp1.prototype = innovaphone.ui1.nodePrototype;

We did an introduction to the basic usage of Client APIs.

Read the documentation to discover more functionality of the API framework.

Useful documentation