@thathoff/cordova-plugin-universal-links 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +84 -0
- package/LICENSE +22 -0
- package/README.md +908 -0
- package/docs/images/app-associated-domains.jpg +0 -0
- package/docs/images/app-id-team-prefix.jpg +0 -0
- package/docs/images/app-id.jpg +0 -0
- package/docs/images/branch-io-link-domain.jpg +0 -0
- package/docs/images/branch-io.jpg +0 -0
- package/docs/images/developer-console.jpg +0 -0
- package/hooks/afterPrepareHook.js +86 -0
- package/hooks/beforePluginInstallHook.js +55 -0
- package/hooks/iosBeforePrepareHook.js +74 -0
- package/hooks/lib/android/manifestWriter.js +320 -0
- package/hooks/lib/android/webSiteHook.js +162 -0
- package/hooks/lib/configXmlHelper.js +117 -0
- package/hooks/lib/configXmlParser.js +145 -0
- package/hooks/lib/ios/appleAppSiteAssociationFile.js +173 -0
- package/hooks/lib/ios/projectEntitlements.js +174 -0
- package/hooks/lib/ios/xcodePreferences.js +243 -0
- package/hooks/lib/xmlHelper.js +57 -0
- package/package.json +58 -0
- package/plugin.xml +106 -0
- package/src/android/com/nordnetab/cordova/ul/UniversalLinksPlugin.java +221 -0
- package/src/android/com/nordnetab/cordova/ul/js/JSAction.java +19 -0
- package/src/android/com/nordnetab/cordova/ul/model/JSMessage.java +193 -0
- package/src/android/com/nordnetab/cordova/ul/model/ULHost.java +85 -0
- package/src/android/com/nordnetab/cordova/ul/model/ULPath.java +43 -0
- package/src/android/com/nordnetab/cordova/ul/parser/ULConfigXmlParser.java +156 -0
- package/src/android/com/nordnetab/cordova/ul/parser/XmlTags.java +49 -0
- package/src/ios/AppDelegate+CULPlugin.h +17 -0
- package/src/ios/AppDelegate+CULPlugin.m +32 -0
- package/src/ios/CULPlugin.h +38 -0
- package/src/ios/CULPlugin.m +176 -0
- package/src/ios/JS/CDVInvokedUrlCommand+CULPlugin.h +21 -0
- package/src/ios/JS/CDVInvokedUrlCommand+CULPlugin.m +19 -0
- package/src/ios/JS/CDVPluginResult+CULPlugin.h +29 -0
- package/src/ios/JS/CDVPluginResult+CULPlugin.m +157 -0
- package/src/ios/Model/CULHost.h +63 -0
- package/src/ios/Model/CULHost.m +50 -0
- package/src/ios/Model/CULPath.h +36 -0
- package/src/ios/Model/CULPath.m +21 -0
- package/src/ios/Parser/JSON/CULConfigJsonParser.h +22 -0
- package/src/ios/Parser/JSON/CULConfigJsonParser.m +60 -0
- package/src/ios/Parser/XML/CULConfigXmlParser.h +22 -0
- package/src/ios/Parser/XML/CULConfigXmlParser.m +123 -0
- package/src/ios/Parser/XML/CULXmlTags.h +54 -0
- package/src/ios/Parser/XML/CULXmlTags.m +22 -0
- package/src/ios/Utils/NSBundle+CULPlugin.h +22 -0
- package/src/ios/Utils/NSBundle+CULPlugin.m +15 -0
- package/ul_web_hooks/android_web_hook_tpl.html +23 -0
- package/www/universal_links.js +56 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Class creates android_web_hook.html file in your Cordova project root folder.
|
|
3
|
+
File holds <link /> tags, which are generated based on data, specified in config.xml.
|
|
4
|
+
You need to include those tags on your website to link web pages to the content inside your application.
|
|
5
|
+
|
|
6
|
+
More documentation on that can be found here:
|
|
7
|
+
https://developer.android.com/training/app-indexing/enabling-app-indexing.html
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var fs = require('fs');
|
|
11
|
+
var path = require('path');
|
|
12
|
+
var mkpath = require('mkpath');
|
|
13
|
+
var ConfigXmlHelper = require('../configXmlHelper.js');
|
|
14
|
+
var WEB_HOOK_FILE_PATH = path.join('ul_web_hooks', 'android', 'android_web_hook.html');
|
|
15
|
+
var WEB_HOOK_TPL_FILE_PATH = path.join('plugins', 'cordova-plugin-universal-links', 'ul_web_hooks', 'android_web_hook_tpl.html');
|
|
16
|
+
var LINK_PLACEHOLDER = '[__LINKS__]';
|
|
17
|
+
var LINK_TEMPLATE = '<link rel="alternate" href="android-app://<package_name>/<scheme>/<host><path>" />';
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
generate: generateWebHook
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// region Public API
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Generate website hook for android application.
|
|
27
|
+
*
|
|
28
|
+
* @param {Object} cordovaContext - cordova context object
|
|
29
|
+
* @param {Object} pluginPreferences - plugin preferences from config.xml file; already parsed
|
|
30
|
+
*/
|
|
31
|
+
function generateWebHook(cordovaContext, pluginPreferences) {
|
|
32
|
+
var projectRoot = cordovaContext.opts.projectRoot;
|
|
33
|
+
var configXmlHelper = new ConfigXmlHelper(cordovaContext);
|
|
34
|
+
var packageName = configXmlHelper.getPackageName('android');
|
|
35
|
+
var template = readTemplate(projectRoot);
|
|
36
|
+
|
|
37
|
+
// if template was not found - exit
|
|
38
|
+
if (template == null || template.length == 0) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// generate hook content
|
|
43
|
+
var linksToInsert = generateLinksSet(projectRoot, packageName, pluginPreferences);
|
|
44
|
+
var hookContent = template.replace(LINK_PLACEHOLDER, linksToInsert);
|
|
45
|
+
|
|
46
|
+
// save hook
|
|
47
|
+
saveWebHook(projectRoot, hookContent);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// endregion
|
|
51
|
+
|
|
52
|
+
// region Public API
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Read hook teplate from plugin directory.
|
|
56
|
+
*
|
|
57
|
+
* @param {String} projectRoot - absolute path to cordova's project root
|
|
58
|
+
* @return {String} data from the template file
|
|
59
|
+
*/
|
|
60
|
+
function readTemplate(projectRoot) {
|
|
61
|
+
var filePath = path.join(projectRoot, WEB_HOOK_TPL_FILE_PATH);
|
|
62
|
+
var tplData = null;
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
tplData = fs.readFileSync(filePath, 'utf8');
|
|
66
|
+
} catch (err) {
|
|
67
|
+
console.warn('Template file for android web hook is not found!');
|
|
68
|
+
console.warn(err);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return tplData;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Generate list of <link /> tags based on plugin preferences.
|
|
76
|
+
*
|
|
77
|
+
* @param {String} projectRoot - absolute path to cordova's project root
|
|
78
|
+
* @param {String} packageName - android application package name
|
|
79
|
+
* @param {Object} pluginPreferences - plugin preferences, defined in config.xml; already parsed
|
|
80
|
+
* @return {String} list of <link /> tags
|
|
81
|
+
*/
|
|
82
|
+
function generateLinksSet(projectRoot, packageName, pluginPreferences) {
|
|
83
|
+
var linkTpl = LINK_TEMPLATE.replace('<package_name>', packageName);
|
|
84
|
+
var content = '';
|
|
85
|
+
|
|
86
|
+
pluginPreferences.hosts.forEach(function(host) {
|
|
87
|
+
host.paths.forEach(function(hostPath) {
|
|
88
|
+
content += generateLinkTag(linkTpl, host.scheme, host.name, hostPath) + '\n';
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return content;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Generate <link /> tag.
|
|
97
|
+
*
|
|
98
|
+
* @param {String} linkTpl - template to use for tag generation
|
|
99
|
+
* @param {String} scheme - host scheme
|
|
100
|
+
* @param {String} host - host name
|
|
101
|
+
* @param {String} path - host path
|
|
102
|
+
* @return {String} <link /> tag
|
|
103
|
+
*/
|
|
104
|
+
function generateLinkTag(linkTpl, scheme, host, path) {
|
|
105
|
+
linkTpl = linkTpl.replace('<scheme>', scheme).replace('<host>', host);
|
|
106
|
+
if (path == null || path === '*') {
|
|
107
|
+
return linkTpl.replace('<path>', '');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// for android we need to replace * with .* for pattern matching
|
|
111
|
+
if (path.indexOf('*') >= 0) {
|
|
112
|
+
path = path.replace(/\*/g, '.*');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// path should start with /
|
|
116
|
+
if (path.indexOf('/') != 0) {
|
|
117
|
+
path = '/' + path;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return linkTpl.replace('<path>', path);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Save data to website hook file.
|
|
125
|
+
*
|
|
126
|
+
* @param {String} projectRoot - absolute path to project root
|
|
127
|
+
* @param {String} hookContent - data to save
|
|
128
|
+
* @return {boolean} true - if data was saved; otherwise - false;
|
|
129
|
+
*/
|
|
130
|
+
function saveWebHook(projectRoot, hookContent) {
|
|
131
|
+
var filePath = path.join(projectRoot, WEB_HOOK_FILE_PATH);
|
|
132
|
+
var isSaved = true;
|
|
133
|
+
|
|
134
|
+
// ensure directory exists
|
|
135
|
+
createDirectoryIfNeeded(path.dirname(filePath));
|
|
136
|
+
|
|
137
|
+
// write data to file
|
|
138
|
+
try {
|
|
139
|
+
fs.writeFileSync(filePath, hookContent, 'utf8');
|
|
140
|
+
} catch (err) {
|
|
141
|
+
console.warn('Failed to create android web hook!');
|
|
142
|
+
console.warn(err);
|
|
143
|
+
isSaved = false;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return isSaved;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Create directory if it doesn't exist yet.
|
|
151
|
+
*
|
|
152
|
+
* @param {String} dir - absolute path to directory
|
|
153
|
+
*/
|
|
154
|
+
function createDirectoryIfNeeded(dir) {
|
|
155
|
+
try {
|
|
156
|
+
mkpath.sync(dir);
|
|
157
|
+
} catch (err) {
|
|
158
|
+
console.log(err);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// endregion
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Helper class to read data from config.xml file.
|
|
3
|
+
*/
|
|
4
|
+
var path = require('path');
|
|
5
|
+
var xmlHelper = require('./xmlHelper.js');
|
|
6
|
+
var ANDROID = 'android';
|
|
7
|
+
var IOS = 'ios';
|
|
8
|
+
var CONFIG_FILE_NAME = 'config.xml';
|
|
9
|
+
var context;
|
|
10
|
+
var projectRoot;
|
|
11
|
+
|
|
12
|
+
module.exports = ConfigXmlHelper;
|
|
13
|
+
|
|
14
|
+
// region public API
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Constructor.
|
|
18
|
+
*
|
|
19
|
+
* @param {Object} cordovaContext - cordova context object
|
|
20
|
+
*/
|
|
21
|
+
function ConfigXmlHelper(cordovaContext) {
|
|
22
|
+
context = cordovaContext;
|
|
23
|
+
projectRoot = context.opts.projectRoot;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Read config.xml data as JSON object.
|
|
28
|
+
*
|
|
29
|
+
* @return {Object} JSON object with data from config.xml
|
|
30
|
+
*/
|
|
31
|
+
ConfigXmlHelper.prototype.read = function() {
|
|
32
|
+
var filePath = getConfigXmlFilePath();
|
|
33
|
+
|
|
34
|
+
return xmlHelper.readXmlAsJson(filePath);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get package name for the application. Depends on the platform.
|
|
39
|
+
*
|
|
40
|
+
* @param {String} platform - 'ios' or 'android'; for what platform we need a package name
|
|
41
|
+
* @return {String} package/bundle name
|
|
42
|
+
*/
|
|
43
|
+
ConfigXmlHelper.prototype.getPackageName = function(platform) {
|
|
44
|
+
var configFilePath = getConfigXmlFilePath();
|
|
45
|
+
var config = getCordovaConfigParser(configFilePath);
|
|
46
|
+
var packageName;
|
|
47
|
+
|
|
48
|
+
switch (platform) {
|
|
49
|
+
case ANDROID:
|
|
50
|
+
{
|
|
51
|
+
packageName = config.android_packageName();
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
case IOS:
|
|
55
|
+
{
|
|
56
|
+
packageName = config.ios_CFBundleIdentifier();
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (packageName === undefined || packageName.length == 0) {
|
|
61
|
+
packageName = config.packageName();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return packageName;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get name of the current project.
|
|
69
|
+
*
|
|
70
|
+
* @return {String} name of the project
|
|
71
|
+
*/
|
|
72
|
+
ConfigXmlHelper.prototype.getProjectName = function() {
|
|
73
|
+
return getProjectName();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// endregion
|
|
77
|
+
|
|
78
|
+
// region Private API
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get config parser from cordova library.
|
|
82
|
+
*
|
|
83
|
+
* @param {String} configFilePath absolute path to the config.xml file
|
|
84
|
+
* @return {Object}
|
|
85
|
+
*/
|
|
86
|
+
function getCordovaConfigParser(configFilePath) {
|
|
87
|
+
var ConfigParser;
|
|
88
|
+
|
|
89
|
+
// If we are running Cordova 5.4 or abova - use parser from cordova-common.
|
|
90
|
+
// Otherwise - from cordova-lib.
|
|
91
|
+
try {
|
|
92
|
+
ConfigParser = context.requireCordovaModule('cordova-common/src/ConfigParser/ConfigParser');
|
|
93
|
+
} catch (e) {
|
|
94
|
+
ConfigParser = context.requireCordovaModule('cordova-lib/src/configparser/ConfigParser')
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return new ConfigParser(configFilePath);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get absolute path to the config.xml.
|
|
102
|
+
*/
|
|
103
|
+
function getConfigXmlFilePath() {
|
|
104
|
+
return path.join(projectRoot, CONFIG_FILE_NAME);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get project name from config.xml
|
|
109
|
+
*/
|
|
110
|
+
function getProjectName() {
|
|
111
|
+
var configFilePath = getConfigXmlFilePath();
|
|
112
|
+
var config = getCordovaConfigParser(configFilePath);
|
|
113
|
+
|
|
114
|
+
return config.name();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// endregion
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Parser for config.xml file. Read plugin-specific preferences (from <universal-links> tag) as JSON object.
|
|
3
|
+
*/
|
|
4
|
+
var path = require('path');
|
|
5
|
+
var ConfigXmlHelper = require('./configXmlHelper.js');
|
|
6
|
+
var DEFAULT_SCHEME = 'http';
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
readPreferences: readPreferences
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// region Public API
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Read plugin preferences from the config.xml file.
|
|
16
|
+
*
|
|
17
|
+
* @param {Object} cordovaContext - cordova context object
|
|
18
|
+
* @return {Array} list of host objects
|
|
19
|
+
*/
|
|
20
|
+
function readPreferences(cordovaContext) {
|
|
21
|
+
// read data from projects root config.xml file
|
|
22
|
+
var configXml = new ConfigXmlHelper(cordovaContext).read();
|
|
23
|
+
if (configXml == null) {
|
|
24
|
+
console.warn('config.xml not found! Please, check that it exist\'s in your project\'s root directory.');
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// look for data from the <universal-links> tag
|
|
29
|
+
var ulXmlPreferences = configXml.widget['universal-links'];
|
|
30
|
+
if (ulXmlPreferences == null || ulXmlPreferences.length == 0) {
|
|
31
|
+
console.warn('<universal-links> tag is not set in the config.xml. Universal Links plugin is not going to work.');
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
var xmlPreferences = ulXmlPreferences[0];
|
|
36
|
+
|
|
37
|
+
// read hosts
|
|
38
|
+
var hosts = constructHostsList(xmlPreferences);
|
|
39
|
+
|
|
40
|
+
// read ios team ID
|
|
41
|
+
var iosTeamId = getTeamIdPreference(xmlPreferences);
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
'hosts': hosts,
|
|
45
|
+
'iosTeamId': iosTeamId
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// endregion
|
|
50
|
+
|
|
51
|
+
// region Private API
|
|
52
|
+
|
|
53
|
+
function getTeamIdPreference(xmlPreferences) {
|
|
54
|
+
if (xmlPreferences.hasOwnProperty('ios-team-id')) {
|
|
55
|
+
return xmlPreferences['ios-team-id'][0]['$']['value'];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Construct list of host objects, defined in xml file.
|
|
63
|
+
*
|
|
64
|
+
* @param {Object} xmlPreferences - plugin preferences from config.xml as JSON object
|
|
65
|
+
* @return {Array} array of JSON objects, where each entry defines host data from config.xml.
|
|
66
|
+
*/
|
|
67
|
+
function constructHostsList(xmlPreferences) {
|
|
68
|
+
var hostsList = [];
|
|
69
|
+
|
|
70
|
+
// look for defined hosts
|
|
71
|
+
var xmlHostList = xmlPreferences['host'];
|
|
72
|
+
if (xmlHostList == null || xmlHostList.length == 0) {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
xmlHostList.forEach(function(xmlElement) {
|
|
77
|
+
var host = constructHostEntry(xmlElement);
|
|
78
|
+
if (host) {
|
|
79
|
+
hostsList.push(host);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return hostsList;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Construct host object from xml data.
|
|
88
|
+
*
|
|
89
|
+
* @param {Object} xmlElement - xml data to process.
|
|
90
|
+
* @return {Object} host entry as JSON object
|
|
91
|
+
*/
|
|
92
|
+
function constructHostEntry(xmlElement) {
|
|
93
|
+
var host = {
|
|
94
|
+
scheme: DEFAULT_SCHEME,
|
|
95
|
+
name: '',
|
|
96
|
+
paths: []
|
|
97
|
+
};
|
|
98
|
+
var hostProperties = xmlElement['$'];
|
|
99
|
+
|
|
100
|
+
if (hostProperties == null || hostProperties.length == 0) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// read host name
|
|
105
|
+
host.name = hostProperties.name;
|
|
106
|
+
|
|
107
|
+
// read scheme if defined
|
|
108
|
+
if (hostProperties['scheme'] != null) {
|
|
109
|
+
host.scheme = hostProperties.scheme;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// construct paths list, defined for the given host
|
|
113
|
+
host.paths = constructPaths(xmlElement);
|
|
114
|
+
|
|
115
|
+
return host;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Construct list of path objects from the xml data.
|
|
120
|
+
*
|
|
121
|
+
* @param {Object} xmlElement - xml data to process
|
|
122
|
+
* @return {Array} list of path entries, each on is a JSON object
|
|
123
|
+
*/
|
|
124
|
+
function constructPaths(xmlElement) {
|
|
125
|
+
if (xmlElement['path'] == null) {
|
|
126
|
+
return ['*'];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
var paths = [];
|
|
130
|
+
xmlElement.path.some(function(pathElement) {
|
|
131
|
+
var url = pathElement['$']['url'];
|
|
132
|
+
|
|
133
|
+
// Ignore explicit paths if '*' is defined
|
|
134
|
+
if (url === '*') {
|
|
135
|
+
paths = ['*'];
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
paths.push(url);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
return paths;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// endregion
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Script generates apple-app-site-association files: one for each domain, defined in config.xml.
|
|
3
|
+
It is executed on 'after prepare' stage, usually when you execute 'cordova build'. Files are placed in 'ul_web_hooks/ios/' folder
|
|
4
|
+
of your projects root.
|
|
5
|
+
|
|
6
|
+
Files are created with the following name:
|
|
7
|
+
hostname#apple-app-site-association
|
|
8
|
+
|
|
9
|
+
Prefix 'hostname#' describes on which host this file should be placed. Don't forget to remove it before uploading file on your host.
|
|
10
|
+
Also, in the file you need to replace <YOUR_TEAM_ID_FROM_MEMBER_CENTER> with the real team id from the member center, if <ios-team-id> preference was not set in projects config.xml.
|
|
11
|
+
|
|
12
|
+
In order to activate support for Universal Links on iOS you need to sign them with the valid SSL certificate and place in the root of your domain.
|
|
13
|
+
|
|
14
|
+
Additional documentation regarding apple-app-site-association file can be found here:
|
|
15
|
+
- https://developer.apple.com/library/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html
|
|
16
|
+
- https://developer.apple.com/library/ios/documentation/Security/Reference/SharedWebCredentialsRef/index.html#//apple_ref/doc/uid/TP40014989
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
var path = require('path');
|
|
21
|
+
var mkpath = require('mkpath');
|
|
22
|
+
var fs = require('fs');
|
|
23
|
+
var rimraf = require('rimraf');
|
|
24
|
+
var ConfigXmlHelper = require('../configXmlHelper.js');
|
|
25
|
+
var IOS_TEAM_ID = '<YOUR_TEAM_ID_FROM_MEMBER_CENTER>';
|
|
26
|
+
var ASSOCIATION_FILE_NAME = 'apple-app-site-association';
|
|
27
|
+
var bundleId;
|
|
28
|
+
var context;
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
generate: generate
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// region Public API
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Generate apple-app-site-association files.
|
|
38
|
+
*
|
|
39
|
+
* @param {Object} cordovaContext - cordova context object
|
|
40
|
+
* @param {Object} pluginPreferences - list of hosts from the config.xml; already parsed
|
|
41
|
+
*/
|
|
42
|
+
function generate(cordovaContext, pluginPreferences) {
|
|
43
|
+
context = cordovaContext;
|
|
44
|
+
removeOldFiles();
|
|
45
|
+
createNewAssociationFiles(pluginPreferences);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// endregion
|
|
49
|
+
|
|
50
|
+
// region Content generation
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Remove old files from ul_web_hooks/ios folder.
|
|
54
|
+
*/
|
|
55
|
+
function removeOldFiles() {
|
|
56
|
+
rimraf.sync(getWebHookDirectory());
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Generate new set of apple-app-site-association files.
|
|
61
|
+
*
|
|
62
|
+
* @param {Object} pluginPreferences - list of hosts from config.xml
|
|
63
|
+
*/
|
|
64
|
+
function createNewAssociationFiles(pluginPreferences) {
|
|
65
|
+
var teamId = pluginPreferences.iosTeamId;
|
|
66
|
+
if (!teamId) {
|
|
67
|
+
teamId = IOS_TEAM_ID;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
pluginPreferences.hosts.forEach(function(host) {
|
|
71
|
+
var content = generateFileContentForHost(host, teamId);
|
|
72
|
+
saveContentToFile(host.name, content);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Generate content of the apple-app-site-association file for the specific host.
|
|
78
|
+
*
|
|
79
|
+
* @param {Object} host - host information
|
|
80
|
+
* @return {Object} content of the file as JSON object
|
|
81
|
+
*/
|
|
82
|
+
function generateFileContentForHost(host, teamId) {
|
|
83
|
+
var appID = teamId + '.' + getBundleId();
|
|
84
|
+
var paths = host.paths.slice();
|
|
85
|
+
|
|
86
|
+
// if paths are '*' - we should add '/' to it to support root domains.
|
|
87
|
+
// https://github.com/nordnet/cordova-universal-links-plugin/issues/46
|
|
88
|
+
if (paths.length == 1 && paths[0] === '*') {
|
|
89
|
+
paths.push('/');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
"applinks": {
|
|
94
|
+
"apps": [],
|
|
95
|
+
"details": [{
|
|
96
|
+
"appID": appID,
|
|
97
|
+
"paths": paths
|
|
98
|
+
}]
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Save data to the the apple-app-site-association file.
|
|
105
|
+
*
|
|
106
|
+
* @param {String} filePrefix - prefix for the generated file; usually - hostname
|
|
107
|
+
* @param {Object} content - file content as JSON object
|
|
108
|
+
*/
|
|
109
|
+
function saveContentToFile(filePrefix, content) {
|
|
110
|
+
var dirPath = getWebHookDirectory();
|
|
111
|
+
var filePath = path.join(dirPath, filePrefix + '#' + ASSOCIATION_FILE_NAME);
|
|
112
|
+
|
|
113
|
+
// create all directories from file path
|
|
114
|
+
createDirectoriesIfNeeded(dirPath);
|
|
115
|
+
|
|
116
|
+
// write content to the file
|
|
117
|
+
try {
|
|
118
|
+
fs.writeFileSync(filePath, JSON.stringify(content, null, 2), 'utf8');
|
|
119
|
+
} catch (err) {
|
|
120
|
+
console.log(err);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Create all directories from the given path.
|
|
126
|
+
*
|
|
127
|
+
* @param {String} dirPath - full path to directory
|
|
128
|
+
*/
|
|
129
|
+
function createDirectoriesIfNeeded(dirPath) {
|
|
130
|
+
try {
|
|
131
|
+
mkpath.sync(dirPath);
|
|
132
|
+
} catch (err) {
|
|
133
|
+
console.log(err);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// endregion
|
|
138
|
+
|
|
139
|
+
// region Support methods
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Path to the ios web hook directory.
|
|
143
|
+
*
|
|
144
|
+
* @return {String} path to web hook directory
|
|
145
|
+
*/
|
|
146
|
+
function getWebHookDirectory() {
|
|
147
|
+
return path.join(getProjectRoot(), 'ul_web_hooks', 'ios');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Project root directory
|
|
152
|
+
*
|
|
153
|
+
* @return {String} absolute path to project root
|
|
154
|
+
*/
|
|
155
|
+
function getProjectRoot() {
|
|
156
|
+
return context.opts.projectRoot;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get bundle id from the config.xml file.
|
|
161
|
+
*
|
|
162
|
+
* @return {String} bundle id
|
|
163
|
+
*/
|
|
164
|
+
function getBundleId() {
|
|
165
|
+
if (bundleId === undefined) {
|
|
166
|
+
var configXmlHelper = new ConfigXmlHelper(context);
|
|
167
|
+
bundleId = configXmlHelper.getPackageName('ios');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return bundleId;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// endregion
|