To retrieve app url using JSOM in sharepoint we need to reconstruct the standard tokens. This can be done as follows:
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
}
});
}
Reference: https://blog.lekman.com/2017/11/retrieving-sharepoint-app-url-using-jsom.html
Another way which I have used in my projects is to use redirect.aspx as follows
function AddIRISSubmisisonsUrl(appName) {
SP.SOD.executeFunc("sp.js", "SP.ClientContext", function () {
SP.SOD.executeFunc("sp.runtime.js", "SP.ClientContext", function () {
var currentContext = new SP.ClientContext.get_current();
var currentWeb = currentContext.get_web();
// Fetch all app instances
var appInstances = SP.AppCatalog.getAppInstances(currentContext, currentWeb);
currentContext.load(currentWeb);
currentContext.load(appInstances);
currentContext.executeQueryAsync(
function () {
console.log('Current web url is ' + currentWeb.get_url());
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();
console.log('AppWebFullUrl is ' + url);
// Compare the name of the app with the app key, or part of the
// URL to match
if (v.get_title().toLowerCase() === appName.toLowerCase()) {
var appRedirectUrl = currentWeb.get_url() + '/_layouts/15/appredirect.aspx?instance_id={' + v.get_id().toString().toUpperCase() + '}';
var a = document.createElement('a');
var linkText = document.createTextNode("Go to My App");
a.appendChild(linkText);
a.title = "Go to My App";
a.href = appRedirectUrl;
var contentDiv = document.getElementsByClassName("article-content")[0];
var newDiv = document.createElement('div');
newDiv.appendChild(a);
newDiv.setAttribute('id', 'appLinkDiv');
$(contentDiv).append(newDiv);
break;
}
} catch (e) { }
}
}
},
function (sender, args) {
console.log(args.get_message());
}
);
});
});
}
This method can only work if the app has been added to current web