Retrieving a SharePoint app URL using JSOM

At occasions, I need to call apps directly from other scripts. I then need the actual app web URL and cannot launch a dialog to find this.
 
There are APIs out there to get this but the entire URL must be constructed.
I know the app domain and redirect URL, but need to fetch the app web, i.e. the masquerade URL. To do this, I can use the following snippet:
 
function loadAppUrl(redirectUrl, appName) {

        // Here, I am fetching the URL to the root site. I want to connect to this app always
        // even when in a sub site collection
        var siteUrl = _spPageContextInfo.siteAbsoluteUrl.toLowerCase().replace("https://", "").split("/")[0];
        var documentPath = "https://" + siteUrl + "/_api/contextinfo";

        $.ajax({
            url: documentPath,
            type: "POST",
            contentType: "application/x-www-url-encoded",
            dataType: "json",
            headers: {
                "Accept": "application/json; odata=verbose"
            },
            success: function (data) {
                if (data.d) {
                    var webUrl = data.d.GetContextWebInformation.WebFullUrl;
                  
                    // Need to create a new ClientContext to create cross site collecton call
                    var clientContext = new SP.ClientContext(webUrl);
                    var web = clientContext.get_web();
                  
                    // Fetch all app instances
                    var appInstances = SP.AppCatalog.getAppInstances(clientContext, web);

                    clientContext.load(web);
                    clientContext.load(appInstances);

                    clientContext.executeQueryAsync(
                        function () {
                            var url = "";
                            if (appInstances.get_count() > 0) {
                                for (var i = 0; i < appInstances.get_count(); i++) {
                                    var v = appInstances.getItemAtIndex(i);
                                    try {
                                        url = v.get_appWebFullUrl();
                                      
                                        // Compare the name of the app with the app key, or part of the
                                        // URL to match
                                        if (url.toLowerCase().indexOf(appName.toLowerCase())) {
                                            break;
                                        }
                                    } catch (e) { }
                                }
                            }                            

                            var appurl = redirectUrl +
                                "?SPLanguage=en%2DUS" +
                                "&SPClientTag=13&SPProductNumber=" +
                                _spPageContextInfo.siteClientTag.split('$$')[1] +
                                "&SPHostUrl=" + encodeURIComponent("https://" + siteUrl) +
                                "&SPAppWebUrl=" +
                                encodeURIComponent(url);

                            //... call another method or update a top level 
                            //... parameter here to store the appurl parameter

                        }, function (sender, args) {
                            // .. log error here using your preferred framework
                        });
                }
            },
            error: function (err) {
                // .. log error here using your preferred framework
            }
        });
    }

 

 
The key here is to send the app redirect URL together with a part of the app URL to check for. For example, if my app generates a subweb named MyCustomApp and I am hosting the backend in Azure then I would call the method as:
 
loadAppUrl("https://mycustomapp.azurewebsites.net/", "MyCustomApp");
 
This method could set a top level parameter, call another method or why not just return a promise with the value. You will then have the full app URL in the following format:
 
https://[app domain]/[app redirect url]?SPLanguage=[lang]
&SPClientTag=[num]&SPProductNumber=[version]&SPHostUrl=[current URL]
&SPAppWebUrl=[app web]