diff --git a/.gitignore b/.gitignore index 69a54264..c4c53182 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,4 @@ testbed/plugins testbed/hooks node_modules testbed/ul_web_hooks/ -.installed - -tests -www -hooks -testbed/www/js \ No newline at end of file +.installed \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 57c7af2e..bb61feeb 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -119,7 +119,11 @@ gulp.task('babel', babelTasks); gulp.task('lint', [ 'eslint', 'jscs-lint' ]); var srcs = [ - '**/*.js', + 'hooks.es6/**/*.js', + 'www.es6/**/*.js', + 'gulpfile.js', + 'tests.es6/**/*.js', + 'testbed/www/js.es6/**/*.js', '!node_modules/**', '!testbed/platforms/**', '!testbed/plugins/**', diff --git a/hooks/afterPrepareHook.js b/hooks/afterPrepareHook.js new file mode 100755 index 00000000..1a6cd505 --- /dev/null +++ b/hooks/afterPrepareHook.js @@ -0,0 +1,83 @@ +'use strict'; + +/** +Hook is executed at the end of the 'prepare' stage. Usually, when you call 'cordova build'. + +It will inject required preferences in the platform-specific projects, based on +data you have specified in the projects config.xml file. +*/ + +var configParser = require('./lib/configXmlParser.js'), + androidManifestWriter = require('./lib/android/manifestWriter.js'), + +// androidWebHook = require('./lib/android/webSiteHook.js'), +iosProjectEntitlements = require('./lib/ios/projectEntitlements.js'), + iosProjectPreferences = require('./lib/ios/xcodePreferences.js'), + ANDROID = 'android', + IOS = 'ios'; + +module.exports = function (ctx) { + run(ctx); +}; + +/** + * Execute hook. + * + * @param {Object} cordovaContext - cordova context object + */ +function run(cordovaContext) { + var pluginPreferences = configParser.readPreferences(cordovaContext), + platformsList = cordovaContext.opts.platforms; + + // if no preferences are found - exit + if (pluginPreferences == null) { + return; + } + + // if no host is defined - exit + if (pluginPreferences.hosts == null || pluginPreferences.hosts.length == 0) { + console.warn('No host is specified in the config.xml. Universal Links plugin is not going to work.'); + return; + } + + platformsList.forEach(function (platform) { + switch (platform) { + case ANDROID: + { + activateUniversalLinksInAndroid(cordovaContext, pluginPreferences); + break; + } + case IOS: + { + activateUniversalLinksInIos(cordovaContext, pluginPreferences); + break; + } + } + }); +} + +/** + * Activate Deep Links for Android application. + * + * @param {Object} cordovaContext - cordova context object + * @param {Object} pluginPreferences - plugin preferences from the config.xml file. Basically, content from tag. + */ +function activateUniversalLinksInAndroid(cordovaContext, pluginPreferences) { + // inject preferenes into AndroidManifest.xml + androidManifestWriter.writePreferences(cordovaContext, pluginPreferences); +} + +/** + * Activate Universal Links for iOS application. + * + * @param {Object} cordovaContext - cordova context object + * @param {Object} pluginPreferences - plugin preferences from the config.xml file. Basically, content from tag. + */ +function activateUniversalLinksInIos(cordovaContext, pluginPreferences) { + // modify xcode project preferences + iosProjectPreferences.enableAssociativeDomainsCapability(cordovaContext); + + // generate entitlements file + iosProjectEntitlements.generateAssociatedDomainsEntitlements(cordovaContext, pluginPreferences); +} +//# sourceMappingURL=afterPrepareHook.js.map diff --git a/hooks/afterPrepareHook.js.map b/hooks/afterPrepareHook.js.map new file mode 100644 index 00000000..d47adedb --- /dev/null +++ b/hooks/afterPrepareHook.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["afterPrepareHook.js"],"names":[],"mappings":";;AAAA;;;;;;;AAOA,IAAI,eAAe,QAAQ,0BAAR,CAAnB;AAAA,IACE,wBAAwB,QAAQ,iCAAR,CAD1B;;AAEE;AACA,yBAAyB,QAAQ,kCAAR,CAH3B;AAAA,IAIE,wBAAwB,QAAQ,+BAAR,CAJ1B;AAAA,IAKE,UAAU,SALZ;AAAA,IAME,MAAM,KANR;;AAQA,OAAO,OAAP,GAAiB,UAAS,GAAT,EAAc;AAC7B,MAAI,GAAJ;AACD,CAFD;;AAIA;;;;;AAKA,SAAS,GAAT,CAAa,cAAb,EAA6B;AAC3B,MAAI,oBAAoB,aAAa,eAAb,CAA6B,cAA7B,CAAxB;AAAA,MACE,gBAAgB,eAAe,IAAf,CAAoB,SADtC;;AAGA;AACA,MAAI,qBAAqB,IAAzB,EAA+B;AAC7B;AACD;;AAED;AACA,MAAI,kBAAkB,KAAlB,IAA2B,IAA3B,IAAmC,kBAAkB,KAAlB,CAAwB,MAAxB,IAAkC,CAAzE,EAA4E;AAC1E,YAAQ,IAAR,CAAa,sFAAb;AACA;AACD;;AAED,gBAAc,OAAd,CAAsB,UAAS,QAAT,EAAmB;AACvC,YAAQ,QAAR;AACE,WAAK,OAAL;AAAc;AACV,0CAAgC,cAAhC,EAAgD,iBAAhD;AACA;AACD;AACH,WAAK,GAAL;AAAU;AACN,sCAA4B,cAA5B,EAA4C,iBAA5C;AACA;AACD;AARL;AAUD,GAXD;AAYD;;AAED;;;;;;AAMA,SAAS,+BAAT,CAAyC,cAAzC,EAAyD,iBAAzD,EAA4E;AAC1E;AACA,wBAAsB,gBAAtB,CAAuC,cAAvC,EAAuD,iBAAvD;AAED;;AAED;;;;;;AAMA,SAAS,2BAAT,CAAqC,cAArC,EAAqD,iBAArD,EAAwE;AACtE;AACA,wBAAsB,kCAAtB,CAAyD,cAAzD;;AAEA;AACA,yBAAuB,qCAAvB,CAA6D,cAA7D,EAA6E,iBAA7E;AAED","file":"afterPrepareHook.js","sourcesContent":["/**\nHook is executed at the end of the 'prepare' stage. Usually, when you call 'cordova build'.\n\nIt will inject required preferences in the platform-specific projects, based on \ndata you have specified in the projects config.xml file.\n*/\n\nvar configParser = require('./lib/configXmlParser.js'),\n androidManifestWriter = require('./lib/android/manifestWriter.js'),\n // androidWebHook = require('./lib/android/webSiteHook.js'),\n iosProjectEntitlements = require('./lib/ios/projectEntitlements.js'),\n iosProjectPreferences = require('./lib/ios/xcodePreferences.js'),\n ANDROID = 'android',\n IOS = 'ios';\n\nmodule.exports = function(ctx) {\n run(ctx);\n};\n\n/**\n * Execute hook.\n *\n * @param {Object} cordovaContext - cordova context object\n */\nfunction run(cordovaContext) {\n var pluginPreferences = configParser.readPreferences(cordovaContext),\n platformsList = cordovaContext.opts.platforms;\n\n // if no preferences are found - exit\n if (pluginPreferences == null) {\n return;\n }\n\n // if no host is defined - exit\n if (pluginPreferences.hosts == null || pluginPreferences.hosts.length == 0) {\n console.warn('No host is specified in the config.xml. Universal Links plugin is not going to work.');\n return;\n }\n\n platformsList.forEach(function(platform) {\n switch (platform) {\n case ANDROID: {\n activateUniversalLinksInAndroid(cordovaContext, pluginPreferences);\n break;\n }\n case IOS: {\n activateUniversalLinksInIos(cordovaContext, pluginPreferences);\n break;\n }\n }\n });\n}\n\n/**\n * Activate Deep Links for Android application.\n *\n * @param {Object} cordovaContext - cordova context object\n * @param {Object} pluginPreferences - plugin preferences from the config.xml file. Basically, content from tag.\n */\nfunction activateUniversalLinksInAndroid(cordovaContext, pluginPreferences) {\n // inject preferenes into AndroidManifest.xml\n androidManifestWriter.writePreferences(cordovaContext, pluginPreferences);\n\n}\n\n/**\n * Activate Universal Links for iOS application.\n *\n * @param {Object} cordovaContext - cordova context object\n * @param {Object} pluginPreferences - plugin preferences from the config.xml file. Basically, content from tag.\n */\nfunction activateUniversalLinksInIos(cordovaContext, pluginPreferences) {\n // modify xcode project preferences\n iosProjectPreferences.enableAssociativeDomainsCapability(cordovaContext);\n\n // generate entitlements file\n iosProjectEntitlements.generateAssociatedDomainsEntitlements(cordovaContext, pluginPreferences);\n\n}\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/hooks/beforePluginInstallHook.js b/hooks/beforePluginInstallHook.js new file mode 100755 index 00000000..db021c96 --- /dev/null +++ b/hooks/beforePluginInstallHook.js @@ -0,0 +1,156 @@ +'use strict'; + +/** +Hook is executed when plugin is added to the project. +It will check all necessary module dependencies and install the missing ones locally. +*/ + +var exec = require('child_process').exec, + path = require('path'), + fs = require('fs'), + INSTALLATION_FLAG_FILE_NAME = '.installed'; + +// region NPM specific + +/** + * Check if node package is installed. + * + * @param {String} moduleName + * @return {Boolean} true if package already installed + */ +function isNodeModuleInstalled(moduleName) { + var installed = true; + try { + var module = require(moduleName); + } catch (err) { + installed = false; + } + + return installed; +} + +/** + * Install node module locally. + * Basically, it runs 'npm install module_name'. + * + * @param {String} moduleName + * @param {Callback(error)} callback + */ +function installNodeModule(moduleName, callback) { + if (isNodeModuleInstalled(moduleName)) { + printLog('Node module ' + moduleName + ' is found'); + callback(null); + return; + } + printLog('Can\'t find module ' + moduleName + ', running npm install'); + + var cmd = 'npm install -D ' + moduleName; + exec(cmd, function (err, stdout, stderr) { + callback(err); + }); +} + +/** + * Install all required node packages. + */ +function installRequiredNodeModules(modulesToInstall) { + if (!modulesToInstall.length) { + return; + } + + var moduleName = modulesToInstall.shift(); + installNodeModule(moduleName, function (err) { + if (err) { + printLog('Failed to install module ' + moduleName + ':' + err); + return; + } + + printLog('Module ' + moduleName + ' is installed'); + installRequiredNodeModules(modulesToInstall); + }); +} + +// endregion + +// region Logging + +function logStart() { + console.log('Checking dependencies:'); +} + +function printLog(msg) { + var formattedMsg = ' ' + msg; + console.log(formattedMsg); +} + +// endregion + +// region Private API + +/** + * Check if we already executed this hook. + * + * @param {Object} ctx - cordova context + * @return {Boolean} true if already executed; otherwise - false + */ +function isInstallationAlreadyPerformed(ctx) { + var pathToInstallFlag = path.join(ctx.opts.projectRoot, 'plugins', ctx.opts.plugin.id, INSTALLATION_FLAG_FILE_NAME), + isInstalled = false; + try { + var content = fs.readFileSync(pathToInstallFlag); + isInstalled = true; + } catch (err) {} + + return isInstalled; +} + +/** + * Create empty file - indicator, that we tried to install dependency modules after installation. + * We have to do that, or this hook is gonna be called on any plugin installation. + */ +function createPluginInstalledFlag(ctx) { + var pathToInstallFlag = path.join(ctx.opts.projectRoot, 'plugins', ctx.opts.plugin.id, INSTALLATION_FLAG_FILE_NAME); + + fs.closeSync(fs.openSync(pathToInstallFlag, 'w')); +} + +// endregion + +/** + * Read dependencies from the package.json. + * We will install them on the next step. + * + * @param {Object} ctx - cordova context + * @return {Array} list of modules to install + */ +function readDependenciesFromPackageJson(ctx) { + var data = require(path.join(ctx.opts.projectRoot, 'plugins', ctx.opts.plugin.id, 'package.json')), + dependencies = data['dependencies'], + modules = []; + + if (!dependencies) { + return modules; + } + + for (var module in dependencies) { + modules.push(module); + } + + return modules; +} + +// hook's entry point +module.exports = function (ctx) { + // exit if we already executed this hook once + if (isInstallationAlreadyPerformed(ctx)) { + return; + } + + logStart(); + + var modules = readDependenciesFromPackageJson(ctx); + installRequiredNodeModules(modules); + + createPluginInstalledFlag(ctx); +}; +//# sourceMappingURL=beforePluginInstallHook.js.map diff --git a/hooks/beforePluginInstallHook.js.map b/hooks/beforePluginInstallHook.js.map new file mode 100644 index 00000000..97354a78 --- /dev/null +++ b/hooks/beforePluginInstallHook.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["beforePluginInstallHook.js"],"names":[],"mappings":"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","file":"beforePluginInstallHook.js","sourcesContent":["/**\nHook is executed when plugin is added to the project.\nIt will check all necessary module dependencies and install the missing ones locally.\n*/\n\nvar exec = require('child_process').exec,\n path = require('path'),\n fs = require('fs'),\n INSTALLATION_FLAG_FILE_NAME = '.installed';\n\n// region NPM specific\n\n/**\n * Check if node package is installed.\n *\n * @param {String} moduleName\n * @return {Boolean} true if package already installed\n */\nfunction isNodeModuleInstalled(moduleName) {\n var installed = true;\n try {\n var module = require(moduleName);\n } catch (err) {\n installed = false;\n }\n\n return installed;\n}\n\n/**\n * Install node module locally.\n * Basically, it runs 'npm install module_name'.\n *\n * @param {String} moduleName\n * @param {Callback(error)} callback\n */\nfunction installNodeModule(moduleName, callback) {\n if (isNodeModuleInstalled(moduleName)) {\n printLog('Node module ' + moduleName + ' is found');\n callback(null);\n return;\n }\n printLog('Can\\'t find module ' + moduleName + ', running npm install');\n\n var cmd = 'npm install -D ' + moduleName;\n exec(cmd, function(err, stdout, stderr) {\n callback(err);\n });\n}\n\n/**\n * Install all required node packages.\n */\nfunction installRequiredNodeModules(modulesToInstall) {\n if (!modulesToInstall.length) {\n return;\n }\n\n var moduleName = modulesToInstall.shift();\n installNodeModule(moduleName, function(err) {\n if (err) {\n printLog('Failed to install module ' + moduleName + ':' + err);\n return;\n }\n\n printLog('Module ' + moduleName + ' is installed');\n installRequiredNodeModules(modulesToInstall);\n });\n}\n\n// endregion\n\n// region Logging\n\nfunction logStart() {\n console.log('Checking dependencies:');\n}\n\nfunction printLog(msg) {\n var formattedMsg = ' ' + msg;\n console.log(formattedMsg);\n}\n\n// endregion\n\n// region Private API\n\n/**\n * Check if we already executed this hook.\n *\n * @param {Object} ctx - cordova context\n * @return {Boolean} true if already executed; otherwise - false\n */\nfunction isInstallationAlreadyPerformed(ctx) {\n var pathToInstallFlag = path.join(ctx.opts.projectRoot, 'plugins', ctx.opts.plugin.id, INSTALLATION_FLAG_FILE_NAME),\n isInstalled = false;\n try {\n var content = fs.readFileSync(pathToInstallFlag);\n isInstalled = true;\n } catch (err) {\n }\n\n return isInstalled;\n}\n\n/**\n * Create empty file - indicator, that we tried to install dependency modules after installation.\n * We have to do that, or this hook is gonna be called on any plugin installation.\n */\nfunction createPluginInstalledFlag(ctx) {\n var pathToInstallFlag = path.join(ctx.opts.projectRoot, 'plugins', ctx.opts.plugin.id, INSTALLATION_FLAG_FILE_NAME);\n\n fs.closeSync(fs.openSync(pathToInstallFlag, 'w'));\n}\n\n// endregion\n\n/**\n * Read dependencies from the package.json.\n * We will install them on the next step.\n *\n * @param {Object} ctx - cordova context\n * @return {Array} list of modules to install\n */\nfunction readDependenciesFromPackageJson(ctx) {\n var data = require(path.join(ctx.opts.projectRoot, 'plugins', ctx.opts.plugin.id, 'package.json')),\n dependencies = data['dependencies'],\n modules = [];\n\n if (!dependencies) {\n return modules;\n }\n\n for (var module in dependencies) {\n modules.push(module);\n }\n\n return modules;\n}\n\n// hook's entry point\nmodule.exports = function(ctx) {\n // exit if we already executed this hook once\n if (isInstallationAlreadyPerformed(ctx)) {\n return;\n }\n\n logStart();\n\n var modules = readDependenciesFromPackageJson(ctx);\n installRequiredNodeModules(modules);\n\n createPluginInstalledFlag(ctx);\n};\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/hooks/iosBeforePrepareHook.js b/hooks/iosBeforePrepareHook.js new file mode 100755 index 00000000..e8aac99c --- /dev/null +++ b/hooks/iosBeforePrepareHook.js @@ -0,0 +1,81 @@ +'use strict'; + +/* +Hook executed before the 'prepare' stage. Only for iOS project. +It will check if project name has changed. If so - it will change the name of the .entitlements file to remove that file duplicates. +If file name has no changed - hook would not do anything. +*/ + +var path = require('path'), + fs = require('fs'), + ConfigXmlHelper = require('./lib/configXmlHelper.js'); + +module.exports = function (ctx) { + run(ctx); +}; + +/** + * Run the hook logic. + * + * @param {Object} ctx - cordova context object + */ +function run(ctx) { + var projectRoot = ctx.opts.projectRoot, + iosProjectFilePath = path.join(projectRoot, 'platforms', 'ios'), + configXmlHelper = new ConfigXmlHelper(ctx), + oldProjectName = getOldProjectName(iosProjectFilePath), + newProjectName = configXmlHelper.getProjectName(); + + // if name has not changed - do nothing + if (oldProjectName.length > 0 && oldProjectName === newProjectName) { + return; + } + + console.log('Project name has changed. Renaming .entitlements file.'); + + // if it does - rename it + var oldEntitlementsFilePath = path.join(iosProjectFilePath, oldProjectName, 'Resources', oldProjectName + '.entitlements'), + newEntitlementsFilePath = path.join(iosProjectFilePath, oldProjectName, 'Resources', newProjectName + '.entitlements'); + + try { + fs.renameSync(oldEntitlementsFilePath, newEntitlementsFilePath); + } catch (err) { + console.warn('Failed to rename .entitlements file.'); + console.warn(err); + } +} + +// region Private API + +/** + * Get old name of the project. + * Name is detected by the name of the .xcodeproj file. + * + * @param {String} projectDir absolute path to ios project directory + * @return {String} old project name + */ +function getOldProjectName(projectDir) { + var files = [], + projectName = ''; + + try { + files = fs.readdirSync(projectDir); + } catch (err) { + return ''; + } + + // find file with .xcodeproj extension, use it as an old project name + files.some(function (fileName) { + if (path.extname(fileName) === '.xcodeproj') { + projectName = path.basename(fileName, '.xcodeproj'); + return true; + } + + return false; + }); + + return projectName; +} + +// endregion +//# sourceMappingURL=iosBeforePrepareHook.js.map diff --git a/hooks/iosBeforePrepareHook.js.map b/hooks/iosBeforePrepareHook.js.map new file mode 100644 index 00000000..1e25460e --- /dev/null +++ b/hooks/iosBeforePrepareHook.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["iosBeforePrepareHook.js"],"names":[],"mappings":";;AAAA;;;;;;AAMA,IAAI,OAAO,QAAQ,MAAR,CAAX;AAAA,IACE,KAAK,QAAQ,IAAR,CADP;AAAA,IAEE,kBAAkB,QAAQ,0BAAR,CAFpB;;AAIA,OAAO,OAAP,GAAiB,UAAS,GAAT,EAAc;AAC7B,MAAI,GAAJ;AACD,CAFD;;AAIA;;;;;AAKA,SAAS,GAAT,CAAa,GAAb,EAAkB;AAChB,MAAI,cAAc,IAAI,IAAJ,CAAS,WAA3B;AAAA,MACE,qBAAqB,KAAK,IAAL,CAAU,WAAV,EAAuB,WAAvB,EAAoC,KAApC,CADvB;AAAA,MAEE,kBAAkB,IAAI,eAAJ,CAAoB,GAApB,CAFpB;AAAA,MAGE,iBAAiB,kBAAkB,kBAAlB,CAHnB;AAAA,MAIE,iBAAiB,gBAAgB,cAAhB,EAJnB;;AAMA;AACA,MAAI,eAAe,MAAf,GAAwB,CAAxB,IAA6B,mBAAmB,cAApD,EAAoE;AAClE;AACD;;AAED,UAAQ,GAAR,CAAY,wDAAZ;;AAEA;AACA,MAAI,0BAA0B,KAAK,IAAL,CAAU,kBAAV,EAA8B,cAA9B,EAA8C,WAA9C,EAA2D,iBAAiB,eAA5E,CAA9B;AAAA,MACE,0BAA0B,KAAK,IAAL,CAAU,kBAAV,EAA8B,cAA9B,EAA8C,WAA9C,EAA2D,iBAAiB,eAA5E,CAD5B;;AAGA,MAAI;AACF,OAAG,UAAH,CAAc,uBAAd,EAAuC,uBAAvC;AACD,GAFD,CAEE,OAAO,GAAP,EAAY;AACZ,YAAQ,IAAR,CAAa,sCAAb;AACA,YAAQ,IAAR,CAAa,GAAb;AACD;AACF;;AAED;;AAEA;;;;;;;AAOA,SAAS,iBAAT,CAA2B,UAA3B,EAAuC;AACrC,MAAI,QAAQ,EAAZ;AAAA,MACE,cAAc,EADhB;;AAGA,MAAI;AACF,YAAQ,GAAG,WAAH,CAAe,UAAf,CAAR;AACD,GAFD,CAEE,OAAO,GAAP,EAAY;AACZ,WAAO,EAAP;AACD;;AAED;AACA,QAAM,IAAN,CAAW,UAAS,QAAT,EAAmB;AAC5B,QAAI,KAAK,OAAL,CAAa,QAAb,MAA2B,YAA/B,EAA6C;AAC3C,oBAAc,KAAK,QAAL,CAAc,QAAd,EAAwB,YAAxB,CAAd;AACA,aAAO,IAAP;AACD;;AAED,WAAO,KAAP;AACD,GAPD;;AASA,SAAO,WAAP;AACD;;AAED","file":"iosBeforePrepareHook.js","sourcesContent":["/*\nHook executed before the 'prepare' stage. Only for iOS project.\nIt will check if project name has changed. If so - it will change the name of the .entitlements file to remove that file duplicates.\nIf file name has no changed - hook would not do anything.\n*/\n\nvar path = require('path'),\n fs = require('fs'),\n ConfigXmlHelper = require('./lib/configXmlHelper.js');\n\nmodule.exports = function(ctx) {\n run(ctx);\n};\n\n/**\n * Run the hook logic.\n *\n * @param {Object} ctx - cordova context object\n */\nfunction run(ctx) {\n var projectRoot = ctx.opts.projectRoot,\n iosProjectFilePath = path.join(projectRoot, 'platforms', 'ios'),\n configXmlHelper = new ConfigXmlHelper(ctx),\n oldProjectName = getOldProjectName(iosProjectFilePath),\n newProjectName = configXmlHelper.getProjectName();\n\n // if name has not changed - do nothing\n if (oldProjectName.length > 0 && oldProjectName === newProjectName) {\n return;\n }\n\n console.log('Project name has changed. Renaming .entitlements file.');\n\n // if it does - rename it\n var oldEntitlementsFilePath = path.join(iosProjectFilePath, oldProjectName, 'Resources', oldProjectName + '.entitlements'),\n newEntitlementsFilePath = path.join(iosProjectFilePath, oldProjectName, 'Resources', newProjectName + '.entitlements');\n\n try {\n fs.renameSync(oldEntitlementsFilePath, newEntitlementsFilePath);\n } catch (err) {\n console.warn('Failed to rename .entitlements file.');\n console.warn(err);\n }\n}\n\n// region Private API\n\n/**\n * Get old name of the project.\n * Name is detected by the name of the .xcodeproj file.\n *\n * @param {String} projectDir absolute path to ios project directory\n * @return {String} old project name\n */\nfunction getOldProjectName(projectDir) {\n var files = [],\n projectName = '';\n\n try {\n files = fs.readdirSync(projectDir);\n } catch (err) {\n return '';\n }\n\n // find file with .xcodeproj extension, use it as an old project name\n files.some(function(fileName) {\n if (path.extname(fileName) === '.xcodeproj') {\n projectName = path.basename(fileName, '.xcodeproj');\n return true;\n }\n\n return false;\n });\n\n return projectName;\n}\n\n// endregion\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/hooks/lib/android/manifestWriter.js b/hooks/lib/android/manifestWriter.js new file mode 100755 index 00000000..ff06d7db --- /dev/null +++ b/hooks/lib/android/manifestWriter.js @@ -0,0 +1,300 @@ +'use strict'; + +/** +Class injects plugin preferences into AndroidManifest.xml file. +*/ +(function () { + + var path = require('path'), + xmlHelper = require('../xmlHelper.js'); + + module.exports = { + writePreferences: writePreferences + }; + + // region Public API + + /** + * Inject preferences into AndroidManifest.xml file. + * + * @param {Object} cordovaContext - cordova context object + * @param {Object} pluginPreferences - plugin preferences as JSON object; already parsed + */ + function writePreferences(cordovaContext, pluginPreferences) { + var pathToManifest = path.join(cordovaContext.opts.projectRoot, 'platforms', 'android', 'AndroidManifest.xml'), + manifestSource = xmlHelper.readXmlAsJson(pathToManifest), + cleanManifest, + updatedManifest; + + // remove old intent-filters + cleanManifest = removeOldOptions(manifestSource); + + // inject intent-filters based on plugin preferences + updatedManifest = injectOptions(cleanManifest, pluginPreferences); + + // save new version of the AndroidManifest + xmlHelper.writeJsonAsXml(updatedManifest, pathToManifest); + } + + // endregion + + // region Manifest cleanup methods + + /** + * Remove old intent-filters from the manifest file. + * + * @param {Object} manifestData - manifest content as JSON object + * @return {Object} manifest data without old intent-filters + */ + function removeOldOptions(manifestData) { + var cleanManifest = manifestData, + activities = manifestData['manifest']['application'][0]['activity']; + + activities.forEach(removeIntentFiltersFromActivity); + cleanManifest['manifest']['application'][0]['activity'] = activities; + + return cleanManifest; + } + + /** + * Remove old intent filters from the given activity. + * + * @param {Object} activity - activity, from which we need to remove intent-filters. + * Changes applied to the passed object. + */ + function removeIntentFiltersFromActivity(activity) { + var oldIntentFilters = activity['intent-filter'], + newIntentFilters = []; + if (oldIntentFilters == null || oldIntentFilters.length == 0) { + return; + } + + oldIntentFilters.forEach(function (intentFilter) { + if (!isIntentFilterForUniversalLinks(intentFilter)) { + newIntentFilters.push(intentFilter); + } + }); + + activity['intent-filter'] = newIntentFilters; + } + + /** + * Check if given intent-filter is for Universal Links. + * + * @param {Object} intentFilter - intent-filter to check + * @return {Boolean} true - if intent-filter for Universal Links; otherwise - false; + */ + function isIntentFilterForUniversalLinks(intentFilter) { + var actions = intentFilter['action'], + categories = intentFilter['category'], + data = intentFilter['data']; + + return isActionForUniversalLinks(actions) && isCategoriesForUniversalLinks(categories) && isDataTagForUniversalLinks(data); + } + + /** + * Check if actions from the intent-filter corresponds to actions for Universal Links. + * + * @param {Array} actions - list of actions in the intent-filter + * @return {Boolean} true - if action for Universal Links; otherwise - false + */ + function isActionForUniversalLinks(actions) { + // there can be only 1 action + if (actions == null || actions.length != 1) { + return false; + } + + var action = actions[0]['$']['android:name']; + + return action === 'android.intent.action.VIEW'; + } + + /** + * Check if categories in the intent-filter corresponds to categories for Universal Links. + * + * @param {Array} categories - list of categories in the intent-filter + * @return {Boolean} true - if action for Universal Links; otherwise - false + */ + function isCategoriesForUniversalLinks(categories) { + // there can be only 2 categories + if (categories == null || categories.length != 2) { + return false; + } + + var isBrowsable = false, + isDefault = false; + + // check intent categories + categories.forEach(function (category) { + var categoryName = category['$']['android:name']; + if (!isBrowsable) { + isBrowsable = categoryName === 'android.intent.category.BROWSABLE'; + } + + if (!isDefault) { + isDefault = categoryName === 'android.intent.category.DEFAULT'; + } + }); + + return isDefault && isBrowsable; + } + + /** + * Check if data tag from intent-filter corresponds to data for Universal Links. + * + * @param {Array} data - list of data tags in the intent-filter + * @return {Boolean} true - if data tag for Universal Links; otherwise - false + */ + function isDataTagForUniversalLinks(data) { + // can have only 1 data tag in the intent-filter + if (data == null || data.length != 1) { + return false; + } + + var dataHost = data[0]['$']['android:host'], + dataScheme = data[0]['$']['android:scheme'], + hostIsSet = dataHost != null && dataHost.length > 0, + schemeIsSet = dataScheme != null && dataScheme.length > 0; + + return hostIsSet && schemeIsSet; + } + + // endregion + + // region Methods to inject preferences into AndroidManifest.xml file + + /** + * Inject options into manifest file. + * + * @param {Object} manifestData - manifest content where preferences should be injected + * @param {Object} pluginPreferences - plugin preferences from config.xml; already parsed + * @return {Object} updated manifest data with corresponding intent-filters + */ + function injectOptions(manifestData, pluginPreferences) { + var changedManifest = manifestData, + targetSdk = changedManifest['manifest']['uses-sdk'][0]['$']['android:targetSdkVersion'], + activitiesList = changedManifest['manifest']['application'][0]['activity'], + launchActivityIndex = getMainLaunchActivityIndex(activitiesList), + ulIntentFilters = [], + launchActivity; + + if (launchActivityIndex < 0) { + console.warn('Could not find launch activity in the AndroidManifest file. Can\'t inject Universal Links preferences.'); + return; + } + + // get launch activity + launchActivity = activitiesList[launchActivityIndex]; + + // generate intent-filters + pluginPreferences.hosts.forEach(function (host) { + ulIntentFilters.push(createIntentFilter(host.name, host.scheme, pluginPreferences.androidPrefix, parseInt(targetSdk) >= 23)); + }); + + // add Universal Links intent-filters to the launch activity + launchActivity['intent-filter'] = launchActivity['intent-filter'].concat(ulIntentFilters); + + return changedManifest; + } + + /** + * Find index of the applications launcher activity. + * + * @param {Array} activities - list of all activities in the app + * @return {Integer} index of the launch activity; -1 - if none was found + */ + function getMainLaunchActivityIndex(activities) { + var launchActivityIndex = -1; + activities.some(function (activity, index) { + if (isLaunchActivity(activity)) { + launchActivityIndex = index; + return true; + } + + return false; + }); + + return launchActivityIndex; + } + + /** + * Check if the given actvity is a launch activity. + * + * @param {Object} activity - activity to check + * @return {Boolean} true - if this is a launch activity; otherwise - false + */ + function isLaunchActivity(activity) { + var intentFilters = activity['intent-filter'], + isLauncher = false; + + if (intentFilters == null || intentFilters.length == 0) { + return false; + } + + isLauncher = intentFilters.some(function (intentFilter) { + var action = intentFilter['action'], + category = intentFilter['category']; + + if (action == null || action.length != 1 || category == null || category.length != 1) { + return false; + } + + var isMainAction = action[0]['$']['android:name'] === 'android.intent.action.MAIN', + isLauncherCategory = category[0]['$']['android:name'] === 'android.intent.category.LAUNCHER'; + + return isMainAction && isLauncherCategory; + }); + + return isLauncher; + } + + /** + * Create JSON object that represent intent-filter for universal link. + * + * @param {String} host - host name + * @param {String} scheme - host scheme + * @param {String} pathName - host path + * @return {Object} intent-filter as a JSON object + */ + function createIntentFilter(host, scheme, pathPrefix, androidM) { + var intentFilter = { + '$': { + 'android:autoVerify': 'true' + }, + 'action': [{ + '$': { + 'android:name': 'android.intent.action.VIEW' + } + }], + 'category': [{ + '$': { + 'android:name': 'android.intent.category.DEFAULT' + } + }, { + '$': { + 'android:name': 'android.intent.category.BROWSABLE' + } + }], + 'data': [{ + '$': { + 'android:host': host, + 'android:scheme': scheme, + 'android:pathPrefix': pathPrefix + } + }] + }; + + if (!pathPrefix) { + delete intentFilter['data'][0]['$']['android:pathPrefix']; + } + + if (!androidM) { + delete intentFilter['$']['android:autoVerify']; + } + + return intentFilter; + } + + // endregion +})(); +//# sourceMappingURL=manifestWriter.js.map diff --git a/hooks/lib/android/manifestWriter.js.map b/hooks/lib/android/manifestWriter.js.map new file mode 100644 index 00000000..d3408b02 --- /dev/null +++ b/hooks/lib/android/manifestWriter.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["lib/android/manifestWriter.js"],"names":[],"mappings":"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","file":"lib/android/manifestWriter.js","sourcesContent":["/**\nClass injects plugin preferences into AndroidManifest.xml file.\n*/\n(function() {\n\n var path = require('path'),\n xmlHelper = require('../xmlHelper.js');\n\n module.exports = {\n writePreferences: writePreferences\n };\n\n // region Public API\n\n /**\n * Inject preferences into AndroidManifest.xml file.\n *\n * @param {Object} cordovaContext - cordova context object\n * @param {Object} pluginPreferences - plugin preferences as JSON object; already parsed\n */\n function writePreferences(cordovaContext, pluginPreferences) {\n var pathToManifest = path.join(cordovaContext.opts.projectRoot, 'platforms', 'android', 'AndroidManifest.xml'),\n manifestSource = xmlHelper.readXmlAsJson(pathToManifest),\n cleanManifest,\n updatedManifest;\n\n // remove old intent-filters\n cleanManifest = removeOldOptions(manifestSource);\n\n // inject intent-filters based on plugin preferences\n updatedManifest = injectOptions(cleanManifest, pluginPreferences);\n\n // save new version of the AndroidManifest\n xmlHelper.writeJsonAsXml(updatedManifest, pathToManifest);\n }\n\n // endregion\n\n // region Manifest cleanup methods\n\n /**\n * Remove old intent-filters from the manifest file.\n *\n * @param {Object} manifestData - manifest content as JSON object\n * @return {Object} manifest data without old intent-filters\n */\n function removeOldOptions(manifestData) {\n var cleanManifest = manifestData,\n activities = manifestData['manifest']['application'][0]['activity'];\n\n activities.forEach(removeIntentFiltersFromActivity);\n cleanManifest['manifest']['application'][0]['activity'] = activities;\n\n return cleanManifest;\n }\n\n /**\n * Remove old intent filters from the given activity.\n *\n * @param {Object} activity - activity, from which we need to remove intent-filters.\n * Changes applied to the passed object.\n */\n function removeIntentFiltersFromActivity(activity) {\n var oldIntentFilters = activity['intent-filter'],\n newIntentFilters = [];\n if (oldIntentFilters == null || oldIntentFilters.length == 0) {\n return;\n }\n\n oldIntentFilters.forEach(function(intentFilter) {\n if (!isIntentFilterForUniversalLinks(intentFilter)) {\n newIntentFilters.push(intentFilter);\n }\n });\n\n activity['intent-filter'] = newIntentFilters;\n }\n\n /**\n * Check if given intent-filter is for Universal Links.\n *\n * @param {Object} intentFilter - intent-filter to check\n * @return {Boolean} true - if intent-filter for Universal Links; otherwise - false;\n */\n function isIntentFilterForUniversalLinks(intentFilter) {\n var actions = intentFilter['action'],\n categories = intentFilter['category'],\n data = intentFilter['data'];\n\n return isActionForUniversalLinks(actions) && isCategoriesForUniversalLinks(categories) && isDataTagForUniversalLinks(data);\n }\n\n /**\n * Check if actions from the intent-filter corresponds to actions for Universal Links.\n *\n * @param {Array} actions - list of actions in the intent-filter\n * @return {Boolean} true - if action for Universal Links; otherwise - false\n */\n function isActionForUniversalLinks(actions) {\n // there can be only 1 action\n if (actions == null || actions.length != 1) {\n return false;\n }\n\n var action = actions[0]['$']['android:name'];\n\n return action === 'android.intent.action.VIEW';\n }\n\n /**\n * Check if categories in the intent-filter corresponds to categories for Universal Links.\n *\n * @param {Array} categories - list of categories in the intent-filter\n * @return {Boolean} true - if action for Universal Links; otherwise - false\n */\n function isCategoriesForUniversalLinks(categories) {\n // there can be only 2 categories\n if (categories == null || categories.length != 2) {\n return false;\n }\n\n var isBrowsable = false,\n isDefault = false;\n\n // check intent categories\n categories.forEach(function(category) {\n var categoryName = category['$']['android:name'];\n if (!isBrowsable) {\n isBrowsable = categoryName === 'android.intent.category.BROWSABLE';\n }\n\n if (!isDefault) {\n isDefault = categoryName === 'android.intent.category.DEFAULT';\n }\n });\n\n return isDefault && isBrowsable;\n }\n\n /**\n * Check if data tag from intent-filter corresponds to data for Universal Links.\n *\n * @param {Array} data - list of data tags in the intent-filter\n * @return {Boolean} true - if data tag for Universal Links; otherwise - false\n */\n function isDataTagForUniversalLinks(data) {\n // can have only 1 data tag in the intent-filter\n if (data == null || data.length != 1) {\n return false;\n }\n\n var dataHost = data[0]['$']['android:host'],\n dataScheme = data[0]['$']['android:scheme'],\n hostIsSet = dataHost != null && dataHost.length > 0,\n schemeIsSet = dataScheme != null && dataScheme.length > 0;\n\n return hostIsSet && schemeIsSet;\n }\n\n // endregion\n\n // region Methods to inject preferences into AndroidManifest.xml file\n\n /**\n * Inject options into manifest file.\n *\n * @param {Object} manifestData - manifest content where preferences should be injected\n * @param {Object} pluginPreferences - plugin preferences from config.xml; already parsed\n * @return {Object} updated manifest data with corresponding intent-filters\n */\n function injectOptions(manifestData, pluginPreferences) {\n var changedManifest = manifestData,\n targetSdk = changedManifest['manifest']['uses-sdk'][0]['$']['android:targetSdkVersion'],\n activitiesList = changedManifest['manifest']['application'][0]['activity'],\n launchActivityIndex = getMainLaunchActivityIndex(activitiesList),\n ulIntentFilters = [],\n launchActivity;\n\n if (launchActivityIndex < 0) {\n console.warn('Could not find launch activity in the AndroidManifest file. Can\\'t inject Universal Links preferences.');\n return;\n }\n\n // get launch activity\n launchActivity = activitiesList[launchActivityIndex];\n\n // generate intent-filters\n pluginPreferences.hosts.forEach(function(host) {\n ulIntentFilters.push(createIntentFilter(host.name, host.scheme, pluginPreferences.androidPrefix, parseInt(targetSdk) >= 23));\n });\n\n // add Universal Links intent-filters to the launch activity\n launchActivity['intent-filter'] = launchActivity['intent-filter'].concat(ulIntentFilters);\n\n return changedManifest;\n }\n\n /**\n * Find index of the applications launcher activity.\n *\n * @param {Array} activities - list of all activities in the app\n * @return {Integer} index of the launch activity; -1 - if none was found\n */\n function getMainLaunchActivityIndex(activities) {\n var launchActivityIndex = -1;\n activities.some(function(activity, index) {\n if (isLaunchActivity(activity)) {\n launchActivityIndex = index;\n return true;\n }\n\n return false;\n });\n\n return launchActivityIndex;\n }\n\n /**\n * Check if the given actvity is a launch activity.\n *\n * @param {Object} activity - activity to check\n * @return {Boolean} true - if this is a launch activity; otherwise - false\n */\n function isLaunchActivity(activity) {\n var intentFilters = activity['intent-filter'],\n isLauncher = false;\n\n if (intentFilters == null || intentFilters.length == 0) {\n return false;\n }\n\n isLauncher = intentFilters.some(function(intentFilter) {\n var action = intentFilter['action'],\n category = intentFilter['category'];\n\n if (action == null || action.length != 1 || category == null || category.length != 1) {\n return false;\n }\n\n var isMainAction = (action[0]['$']['android:name'] === 'android.intent.action.MAIN'),\n isLauncherCategory = (category[0]['$']['android:name'] === 'android.intent.category.LAUNCHER');\n\n return isMainAction && isLauncherCategory;\n });\n\n return isLauncher;\n }\n\n /**\n * Create JSON object that represent intent-filter for universal link.\n *\n * @param {String} host - host name\n * @param {String} scheme - host scheme\n * @param {String} pathName - host path\n * @return {Object} intent-filter as a JSON object\n */\n function createIntentFilter(host, scheme, pathPrefix, androidM) {\n var intentFilter = {\n '$': {\n 'android:autoVerify': 'true'\n },\n 'action': [ {\n '$': {\n 'android:name': 'android.intent.action.VIEW'\n }\n } ],\n 'category': [ {\n '$': {\n 'android:name': 'android.intent.category.DEFAULT'\n }\n }, {\n '$': {\n 'android:name': 'android.intent.category.BROWSABLE'\n }\n } ],\n 'data': [ {\n '$': {\n 'android:host': host,\n 'android:scheme': scheme,\n 'android:pathPrefix': pathPrefix\n }\n } ]\n };\n\n if (!pathPrefix) {\n delete intentFilter['data'][0]['$']['android:pathPrefix'];\n }\n\n if (!androidM) {\n delete intentFilter['$']['android:autoVerify'];\n }\n\n return intentFilter;\n }\n\n // endregion\n\n})();\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/hooks/lib/configXmlHelper.js b/hooks/lib/configXmlHelper.js new file mode 100755 index 00000000..45475743 --- /dev/null +++ b/hooks/lib/configXmlHelper.js @@ -0,0 +1,122 @@ +'use strict'; + +/* +Helper class to read data from config.xml file. +*/ +(function () { + var path = require('path'), + xmlHelper = require('./xmlHelper.js'), + ANDROID = 'android', + IOS = 'ios', + CONFIG_FILE_NAME = 'config.xml', + context, + projectRoot; + + module.exports = ConfigXmlHelper; + + // region public API + + /** + * Constructor. + * + * @param {Object} cordovaContext - cordova context object + */ + function ConfigXmlHelper(cordovaContext) { + context = cordovaContext; + projectRoot = context.opts.projectRoot; + } + + /** + * Read config.xml data as JSON object. + * + * @return {Object} JSON object with data from config.xml + */ + ConfigXmlHelper.prototype.read = function () { + var filePath = getConfigXmlFilePath(); + + return xmlHelper.readXmlAsJson(filePath); + }; + + /** + * Get package name for the application. Depends on the platform. + * + * @param {String} platform - 'ios' or 'android'; for what platform we need a package name + * @return {String} package/bundle name + */ + ConfigXmlHelper.prototype.getPackageName = function (platform) { + var configFilePath = getConfigXmlFilePath(), + config = getCordovaConfigParser(configFilePath), + packageName; + + switch (platform) { + case ANDROID: + { + packageName = config.android_packageName(); + break; + } + case IOS: + { + packageName = config.ios_CFBundleIdentifier(); + break; + } + } + if (packageName === undefined || packageName.length == 0) { + packageName = config.packageName(); + } + + return packageName; + }; + + /** + * Get name of the current project. + * + * @return {String} name of the project + */ + ConfigXmlHelper.prototype.getProjectName = function () { + return getProjectName(); + }; + + // endregion + + // region Private API + + /** + * Get config parser from cordova library. + * + * @param {String} configFilePath absolute path to the config.xml file + * @return {Object} + */ + function getCordovaConfigParser(configFilePath) { + var ConfigParser; + + // If we are running Cordova 5.4 or abova - use parser from cordova-common. + // Otherwise - from cordova-lib. + try { + ConfigParser = context.requireCordovaModule('cordova-common/src/ConfigParser/ConfigParser'); + } catch (e) { + ConfigParser = context.requireCordovaModule('cordova-lib/src/configparser/ConfigParser'); + } + + return new ConfigParser(configFilePath); + } + + /** + * Get absolute path to the config.xml. + */ + function getConfigXmlFilePath() { + return path.join(projectRoot, CONFIG_FILE_NAME); + } + + /** + * Get project name from config.xml + */ + function getProjectName() { + var configFilePath = getConfigXmlFilePath(), + config = getCordovaConfigParser(configFilePath); + + return config.name(); + } + + // endregion +})(); +//# sourceMappingURL=configXmlHelper.js.map diff --git a/hooks/lib/configXmlHelper.js.map b/hooks/lib/configXmlHelper.js.map new file mode 100644 index 00000000..90256922 --- /dev/null +++ b/hooks/lib/configXmlHelper.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["lib/configXmlHelper.js"],"names":[],"mappings":";;AAAA;;;AAGA,CAAC,YAAW;AACV,MAAI,OAAO,QAAQ,MAAR,CAAX;AAAA,MACE,YAAY,QAAQ,gBAAR,CADd;AAAA,MAEE,UAAU,SAFZ;AAAA,MAGE,MAAM,KAHR;AAAA,MAIE,mBAAmB,YAJrB;AAAA,MAKE,OALF;AAAA,MAME,WANF;;AAQA,SAAO,OAAP,GAAiB,eAAjB;;AAEA;;AAEA;;;;;AAKA,WAAS,eAAT,CAAyB,cAAzB,EAAyC;AACvC,cAAU,cAAV;AACA,kBAAc,QAAQ,IAAR,CAAa,WAA3B;AACD;;AAED;;;;;AAKA,kBAAgB,SAAhB,CAA0B,IAA1B,GAAiC,YAAW;AAC1C,QAAI,WAAW,sBAAf;;AAEA,WAAO,UAAU,aAAV,CAAwB,QAAxB,CAAP;AACD,GAJD;;AAMA;;;;;;AAMA,kBAAgB,SAAhB,CAA0B,cAA1B,GAA2C,UAAS,QAAT,EAAmB;AAC5D,QAAI,iBAAiB,sBAArB;AAAA,QACE,SAAS,uBAAuB,cAAvB,CADX;AAAA,QAEE,WAFF;;AAIA,YAAQ,QAAR;AACE,WAAK,OAAL;AAAc;AACV,wBAAc,OAAO,mBAAP,EAAd;AACA;AACD;AACH,WAAK,GAAL;AAAU;AACN,wBAAc,OAAO,sBAAP,EAAd;AACA;AACD;AARL;AAUA,QAAI,gBAAgB,SAAhB,IAA6B,YAAY,MAAZ,IAAsB,CAAvD,EAA0D;AACxD,oBAAc,OAAO,WAAP,EAAd;AACD;;AAED,WAAO,WAAP;AACD,GApBD;;AAsBA;;;;;AAKA,kBAAgB,SAAhB,CAA0B,cAA1B,GAA2C,YAAW;AACpD,WAAO,gBAAP;AACD,GAFD;;AAIA;;AAEA;;AAEA;;;;;;AAMA,WAAS,sBAAT,CAAgC,cAAhC,EAAgD;AAC9C,QAAI,YAAJ;;AAEA;AACA;AACA,QAAI;AACF,qBAAe,QAAQ,oBAAR,CAA6B,8CAA7B,CAAf;AACD,KAFD,CAEE,OAAO,CAAP,EAAU;AACV,qBAAe,QAAQ,oBAAR,CAA6B,2CAA7B,CAAf;AACD;;AAED,WAAO,IAAI,YAAJ,CAAiB,cAAjB,CAAP;AACD;;AAED;;;AAGA,WAAS,oBAAT,GAAgC;AAC9B,WAAO,KAAK,IAAL,CAAU,WAAV,EAAuB,gBAAvB,CAAP;AACD;;AAED;;;AAGA,WAAS,cAAT,GAA0B;AACxB,QAAI,iBAAiB,sBAArB;AAAA,QACE,SAAS,uBAAuB,cAAvB,CADX;;AAGA,WAAO,OAAO,IAAP,EAAP;AACD;;AAED;AAED,CAlHD","file":"lib/configXmlHelper.js","sourcesContent":["/*\nHelper class to read data from config.xml file.\n*/\n(function() {\n var path = require('path'),\n xmlHelper = require('./xmlHelper.js'),\n ANDROID = 'android',\n IOS = 'ios',\n CONFIG_FILE_NAME = 'config.xml',\n context,\n projectRoot;\n\n module.exports = ConfigXmlHelper;\n\n // region public API\n\n /**\n * Constructor.\n *\n * @param {Object} cordovaContext - cordova context object\n */\n function ConfigXmlHelper(cordovaContext) {\n context = cordovaContext;\n projectRoot = context.opts.projectRoot;\n }\n\n /**\n * Read config.xml data as JSON object.\n *\n * @return {Object} JSON object with data from config.xml\n */\n ConfigXmlHelper.prototype.read = function() {\n var filePath = getConfigXmlFilePath();\n\n return xmlHelper.readXmlAsJson(filePath);\n }\n\n /**\n * Get package name for the application. Depends on the platform.\n *\n * @param {String} platform - 'ios' or 'android'; for what platform we need a package name\n * @return {String} package/bundle name\n */\n ConfigXmlHelper.prototype.getPackageName = function(platform) {\n var configFilePath = getConfigXmlFilePath(),\n config = getCordovaConfigParser(configFilePath),\n packageName;\n\n switch (platform) {\n case ANDROID: {\n packageName = config.android_packageName();\n break;\n }\n case IOS: {\n packageName = config.ios_CFBundleIdentifier();\n break;\n }\n }\n if (packageName === undefined || packageName.length == 0) {\n packageName = config.packageName();\n }\n\n return packageName;\n }\n\n /**\n * Get name of the current project.\n *\n * @return {String} name of the project\n */\n ConfigXmlHelper.prototype.getProjectName = function() {\n return getProjectName();\n }\n\n // endregion\n\n // region Private API\n\n /**\n * Get config parser from cordova library.\n *\n * @param {String} configFilePath absolute path to the config.xml file\n * @return {Object}\n */\n function getCordovaConfigParser(configFilePath) {\n var ConfigParser;\n\n // If we are running Cordova 5.4 or abova - use parser from cordova-common.\n // Otherwise - from cordova-lib.\n try {\n ConfigParser = context.requireCordovaModule('cordova-common/src/ConfigParser/ConfigParser');\n } catch (e) {\n ConfigParser = context.requireCordovaModule('cordova-lib/src/configparser/ConfigParser')\n }\n\n return new ConfigParser(configFilePath);\n }\n\n /**\n * Get absolute path to the config.xml.\n */\n function getConfigXmlFilePath() {\n return path.join(projectRoot, CONFIG_FILE_NAME);\n }\n\n /**\n * Get project name from config.xml\n */\n function getProjectName() {\n var configFilePath = getConfigXmlFilePath(),\n config = getCordovaConfigParser(configFilePath);\n\n return config.name();\n }\n\n // endregion\n\n})();\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/hooks/lib/configXmlParser.js b/hooks/lib/configXmlParser.js new file mode 100755 index 00000000..9f51926d --- /dev/null +++ b/hooks/lib/configXmlParser.js @@ -0,0 +1,134 @@ +'use strict'; + +/* +Parser for config.xml file. Read plugin-specific preferences (from tag) as JSON object. +*/ +(function () { + + var path = require('path'), + fs = require('fs'), + xml2js = require('xml2js'), + ConfigXmlHelper = require('./configXmlHelper.js'), + DEFAULT_SCHEME = 'http'; + + module.exports = { + readPreferences: readPreferences + }; + + // region Public API + + /** + * Read plugin preferences from the config.xml file. + * + * @param {Object} cordovaContext - cordova context object + * @return {Array} list of host objects + */ + function readPreferences(cordovaContext) { + // read data from projects root config.xml file + var configXml = new ConfigXmlHelper(cordovaContext).read(); + if (configXml == null) { + console.warn('config.xml not found! Please, check that it exist\'s in your project\'s root directory.'); + return null; + } + + // look for data from the tag + var ulXmlPreferences = configXml.widget['branch-config']; + if (ulXmlPreferences == null || ulXmlPreferences.length == 0) { + console.warn(' tag is not set in the config.xml. Universal Links plugin is not going to work.'); + return null; + } + + var xmlPreferences = ulXmlPreferences[0]; + + // read hosts + var hosts = constructHostsList(xmlPreferences); + + // read ios team ID + var iosTeamId = getTeamIdPreference(xmlPreferences); + + // read Android prefix + var androidPrefix = getAndroidPrefixPreference(xmlPreferences); + + return { + 'hosts': hosts, + 'iosTeamId': iosTeamId, + 'androidPrefix': androidPrefix + }; + } + + // endregion + + // region Private API + + function getTeamIdPreference(xmlPreferences) { + if (xmlPreferences.hasOwnProperty('ios-team-id')) { + return xmlPreferences['ios-team-id'][0]['$']['value']; + } + + return null; + } + + function getAndroidPrefixPreference(xmlPreferences) { + if (xmlPreferences.hasOwnProperty('android-prefix')) { + return xmlPreferences['android-prefix'][0]['$']['value']; + } + + return null; + } + + /** + * Construct list of host objects, defined in xml file. + * + * @param {Object} xmlPreferences - plugin preferences from config.xml as JSON object + * @return {Array} array of JSON objects, where each entry defines host data from config.xml. + */ + function constructHostsList(xmlPreferences) { + var hostsList = []; + + // look for defined hosts + var xmlHostList = xmlPreferences['host']; + if (xmlHostList == null || xmlHostList.length == 0) { + return []; + } + + xmlHostList.forEach(function (xmlElement) { + var host = constructHostEntry(xmlElement); + if (host) { + hostsList.push(host); + } + }); + + return hostsList; + } + + /** + * Construct host object from xml data. + * + * @param {Object} xmlElement - xml data to process. + * @return {Object} host entry as JSON object + */ + function constructHostEntry(xmlElement) { + var host = { + scheme: DEFAULT_SCHEME, + name: '' + }, + hostProperties = xmlElement['$']; + + if (hostProperties == null || hostProperties.length == 0) { + return null; + } + + // read host name + host.name = hostProperties.name; + + // read scheme if defined + if (hostProperties['scheme'] != null) { + host.scheme = hostProperties.scheme; + } + + return host; + } + + // endregion +})(); +//# sourceMappingURL=configXmlParser.js.map diff --git a/hooks/lib/configXmlParser.js.map b/hooks/lib/configXmlParser.js.map new file mode 100644 index 00000000..ea1191ab --- /dev/null +++ b/hooks/lib/configXmlParser.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["lib/configXmlParser.js"],"names":[],"mappings":";;AAAA;;;AAGA,CAAC,YAAW;;AAEV,MAAI,OAAO,QAAQ,MAAR,CAAX;AAAA,MACE,KAAK,QAAQ,IAAR,CADP;AAAA,MAEE,SAAS,QAAQ,QAAR,CAFX;AAAA,MAGE,kBAAkB,QAAQ,sBAAR,CAHpB;AAAA,MAIE,iBAAiB,MAJnB;;AAMA,SAAO,OAAP,GAAiB;AACf,qBAAiB;AADF,GAAjB;;AAIA;;AAEA;;;;;;AAMA,WAAS,eAAT,CAAyB,cAAzB,EAAyC;AACvC;AACA,QAAI,YAAY,IAAI,eAAJ,CAAoB,cAApB,EAAoC,IAApC,EAAhB;AACA,QAAI,aAAa,IAAjB,EAAuB;AACrB,cAAQ,IAAR,CAAa,yFAAb;AACA,aAAO,IAAP;AACD;;AAED;AACA,QAAI,mBAAmB,UAAU,MAAV,CAAiB,eAAjB,CAAvB;AACA,QAAI,oBAAoB,IAApB,IAA4B,iBAAiB,MAAjB,IAA2B,CAA3D,EAA8D;AAC5D,cAAQ,IAAR,CAAa,gGAAb;AACA,aAAO,IAAP;AACD;;AAED,QAAI,iBAAiB,iBAAiB,CAAjB,CAArB;;AAEA;AACA,QAAI,QAAQ,mBAAmB,cAAnB,CAAZ;;AAEA;AACA,QAAI,YAAY,oBAAoB,cAApB,CAAhB;;AAEA;AACA,QAAI,gBAAgB,2BAA2B,cAA3B,CAApB;;AAEA,WAAO;AACL,eAAS,KADJ;AAEL,mBAAa,SAFR;AAGL,uBAAiB;AAHZ,KAAP;AAKD;;AAED;;AAEA;;AAEA,WAAS,mBAAT,CAA6B,cAA7B,EAA6C;AAC3C,QAAI,eAAe,cAAf,CAA8B,aAA9B,CAAJ,EAAkD;AAChD,aAAO,eAAe,aAAf,EAA8B,CAA9B,EAAiC,GAAjC,EAAsC,OAAtC,CAAP;AACD;;AAED,WAAO,IAAP;AACD;;AAED,WAAS,0BAAT,CAAoC,cAApC,EAAoD;AAClD,QAAI,eAAe,cAAf,CAA8B,gBAA9B,CAAJ,EAAqD;AACnD,aAAO,eAAe,gBAAf,EAAiC,CAAjC,EAAoC,GAApC,EAAyC,OAAzC,CAAP;AACD;;AAED,WAAO,IAAP;AACD;;AAED;;;;;;AAMA,WAAS,kBAAT,CAA4B,cAA5B,EAA4C;AAC1C,QAAI,YAAY,EAAhB;;AAEA;AACA,QAAI,cAAc,eAAe,MAAf,CAAlB;AACA,QAAI,eAAe,IAAf,IAAuB,YAAY,MAAZ,IAAsB,CAAjD,EAAoD;AAClD,aAAO,EAAP;AACD;;AAED,gBAAY,OAAZ,CAAoB,UAAS,UAAT,EAAqB;AACvC,UAAI,OAAO,mBAAmB,UAAnB,CAAX;AACA,UAAI,IAAJ,EAAU;AACR,kBAAU,IAAV,CAAe,IAAf;AACD;AACF,KALD;;AAOA,WAAO,SAAP;AACD;;AAED;;;;;;AAMA,WAAS,kBAAT,CAA4B,UAA5B,EAAwC;AACtC,QAAI,OAAO;AACP,cAAQ,cADD;AAEP,YAAM;AAFC,KAAX;AAAA,QAIE,iBAAiB,WAAW,GAAX,CAJnB;;AAMA,QAAI,kBAAkB,IAAlB,IAA0B,eAAe,MAAf,IAAyB,CAAvD,EAA0D;AACxD,aAAO,IAAP;AACD;;AAED;AACA,SAAK,IAAL,GAAY,eAAe,IAA3B;;AAEA;AACA,QAAI,eAAe,QAAf,KAA4B,IAAhC,EAAsC;AACpC,WAAK,MAAL,GAAc,eAAe,MAA7B;AACD;;AAED,WAAO,IAAP;AACD;;AAED;AAED,CAhID","file":"lib/configXmlParser.js","sourcesContent":["/*\nParser for config.xml file. Read plugin-specific preferences (from tag) as JSON object.\n*/\n(function() {\n\n var path = require('path'),\n fs = require('fs'),\n xml2js = require('xml2js'),\n ConfigXmlHelper = require('./configXmlHelper.js'),\n DEFAULT_SCHEME = 'http';\n\n module.exports = {\n readPreferences: readPreferences\n };\n\n // region Public API\n\n /**\n * Read plugin preferences from the config.xml file.\n *\n * @param {Object} cordovaContext - cordova context object\n * @return {Array} list of host objects\n */\n function readPreferences(cordovaContext) {\n // read data from projects root config.xml file\n var configXml = new ConfigXmlHelper(cordovaContext).read();\n if (configXml == null) {\n console.warn('config.xml not found! Please, check that it exist\\'s in your project\\'s root directory.');\n return null;\n }\n\n // look for data from the tag\n var ulXmlPreferences = configXml.widget['branch-config'];\n if (ulXmlPreferences == null || ulXmlPreferences.length == 0) {\n console.warn(' tag is not set in the config.xml. Universal Links plugin is not going to work.');\n return null;\n }\n\n var xmlPreferences = ulXmlPreferences[0];\n\n // read hosts\n var hosts = constructHostsList(xmlPreferences);\n\n // read ios team ID\n var iosTeamId = getTeamIdPreference(xmlPreferences);\n\n // read Android prefix\n var androidPrefix = getAndroidPrefixPreference(xmlPreferences);\n\n return {\n 'hosts': hosts,\n 'iosTeamId': iosTeamId,\n 'androidPrefix': androidPrefix\n };\n }\n\n // endregion\n\n // region Private API\n\n function getTeamIdPreference(xmlPreferences) {\n if (xmlPreferences.hasOwnProperty('ios-team-id')) {\n return xmlPreferences['ios-team-id'][0]['$']['value'];\n }\n\n return null;\n }\n\n function getAndroidPrefixPreference(xmlPreferences) {\n if (xmlPreferences.hasOwnProperty('android-prefix')) {\n return xmlPreferences['android-prefix'][0]['$']['value'];\n }\n\n return null;\n }\n\n /**\n * Construct list of host objects, defined in xml file.\n *\n * @param {Object} xmlPreferences - plugin preferences from config.xml as JSON object\n * @return {Array} array of JSON objects, where each entry defines host data from config.xml.\n */\n function constructHostsList(xmlPreferences) {\n var hostsList = [];\n\n // look for defined hosts\n var xmlHostList = xmlPreferences['host'];\n if (xmlHostList == null || xmlHostList.length == 0) {\n return [];\n }\n\n xmlHostList.forEach(function(xmlElement) {\n var host = constructHostEntry(xmlElement);\n if (host) {\n hostsList.push(host);\n }\n });\n\n return hostsList;\n }\n\n /**\n * Construct host object from xml data.\n *\n * @param {Object} xmlElement - xml data to process.\n * @return {Object} host entry as JSON object\n */\n function constructHostEntry(xmlElement) {\n var host = {\n scheme: DEFAULT_SCHEME,\n name: ''\n },\n hostProperties = xmlElement['$'];\n\n if (hostProperties == null || hostProperties.length == 0) {\n return null;\n }\n\n // read host name\n host.name = hostProperties.name;\n\n // read scheme if defined\n if (hostProperties['scheme'] != null) {\n host.scheme = hostProperties.scheme;\n }\n\n return host;\n }\n\n // endregion\n\n})();\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/hooks/lib/ios/projectEntitlements.js b/hooks/lib/ios/projectEntitlements.js new file mode 100755 index 00000000..be576844 --- /dev/null +++ b/hooks/lib/ios/projectEntitlements.js @@ -0,0 +1,178 @@ +'use strict'; + +/* +Script creates entitlements file with the list of hosts, specified in config.xml. +File name is: ProjectName.entitlements +Location: ProjectName/ + +Script only generates content. File it self is included in the xcode project in another hook: xcodePreferences.js. +*/ +(function () { + + var path = require('path'), + fs = require('fs'), + plist = require('plist'), + mkpath = require('mkpath'), + ConfigXmlHelper = require('../configXmlHelper.js'), + ASSOCIATED_DOMAINS = 'com.apple.developer.associated-domains', + context, + projectRoot, + projectName, + entitlementsFilePath; + + module.exports = { + generateAssociatedDomainsEntitlements: generateEntitlements + }; + + // region Public API + + /** + * Generate entitlements file content. + * + * @param {Object} cordovaContext - cordova context object + * @param {Object} pluginPreferences - plugin preferences from config.xml; already parsed + */ + function generateEntitlements(cordovaContext, pluginPreferences) { + context = cordovaContext; + + var currentEntitlements = getEntitlementsFileContent(), + newEntitlements = injectPreferences(currentEntitlements, pluginPreferences); + + saveContentToEntitlementsFile(newEntitlements); + } + + // endregion + + // region Work with entitlements file + + /** + * Save data to entitlements file. + * + * @param {Object} content - data to save; JSON object that will be transformed into xml + */ + function saveContentToEntitlementsFile(content) { + var plistContent = plist.build(content), + filePath = pathToEntitlementsFile(); + + // ensure that file exists + mkpath.sync(path.dirname(filePath)); + + // save it's content + fs.writeFileSync(filePath, plistContent, 'utf8'); + } + + /** + * Read data from existing entitlements file. If none exist - default value is returned + * + * @return {String} entitlements file content + */ + function getEntitlementsFileContent() { + var pathToFile = pathToEntitlementsFile(), + content; + + try { + content = fs.readFileSync(pathToFile, 'utf8'); + } catch (err) { + return defaultEntitlementsFile(); + } + + return plist.parse(content); + } + + /** + * Get content for an empty entitlements file. + * + * @return {String} default entitlements file content + */ + function defaultEntitlementsFile() { + return {}; + } + + /** + * Inject list of hosts into entitlements file. + * + * @param {Object} currentEntitlements - entitlements where to inject preferences + * @param {Object} pluginPreferences - list of hosts from config.xml + * @return {Object} new entitlements content + */ + function injectPreferences(currentEntitlements, pluginPreferences) { + var newEntitlements = currentEntitlements, + content = generateAssociatedDomainsContent(pluginPreferences); + + newEntitlements[ASSOCIATED_DOMAINS] = content; + + return newEntitlements; + } + + /** + * Generate content for associated-domains dictionary in the entitlements file. + * + * @param {Object} pluginPreferences - list of hosts from conig.xml + * @return {Object} associated-domains dictionary content + */ + function generateAssociatedDomainsContent(pluginPreferences) { + var domainsList = [], + link; + + // generate list of host links + pluginPreferences.hosts.forEach(function (host) { + link = domainsListEntryForHost(host); + domainsList.push(link); + }); + + return domainsList; + } + + /** + * Generate domain record for the given host. + * + * @param {Object} host - host entry + * @return {String} record + */ + function domainsListEntryForHost(host) { + return 'applinks:' + host.name; + } + + // endregion + + // region Path helper methods + + /** + * Path to entitlements file. + * + * @return {String} absolute path to entitlements file + */ + function pathToEntitlementsFile() { + if (entitlementsFilePath === undefined) { + entitlementsFilePath = path.join(getProjectRoot(), 'platforms', 'ios', getProjectName(), 'Resources', getProjectName() + '.entitlements'); + } + + return entitlementsFilePath; + } + + /** + * Projects root folder path. + * + * @return {String} absolute path to the projects root + */ + function getProjectRoot() { + return context.opts.projectRoot; + } + + /** + * Name of the project from config.xml + * + * @return {String} project name + */ + function getProjectName() { + if (projectName === undefined) { + var configXmlHelper = new ConfigXmlHelper(context); + projectName = configXmlHelper.getProjectName(); + } + + return projectName; + } + + // endregion +})(); +//# sourceMappingURL=projectEntitlements.js.map diff --git a/hooks/lib/ios/projectEntitlements.js.map b/hooks/lib/ios/projectEntitlements.js.map new file mode 100644 index 00000000..a8207b6e --- /dev/null +++ b/hooks/lib/ios/projectEntitlements.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["lib/ios/projectEntitlements.js"],"names":[],"mappings":";;AAAA;;;;;;;AAOA,CAAC,YAAW;;AAEV,MAAI,OAAO,QAAQ,MAAR,CAAX;AAAA,MACE,KAAK,QAAQ,IAAR,CADP;AAAA,MAEE,QAAQ,QAAQ,OAAR,CAFV;AAAA,MAGE,SAAS,QAAQ,QAAR,CAHX;AAAA,MAIE,kBAAkB,QAAQ,uBAAR,CAJpB;AAAA,MAKE,qBAAqB,wCALvB;AAAA,MAME,OANF;AAAA,MAOE,WAPF;AAAA,MAQE,WARF;AAAA,MASE,oBATF;;AAWA,SAAO,OAAP,GAAiB;AACf,2CAAuC;AADxB,GAAjB;;AAIA;;AAEA;;;;;;AAMA,WAAS,oBAAT,CAA8B,cAA9B,EAA8C,iBAA9C,EAAiE;AAC/D,cAAU,cAAV;;AAEA,QAAI,sBAAsB,4BAA1B;AAAA,QACE,kBAAkB,kBAAkB,mBAAlB,EAAuC,iBAAvC,CADpB;;AAGA,kCAA8B,eAA9B;AACD;;AAED;;AAEA;;AAEA;;;;;AAKA,WAAS,6BAAT,CAAuC,OAAvC,EAAgD;AAC9C,QAAI,eAAe,MAAM,KAAN,CAAY,OAAZ,CAAnB;AAAA,QACE,WAAW,wBADb;;AAGA;AACA,WAAO,IAAP,CAAY,KAAK,OAAL,CAAa,QAAb,CAAZ;;AAEA;AACA,OAAG,aAAH,CAAiB,QAAjB,EAA2B,YAA3B,EAAyC,MAAzC;AACD;;AAED;;;;;AAKA,WAAS,0BAAT,GAAsC;AACpC,QAAI,aAAa,wBAAjB;AAAA,QACE,OADF;;AAGA,QAAI;AACF,gBAAU,GAAG,YAAH,CAAgB,UAAhB,EAA4B,MAA5B,CAAV;AACD,KAFD,CAEE,OAAO,GAAP,EAAY;AACZ,aAAO,yBAAP;AACD;;AAED,WAAO,MAAM,KAAN,CAAY,OAAZ,CAAP;AACD;;AAED;;;;;AAKA,WAAS,uBAAT,GAAmC;AACjC,WAAO,EAAP;AACD;;AAED;;;;;;;AAOA,WAAS,iBAAT,CAA2B,mBAA3B,EAAgD,iBAAhD,EAAmE;AACjE,QAAI,kBAAkB,mBAAtB;AAAA,QACE,UAAU,iCAAiC,iBAAjC,CADZ;;AAGA,oBAAgB,kBAAhB,IAAsC,OAAtC;;AAEA,WAAO,eAAP;AACD;;AAED;;;;;;AAMA,WAAS,gCAAT,CAA0C,iBAA1C,EAA6D;AAC3D,QAAI,cAAc,EAAlB;AAAA,QACE,IADF;;AAGA;AACA,sBAAkB,KAAlB,CAAwB,OAAxB,CAAgC,UAAS,IAAT,EAAe;AAC7C,aAAO,wBAAwB,IAAxB,CAAP;AACA,kBAAY,IAAZ,CAAiB,IAAjB;AACD,KAHD;;AAKA,WAAO,WAAP;AACD;;AAED;;;;;;AAMA,WAAS,uBAAT,CAAiC,IAAjC,EAAuC;AACrC,WAAO,cAAc,KAAK,IAA1B;AACD;;AAED;;AAEA;;AAEA;;;;;AAKA,WAAS,sBAAT,GAAkC;AAChC,QAAI,yBAAyB,SAA7B,EAAwC;AACtC,6BAAuB,KAAK,IAAL,CAAU,gBAAV,EAA4B,WAA5B,EAAyC,KAAzC,EAAgD,gBAAhD,EAAkE,WAAlE,EAA+E,mBAAmB,eAAlG,CAAvB;AACD;;AAED,WAAO,oBAAP;AACD;;AAED;;;;;AAKA,WAAS,cAAT,GAA0B;AACxB,WAAO,QAAQ,IAAR,CAAa,WAApB;AACD;;AAED;;;;;AAKA,WAAS,cAAT,GAA0B;AACxB,QAAI,gBAAgB,SAApB,EAA+B;AAC7B,UAAI,kBAAkB,IAAI,eAAJ,CAAoB,OAApB,CAAtB;AACA,oBAAc,gBAAgB,cAAhB,EAAd;AACD;;AAED,WAAO,WAAP;AACD;;AAED;AAED,CAxKD","file":"lib/ios/projectEntitlements.js","sourcesContent":["/*\nScript creates entitlements file with the list of hosts, specified in config.xml.\nFile name is: ProjectName.entitlements\nLocation: ProjectName/\n\nScript only generates content. File it self is included in the xcode project in another hook: xcodePreferences.js.\n*/\n(function() {\n\n var path = require('path'),\n fs = require('fs'),\n plist = require('plist'),\n mkpath = require('mkpath'),\n ConfigXmlHelper = require('../configXmlHelper.js'),\n ASSOCIATED_DOMAINS = 'com.apple.developer.associated-domains',\n context,\n projectRoot,\n projectName,\n entitlementsFilePath;\n\n module.exports = {\n generateAssociatedDomainsEntitlements: generateEntitlements\n };\n\n // region Public API\n\n /**\n * Generate entitlements file content.\n *\n * @param {Object} cordovaContext - cordova context object\n * @param {Object} pluginPreferences - plugin preferences from config.xml; already parsed\n */\n function generateEntitlements(cordovaContext, pluginPreferences) {\n context = cordovaContext;\n\n var currentEntitlements = getEntitlementsFileContent(),\n newEntitlements = injectPreferences(currentEntitlements, pluginPreferences);\n\n saveContentToEntitlementsFile(newEntitlements);\n }\n\n // endregion\n\n // region Work with entitlements file\n\n /**\n * Save data to entitlements file.\n *\n * @param {Object} content - data to save; JSON object that will be transformed into xml\n */\n function saveContentToEntitlementsFile(content) {\n var plistContent = plist.build(content),\n filePath = pathToEntitlementsFile();\n\n // ensure that file exists\n mkpath.sync(path.dirname(filePath));\n\n // save it's content\n fs.writeFileSync(filePath, plistContent, 'utf8');\n }\n\n /**\n * Read data from existing entitlements file. If none exist - default value is returned\n *\n * @return {String} entitlements file content\n */\n function getEntitlementsFileContent() {\n var pathToFile = pathToEntitlementsFile(),\n content;\n\n try {\n content = fs.readFileSync(pathToFile, 'utf8');\n } catch (err) {\n return defaultEntitlementsFile();\n }\n\n return plist.parse(content);\n }\n\n /**\n * Get content for an empty entitlements file.\n *\n * @return {String} default entitlements file content\n */\n function defaultEntitlementsFile() {\n return {};\n }\n\n /**\n * Inject list of hosts into entitlements file.\n *\n * @param {Object} currentEntitlements - entitlements where to inject preferences\n * @param {Object} pluginPreferences - list of hosts from config.xml\n * @return {Object} new entitlements content\n */\n function injectPreferences(currentEntitlements, pluginPreferences) {\n var newEntitlements = currentEntitlements,\n content = generateAssociatedDomainsContent(pluginPreferences);\n\n newEntitlements[ASSOCIATED_DOMAINS] = content;\n\n return newEntitlements;\n }\n\n /**\n * Generate content for associated-domains dictionary in the entitlements file.\n *\n * @param {Object} pluginPreferences - list of hosts from conig.xml\n * @return {Object} associated-domains dictionary content\n */\n function generateAssociatedDomainsContent(pluginPreferences) {\n var domainsList = [],\n link;\n\n // generate list of host links\n pluginPreferences.hosts.forEach(function(host) {\n link = domainsListEntryForHost(host);\n domainsList.push(link);\n });\n\n return domainsList;\n }\n\n /**\n * Generate domain record for the given host.\n *\n * @param {Object} host - host entry\n * @return {String} record\n */\n function domainsListEntryForHost(host) {\n return 'applinks:' + host.name;\n }\n\n // endregion\n\n // region Path helper methods\n\n /**\n * Path to entitlements file.\n *\n * @return {String} absolute path to entitlements file\n */\n function pathToEntitlementsFile() {\n if (entitlementsFilePath === undefined) {\n entitlementsFilePath = path.join(getProjectRoot(), 'platforms', 'ios', getProjectName(), 'Resources', getProjectName() + '.entitlements');\n }\n\n return entitlementsFilePath;\n }\n\n /**\n * Projects root folder path.\n *\n * @return {String} absolute path to the projects root\n */\n function getProjectRoot() {\n return context.opts.projectRoot;\n }\n\n /**\n * Name of the project from config.xml\n *\n * @return {String} project name\n */\n function getProjectName() {\n if (projectName === undefined) {\n var configXmlHelper = new ConfigXmlHelper(context);\n projectName = configXmlHelper.getProjectName();\n }\n\n return projectName;\n }\n\n // endregion\n\n})();\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/hooks/lib/ios/xcodePreferences.js b/hooks/lib/ios/xcodePreferences.js new file mode 100755 index 00000000..71cddab0 --- /dev/null +++ b/hooks/lib/ios/xcodePreferences.js @@ -0,0 +1,227 @@ +'use strict'; + +var _keys = require('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/* +Script activates support for Universal Links in the application by setting proper preferences in the xcode project file. +Which is: +- deployment target set to iOS 9.0 +- .entitlements file added to project PBXGroup and PBXFileReferences section +- path to .entitlements file added to Code Sign Entitlements preference +*/ + +(function () { + + var path = require('path'), + compare = require('node-version-compare'), + ConfigXmlHelper = require('../configXmlHelper.js'), + + // pbxFile = require('xcode/lib/pbxFile'), + IOS_DEPLOYMENT_TARGET = '8.0', + COMMENT_KEY = /_comment$/, + context; + + module.exports = { + enableAssociativeDomainsCapability: enableAssociativeDomainsCapability + }; + + // region Public API + + /** + * Activate associated domains capability for the application. + * + * @param {Object} cordovaContext - cordova context object + */ + function enableAssociativeDomainsCapability(cordovaContext) { + context = cordovaContext; + + var projectFile = loadProjectFile(); + + // adjust preferences + activateAssociativeDomains(projectFile.xcode); + + // add entitlements file to pbxfilereference + addPbxReference(projectFile.xcode); + + // save changes + projectFile.write(); + } + + // endregion + + // region Alter project file preferences + + /** + * Activate associated domains support in the xcode project file: + * - set deployment target to ios 9; + * - add .entitlements file to Code Sign Entitlements preference. + * + * @param {Object} xcodeProject - xcode project preferences; all changes are made in that instance + */ + function activateAssociativeDomains(xcodeProject) { + var configurations = nonComments(xcodeProject.pbxXCBuildConfigurationSection()), + entitlementsFilePath = pathToEntitlementsFile(), + config, + buildSettings, + deploymentTargetIsUpdated; + + for (config in configurations) { + buildSettings = configurations[config].buildSettings; + buildSettings['CODE_SIGN_ENTITLEMENTS'] = '"' + entitlementsFilePath + '"'; + // if deployment target is less then the required one - increase it + if (buildSettings['IPHONEOS_DEPLOYMENT_TARGET']) { + var buildDeploymentTarget = buildSettings['IPHONEOS_DEPLOYMENT_TARGET'].toString(); + if (compare(buildDeploymentTarget, IOS_DEPLOYMENT_TARGET) == -1) { + buildSettings['IPHONEOS_DEPLOYMENT_TARGET'] = IOS_DEPLOYMENT_TARGET; + deploymentTargetIsUpdated = true; + } + } else { + buildSettings['IPHONEOS_DEPLOYMENT_TARGET'] = IOS_DEPLOYMENT_TARGET; + deploymentTargetIsUpdated = true; + } + } + + if (deploymentTargetIsUpdated) { + console.log('IOS project now has deployment target set as: ' + IOS_DEPLOYMENT_TARGET); + } + + console.log('IOS project Code Sign Entitlements now set to: ' + entitlementsFilePath); + } + + // endregion + + // region PBXReference methods + + /** + * Add .entitlemets file into the project. + * + * @param {Object} xcodeProject - xcode project preferences; all changes are made in that instance + */ + function addPbxReference(xcodeProject) { + var fileReferenceSection = nonComments(xcodeProject.pbxFileReferenceSection()), + entitlementsRelativeFilePath = pathToEntitlementsFile(); + + if (isPbxReferenceAlreadySet(fileReferenceSection, entitlementsRelativeFilePath)) { + console.log('Entitlements file is in reference section.'); + return; + } + + console.log('Entitlements file is not in references section, adding it'); + createPbxFileReference(xcodeProject, entitlementsRelativeFilePath); + } + + /** + * Check if .entitlemets file reference already set. + * + * @param {Object} fileReferenceSection - PBXFileReference section + * @param {String} entitlementsRelativeFilePath - relative path to entitlements file + * @return true - if reference is set; otherwise - false + */ + function isPbxReferenceAlreadySet(fileReferenceSection, entitlementsRelativeFilePath) { + var isAlreadyInReferencesSection = false, + uuid, + fileRefEntry; + + for (uuid in fileReferenceSection) { + fileRefEntry = fileReferenceSection[uuid]; + if (fileRefEntry.path && fileRefEntry.path.indexOf(entitlementsRelativeFilePath) > -1) { + isAlreadyInReferencesSection = true; + break; + } + } + + return isAlreadyInReferencesSection; + } + + /** + * Create reference to the entitlements file in the xcode project. + * + * @param {Object} xcodeProject - xcode project preferences; all changes are made in that instance + * @param {String} entitlementsRelativeFilePath - relative path to entitlemets file + */ + function createPbxFileReference(xcodeProject, entitlementsRelativeFilePath) { + // commented for now + // var rootGroup = nonComments(xcodeProject.pbxGroupByName('CustomTemplate')), + // entitlementsPbxFile = new pbxFile(entitlementsRelativeFilePath); + // + // entitlementsPbxFile.fileRef = xcodeProject.generateUuid(), + // entitlementsPbxFile.uuid = xcodeProject.generateUuid(); + // + // xcodeProject.addToPbxFileReferenceSection(entitlementsPbxFile); + // + // rootGroup.children.push({ + // 'value': entitlementsPbxFile.fileRef, + // 'comment': path.basename(entitlementsRelativeFilePath) + // }); + xcodeProject.addResourceFile(path.basename(entitlementsRelativeFilePath)); + } + + // region Xcode project file helpers + + /** + * Load iOS project file from platform specific folder. + * + * @return {Object} projectFile - project file information + */ + function loadProjectFile() { + var platform_ios, projectFile; + + try { + // try pre-5.0 cordova structure + platform_ios = context.requireCordovaModule('cordova-lib/src/plugman/platforms')['ios']; + projectFile = platform_ios.parseProjectFile(iosPlatformPath()); + } catch (e) { + // let's try cordova 5.0 structure + platform_ios = context.requireCordovaModule('cordova-lib/src/plugman/platforms/ios'); + projectFile = platform_ios.parseProjectFile(iosPlatformPath()); + } + + return projectFile; + } + + /** + * Remove comments from the file. + * + * @param {Object} obj - file object + * @return {Object} file object without comments + */ + function nonComments(obj) { + var keys = (0, _keys2.default)(obj), + newObj = {}; + + for (var i = 0, len = keys.length; i < len; i++) { + if (!COMMENT_KEY.test(keys[i])) { + newObj[keys[i]] = obj[keys[i]]; + } + } + + return newObj; + } + + // endregion + + // region Path helpers + + function iosPlatformPath() { + return path.join(projectRoot(), 'platforms', 'ios'); + } + + function projectRoot() { + return context.opts.projectRoot; + } + + function pathToEntitlementsFile() { + var configXmlHelper = new ConfigXmlHelper(context), + projectName = configXmlHelper.getProjectName(), + fileName = projectName + '.entitlements'; + + return path.join(projectName, 'Resources', fileName); + } + + // endregion +})(); +//# sourceMappingURL=xcodePreferences.js.map diff --git a/hooks/lib/ios/xcodePreferences.js.map b/hooks/lib/ios/xcodePreferences.js.map new file mode 100644 index 00000000..fb02e9c2 --- /dev/null +++ b/hooks/lib/ios/xcodePreferences.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["lib/ios/xcodePreferences.js"],"names":[],"mappings":"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","file":"lib/ios/xcodePreferences.js","sourcesContent":["/*\nScript activates support for Universal Links in the application by setting proper preferences in the xcode project file.\nWhich is:\n- deployment target set to iOS 9.0\n- .entitlements file added to project PBXGroup and PBXFileReferences section\n- path to .entitlements file added to Code Sign Entitlements preference\n*/\n\n(function() {\n\n var path = require('path'),\n compare = require('node-version-compare'),\n ConfigXmlHelper = require('../configXmlHelper.js'),\n // pbxFile = require('xcode/lib/pbxFile'),\n IOS_DEPLOYMENT_TARGET = '8.0',\n COMMENT_KEY = /_comment$/,\n context;\n\n module.exports = {\n enableAssociativeDomainsCapability: enableAssociativeDomainsCapability\n }\n\n // region Public API\n\n /**\n * Activate associated domains capability for the application.\n *\n * @param {Object} cordovaContext - cordova context object\n */\n function enableAssociativeDomainsCapability(cordovaContext) {\n context = cordovaContext;\n\n var projectFile = loadProjectFile();\n\n // adjust preferences\n activateAssociativeDomains(projectFile.xcode);\n\n // add entitlements file to pbxfilereference\n addPbxReference(projectFile.xcode);\n\n // save changes\n projectFile.write();\n }\n\n // endregion\n\n // region Alter project file preferences\n\n /**\n * Activate associated domains support in the xcode project file:\n * - set deployment target to ios 9;\n * - add .entitlements file to Code Sign Entitlements preference.\n *\n * @param {Object} xcodeProject - xcode project preferences; all changes are made in that instance\n */\n function activateAssociativeDomains(xcodeProject) {\n var configurations = nonComments(xcodeProject.pbxXCBuildConfigurationSection()),\n entitlementsFilePath = pathToEntitlementsFile(),\n config,\n buildSettings,\n deploymentTargetIsUpdated;\n\n for (config in configurations) {\n buildSettings = configurations[config].buildSettings;\n buildSettings['CODE_SIGN_ENTITLEMENTS'] = '\"' + entitlementsFilePath + '\"';\n // if deployment target is less then the required one - increase it\n if (buildSettings['IPHONEOS_DEPLOYMENT_TARGET']) {\n var buildDeploymentTarget = buildSettings['IPHONEOS_DEPLOYMENT_TARGET'].toString();\n if (compare(buildDeploymentTarget, IOS_DEPLOYMENT_TARGET) == -1) {\n buildSettings['IPHONEOS_DEPLOYMENT_TARGET'] = IOS_DEPLOYMENT_TARGET;\n deploymentTargetIsUpdated = true;\n }\n }\n else {\n buildSettings['IPHONEOS_DEPLOYMENT_TARGET'] = IOS_DEPLOYMENT_TARGET;\n deploymentTargetIsUpdated = true;\n }\n }\n\n if (deploymentTargetIsUpdated) {\n console.log('IOS project now has deployment target set as: ' + IOS_DEPLOYMENT_TARGET);\n }\n\n console.log('IOS project Code Sign Entitlements now set to: ' + entitlementsFilePath);\n }\n\n // endregion\n\n // region PBXReference methods\n\n /**\n * Add .entitlemets file into the project.\n *\n * @param {Object} xcodeProject - xcode project preferences; all changes are made in that instance\n */\n function addPbxReference(xcodeProject) {\n var fileReferenceSection = nonComments(xcodeProject.pbxFileReferenceSection()),\n entitlementsRelativeFilePath = pathToEntitlementsFile();\n\n if (isPbxReferenceAlreadySet(fileReferenceSection, entitlementsRelativeFilePath)) {\n console.log('Entitlements file is in reference section.');\n return;\n }\n\n console.log('Entitlements file is not in references section, adding it');\n createPbxFileReference(xcodeProject, entitlementsRelativeFilePath);\n }\n\n /**\n * Check if .entitlemets file reference already set.\n *\n * @param {Object} fileReferenceSection - PBXFileReference section\n * @param {String} entitlementsRelativeFilePath - relative path to entitlements file\n * @return true - if reference is set; otherwise - false\n */\n function isPbxReferenceAlreadySet(fileReferenceSection, entitlementsRelativeFilePath) {\n var isAlreadyInReferencesSection = false,\n uuid,\n fileRefEntry;\n\n for (uuid in fileReferenceSection) {\n fileRefEntry = fileReferenceSection[uuid];\n if (fileRefEntry.path && fileRefEntry.path.indexOf(entitlementsRelativeFilePath) > -1) {\n isAlreadyInReferencesSection = true;\n break;\n }\n }\n\n return isAlreadyInReferencesSection;\n }\n\n /**\n * Create reference to the entitlements file in the xcode project.\n *\n * @param {Object} xcodeProject - xcode project preferences; all changes are made in that instance\n * @param {String} entitlementsRelativeFilePath - relative path to entitlemets file\n */\n function createPbxFileReference(xcodeProject, entitlementsRelativeFilePath) {\n // commented for now\n // var rootGroup = nonComments(xcodeProject.pbxGroupByName('CustomTemplate')),\n // entitlementsPbxFile = new pbxFile(entitlementsRelativeFilePath);\n //\n // entitlementsPbxFile.fileRef = xcodeProject.generateUuid(),\n // entitlementsPbxFile.uuid = xcodeProject.generateUuid();\n //\n // xcodeProject.addToPbxFileReferenceSection(entitlementsPbxFile);\n //\n // rootGroup.children.push({\n // 'value': entitlementsPbxFile.fileRef,\n // 'comment': path.basename(entitlementsRelativeFilePath)\n // });\n xcodeProject.addResourceFile(path.basename(entitlementsRelativeFilePath));\n }\n\n // region Xcode project file helpers\n\n /**\n * Load iOS project file from platform specific folder.\n *\n * @return {Object} projectFile - project file information\n */\n function loadProjectFile() {\n var platform_ios,\n projectFile;\n\n try {\n // try pre-5.0 cordova structure\n platform_ios = context.requireCordovaModule('cordova-lib/src/plugman/platforms')['ios'];\n projectFile = platform_ios.parseProjectFile(iosPlatformPath());\n } catch (e) {\n // let's try cordova 5.0 structure\n platform_ios = context.requireCordovaModule('cordova-lib/src/plugman/platforms/ios');\n projectFile = platform_ios.parseProjectFile(iosPlatformPath());\n }\n\n return projectFile;\n }\n\n /**\n * Remove comments from the file.\n *\n * @param {Object} obj - file object\n * @return {Object} file object without comments\n */\n function nonComments(obj) {\n var keys = Object.keys(obj),\n newObj = {};\n\n for (var i = 0, len = keys.length; i < len; i++) {\n if (!COMMENT_KEY.test(keys[i])) {\n newObj[keys[i]] = obj[keys[i]];\n }\n }\n\n return newObj;\n }\n\n // endregion\n\n // region Path helpers\n\n function iosPlatformPath() {\n return path.join(projectRoot(), 'platforms', 'ios');\n }\n\n function projectRoot() {\n return context.opts.projectRoot;\n }\n\n function pathToEntitlementsFile() {\n var configXmlHelper = new ConfigXmlHelper(context),\n projectName = configXmlHelper.getProjectName(),\n fileName = projectName + '.entitlements';\n\n return path.join(projectName, 'Resources', fileName);\n }\n\n // endregion\n\n})();\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/hooks/lib/xmlHelper.js b/hooks/lib/xmlHelper.js new file mode 100755 index 00000000..6840d5f2 --- /dev/null +++ b/hooks/lib/xmlHelper.js @@ -0,0 +1,60 @@ +'use strict'; + +/* +Small helper class to read/write from/to xml file. +*/ +(function () { + + var fs = require('fs'), + xml2js = require('xml2js'); + + module.exports = { + readXmlAsJson: readXmlAsJson, + writeJsonAsXml: writeJsonAsXml + }; + + /** + * Read data from the xml file as JSON object. + * + * @param {String} filePath - absolute path to xml file + * @return {Object} JSON object with the contents of the xml file + */ + function readXmlAsJson(filePath) { + var xmlData, xmlParser, parsedData; + + try { + xmlData = fs.readFileSync(filePath); + xmlParser = new xml2js.Parser(); + xmlParser.parseString(xmlData, function (err, data) { + if (data) { + parsedData = data; + } + }); + } catch (err) {} + + return parsedData; + } + + /** + * Write JSON object as xml into the specified file. + * + * @param {Object} jsData - JSON object to write + * @param {String} filePath - path to the xml file where data should be saved + * @return {boolean} true - if data saved to file; false - otherwise + */ + function writeJsonAsXml(jsData, filePath, options) { + var xmlBuilder = new xml2js.Builder(options), + changedXmlData = xmlBuilder.buildObject(jsData), + isSaved = true; + + try { + fs.writeFileSync(filePath, changedXmlData); + } catch (err) { + console.log(err); + isSaved = false; + } + + return isSaved; + } +})(); +//# sourceMappingURL=xmlHelper.js.map diff --git a/hooks/lib/xmlHelper.js.map b/hooks/lib/xmlHelper.js.map new file mode 100644 index 00000000..5404c120 --- /dev/null +++ b/hooks/lib/xmlHelper.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["lib/xmlHelper.js"],"names":[],"mappings":";;AAAA;;;AAGA,CAAC,YAAW;;AAEV,MAAI,KAAK,QAAQ,IAAR,CAAT;AAAA,MACE,SAAS,QAAQ,QAAR,CADX;;AAGA,SAAO,OAAP,GAAiB;AACf,mBAAe,aADA;AAEf,oBAAgB;AAFD,GAAjB;;AAKA;;;;;;AAMA,WAAS,aAAT,CAAuB,QAAvB,EAAiC;AAC/B,QAAI,OAAJ,EACE,SADF,EAEE,UAFF;;AAIA,QAAI;AACF,gBAAU,GAAG,YAAH,CAAgB,QAAhB,CAAV;AACA,kBAAY,IAAI,OAAO,MAAX,EAAZ;AACA,gBAAU,WAAV,CAAsB,OAAtB,EAA+B,UAAS,GAAT,EAAc,IAAd,EAAoB;AACjD,YAAI,IAAJ,EAAU;AACR,uBAAa,IAAb;AACD;AACF,OAJD;AAKD,KARD,CAQE,OAAO,GAAP,EAAY,CAAE;;AAEhB,WAAO,UAAP;AACD;;AAED;;;;;;;AAOA,WAAS,cAAT,CAAwB,MAAxB,EAAgC,QAAhC,EAA0C,OAA1C,EAAmD;AACjD,QAAI,aAAa,IAAI,OAAO,OAAX,CAAmB,OAAnB,CAAjB;AAAA,QACE,iBAAiB,WAAW,WAAX,CAAuB,MAAvB,CADnB;AAAA,QAEE,UAAU,IAFZ;;AAIA,QAAI;AACF,SAAG,aAAH,CAAiB,QAAjB,EAA2B,cAA3B;AACD,KAFD,CAEE,OAAO,GAAP,EAAY;AACZ,cAAQ,GAAR,CAAY,GAAZ;AACA,gBAAU,KAAV;AACD;;AAED,WAAO,OAAP;AACD;AAEF,CAxDD","file":"lib/xmlHelper.js","sourcesContent":["/*\nSmall helper class to read/write from/to xml file.\n*/\n(function() {\n\n var fs = require('fs'),\n xml2js = require('xml2js');\n\n module.exports = {\n readXmlAsJson: readXmlAsJson,\n writeJsonAsXml: writeJsonAsXml\n };\n\n /**\n * Read data from the xml file as JSON object.\n *\n * @param {String} filePath - absolute path to xml file\n * @return {Object} JSON object with the contents of the xml file\n */\n function readXmlAsJson(filePath) {\n var xmlData,\n xmlParser,\n parsedData;\n\n try {\n xmlData = fs.readFileSync(filePath);\n xmlParser = new xml2js.Parser();\n xmlParser.parseString(xmlData, function(err, data) {\n if (data) {\n parsedData = data;\n }\n });\n } catch (err) {}\n\n return parsedData;\n }\n\n /**\n * Write JSON object as xml into the specified file.\n *\n * @param {Object} jsData - JSON object to write\n * @param {String} filePath - path to the xml file where data should be saved\n * @return {boolean} true - if data saved to file; false - otherwise\n */\n function writeJsonAsXml(jsData, filePath, options) {\n var xmlBuilder = new xml2js.Builder(options),\n changedXmlData = xmlBuilder.buildObject(jsData),\n isSaved = true;\n\n try {\n fs.writeFileSync(filePath, changedXmlData);\n } catch (err) {\n console.log(err);\n isSaved = false;\n }\n\n return isSaved;\n }\n\n})();\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/plugin.xml b/plugin.xml index fc1ca696..92938d4a 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,8 +1,7 @@ - @@ -105,9 +104,92 @@ SOFTWARE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ios/BranchNPM.h b/src/ios/BranchNPM.h index 90fe1bcc..39325ca4 100644 --- a/src/ios/BranchNPM.h +++ b/src/ios/BranchNPM.h @@ -1 +1 @@ -//empty +#define BRANCH_NPM true diff --git a/testbed/www/js/index.js b/testbed/www/js/index.js new file mode 100644 index 00000000..201b8960 --- /dev/null +++ b/testbed/www/js/index.js @@ -0,0 +1,305 @@ +'use strict'; + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var app = { + // Application Constructor + initialize: function initialize() { + this.bindEvents(); + }, + // Bind Event Listeners + // + // Bind any events that are required on startup. Common events are: + // 'load', 'deviceready', 'offline', and 'online'. + bindEvents: function bindEvents() { + document.addEventListener('deviceready', this.onDeviceReady, false); + }, + // deviceready Event Handler + // + // The scope of 'this' is the event. In order to call the 'receivedEvent' + // function, we must explicitly call 'app.receivedEvent(...);' + onDeviceReady: function onDeviceReady() { + app.receivedEvent('app'); + }, + // Update DOM on a Received Event + receivedEvent: function receivedEvent(id) { + + if (navigator.userAgent.indexOf('iPhone') >= 0) { + document.getElementsByTagName("html")[0].className = 'ios'; + } else if (navigator.userAgent.indexOf('Android') >= 0) { + document.getElementsByTagName("html")[0].className = 'android'; + } + + InitSession(); + } +}; + +app.initialize(); + +function DeepLinkHandler(data) { + if (data) { + alert('Initialize: ' + (0, _stringify2.default)(data)); + } else { + alert('No data found'); + } +} + +function NonBranchLinkHandler(data) { + if (data) { + alert('Non-branch link found: ' + (0, _stringify2.default)(data)); + } +} + +function InitSession() { + console.log('Trigger InitSession()'); + + Branch.setMixpanelToken(''); + Branch.initSession().then(function (res) { + console.log(res); + alert('Response: ' + (0, _stringify2.default)(res)); + }).catch(function (err) { + console.error(err); + alert('Error: ' + (0, _stringify2.default)(err)); + }); +} + +function CustomAction() { + console.log('Trigger CustomAction()'); + + var action = document.getElementById('custom-action').value; + + Branch.userCompletedAction(action).then(function (res) { + console.log(res); + alert('Response: ' + (0, _stringify2.default)(res)); + }).catch(function (err) { + console.error(err); + alert('Error: ' + (0, _stringify2.default)(err)); + }); +} + +function GetLatestReferringParams() { + console.log('Trigger GetLatestReferringParams()'); + + Branch.getLatestReferringParams().then(function (res) { + console.log(res); + alert('Response: ' + (0, _stringify2.default)(res)); + }).catch(function (err) { + console.error(err); + alert('Error: ' + (0, _stringify2.default)(err)); + }); +} + +function GetFirstReferringParams() { + console.log('Trigger GetFirstReferringParams()'); + + Branch.getFirstReferringParams().then(function (res) { + alert('Response: ' + (0, _stringify2.default)(res)); + console.log(res); + }).catch(function (err) { + alert('Error: ' + (0, _stringify2.default)(err)); + console.error(err); + }); +} + +function SetIdentity() { + console.log('Trigger SetIdentity()'); + + var newIdentity = document.getElementById('identity').value; + + Branch.setIdentity(newIdentity).then(function (res) { + console.log(res); + alert('Response: ' + (0, _stringify2.default)(res)); + }).catch(function (err) { + console.error(err); + alert('Error: ' + (0, _stringify2.default)(err)); + }); +} + +function Logout() { + console.log('Trigger Logout()'); + + Branch.logout().then(function (res) { + console.log(res); + alert('Response: ' + (0, _stringify2.default)(res)); + }).catch(function (err) { + console.error(err); + alert('Error: ' + (0, _stringify2.default)(err)); + }); +} + +var branchUniversalObj = null; + +function CreateBranchUniversalObject() { + + console.log('Trigger CreateBranchUniversalObject()'); + + var properties = { + canonicalIdentifier: 'testbed', + title: 'testbed', + contentDescription: 'Testbed Application', + contentImageUrl: 'https://imgflip.com/s/meme/Derp.jpg', + contentIndexingMode: 'public', + contentMetadata: {} + }; + + Branch.createBranchUniversalObject(properties).then(function (res) { + console.log(res); + alert('Response: ' + (0, _stringify2.default)(res)); + branchUniversalObj = res; + }).catch(function (err) { + console.error(err); + alert('Error: ' + (0, _stringify2.default)(err)); + }); +} + +function RegisterView() { + console.log('Trigger RegisterView()'); + + branchUniversalObj.registerView().then(function (res) { + console.log(res); + alert('Response: ' + (0, _stringify2.default)(res)); + }).catch(function (err) { + console.error(err); + alert('Error: ' + (0, _stringify2.default)(err)); + });; +} + +function GenerateShortUrl() { + console.log('Trigger GenerateShortUrl()'); + + var properties = { + feature: 'test', + alias: document.getElementById('alias').value, + channel: 'test', + stage: 'test', + duration: 10000 + }; + var controlParams = { + $fallback_url: 'www.another.com', + $desktop_url: 'www.desktop.com', + $android_url: 'test', + $ios_url: 'ios', + $ipad_url: 'ipad', + $fire_url: 'fire', + $blackberry_url: 'blackberry', + $windows_phone_url: 'win-phone' + }; + + branchUniversalObj.generateShortUrl(properties, controlParams).then(function (res) { + console.log(res); + document.getElementById('generated-url').value = res.url; + }).catch(function (err) { + console.error(err); + alert('Error: ' + (0, _stringify2.default)(err)); + }); +} + +function ShowShareSheet() { + console.log('Trigger ShowShareSheet()'); + + var properties = { + feature: 'test', + alias: document.getElementById('alias').value, + channel: 'test', + stage: 'test', + duration: 10000 + }; + var controlParams = { + $fallback_url: 'www.another.com', + $desktop_url: 'www.desktop.com', + $android_url: 'test', + $ios_url: 'ios', + $ipad_url: 'ipad', + $fire_url: 'fire', + $blackberry_url: 'blackberry', + $windows_phone_url: 'win-phone' + }; + + console.log(branchUniversalObj); + + // Set listeners + branchUniversalObj.onShareSheetLaunched(function () { + console.log('Share sheet launched'); + }); + branchUniversalObj.onShareSheetDismissed(function () { + console.log('Share sheet dismissed'); + }); + branchUniversalObj.onLinkShareResponse(function (res) { + console.log('Share link response: ' + (0, _stringify2.default)(res)); + }); + branchUniversalObj.onChannelSelected(function (res) { + console.log('Channel selected: ' + (0, _stringify2.default)(res)); + }); + + branchUniversalObj.showShareSheet(properties, controlParams, 'Custom Text'); +} + +function ListOnSpotlight() { + console.log('Trigger ListOnSpotlight()'); + branchUniversalObj.listOnSpotlight().then(function (res) { + console.log(res); + alert('Response: ' + (0, _stringify2.default)(res)); + }).catch(function (err) { + console.error(err); + alert('Error: ' + (0, _stringify2.default)(err)); + }); +} + +function LoadRewards() { + console.log('Trigger LoadRewards()'); + Branch.loadRewards().then(function (res) { + console.log(res); + alert('Response: ' + (0, _stringify2.default)(res)); + }).catch(function (err) { + console.error(err); + alert('Error: ' + (0, _stringify2.default)(err)); + }); +} + +function RedeemRewards() { + console.log('Trigger RedeemRewards()'); + var reward = 1000; + + Branch.redeemRewards(reward).then(function (res) { + console.log(res); + alert('Response: ' + (0, _stringify2.default)(res)); + }).catch(function (err) { + console.error(err); + alert('Error: ' + (0, _stringify2.default)(err)); + }); +} + +function CreditHistory() { + console.log('Trigger CreditHistory()'); + Branch.creditHistory().then(function (res) { + console.log(res); + alert('Response: ' + (0, _stringify2.default)(res)); + }).catch(function (err) { + console.error(err); + alert('Error: ' + (0, _stringify2.default)(err)); + }); +} +//# sourceMappingURL=index.js.map diff --git a/testbed/www/js/index.js.map b/testbed/www/js/index.js.map new file mode 100644 index 00000000..09c4f441 --- /dev/null +++ b/testbed/www/js/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["index.js"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements. See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership. The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied. See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\n\nvar app = {\n // Application Constructor\n initialize: function() {\n this.bindEvents();\n },\n // Bind Event Listeners\n //\n // Bind any events that are required on startup. Common events are:\n // 'load', 'deviceready', 'offline', and 'online'.\n bindEvents: function() {\n document.addEventListener('deviceready', this.onDeviceReady, false);\n },\n // deviceready Event Handler\n //\n // The scope of 'this' is the event. In order to call the 'receivedEvent'\n // function, we must explicitly call 'app.receivedEvent(...);'\n onDeviceReady: function() {\n app.receivedEvent('app');\n },\n // Update DOM on a Received Event\n receivedEvent: function(id) {\n\n if (navigator.userAgent.indexOf('iPhone') >= 0) {\n document.getElementsByTagName(\"html\")[0].className = 'ios';\n }\n else if (navigator.userAgent.indexOf('Android') >= 0) {\n document.getElementsByTagName(\"html\")[0].className = 'android';\n }\n\n InitSession();\n\n }\n};\n\napp.initialize();\n\nfunction DeepLinkHandler(data) {\n if (data) {\n alert('Initialize: ' + JSON.stringify(data));\n }\n else {\n alert('No data found');\n }\n}\n\nfunction NonBranchLinkHandler(data) {\n if (data) {\n alert('Non-branch link found: ' + JSON.stringify(data));\n }\n}\n\nfunction InitSession() {\n console.log('Trigger InitSession()');\n\n Branch.setMixpanelToken('');\n Branch.initSession().then(function(res) {\n console.log(res);\n alert('Response: ' + JSON.stringify(res));\n }).catch(function(err) {\n console.error(err);\n alert('Error: ' + JSON.stringify(err));\n });\n}\n\nfunction CustomAction() {\n console.log('Trigger CustomAction()');\n\n var action = document.getElementById('custom-action').value;\n\n Branch.userCompletedAction(action).then(function(res) {\n console.log(res);\n alert('Response: ' + JSON.stringify(res));\n }).catch(function(err) {\n console.error(err);\n alert('Error: ' + JSON.stringify(err));\n });\n}\n\nfunction GetLatestReferringParams() {\n console.log('Trigger GetLatestReferringParams()');\n\n Branch.getLatestReferringParams().then(function(res) {\n console.log(res);\n alert('Response: ' + JSON.stringify(res));\n }).catch(function(err) {\n console.error(err);\n alert('Error: ' + JSON.stringify(err));\n });\n}\n\nfunction GetFirstReferringParams() {\n console.log('Trigger GetFirstReferringParams()');\n\n Branch.getFirstReferringParams().then(function(res) {\n alert('Response: ' + JSON.stringify(res));\n console.log(res);\n }).catch(function(err) {\n alert('Error: ' + JSON.stringify(err));\n console.error(err);\n });\n}\n\nfunction SetIdentity() {\n console.log('Trigger SetIdentity()');\n\n var newIdentity = document.getElementById('identity').value;\n\n Branch.setIdentity(newIdentity).then(function(res) {\n console.log(res);\n alert('Response: ' + JSON.stringify(res));\n }).catch(function(err) {\n console.error(err);\n alert('Error: ' + JSON.stringify(err));\n });\n}\n\nfunction Logout() {\n console.log('Trigger Logout()');\n\n Branch.logout().then(function(res) {\n console.log(res);\n alert('Response: ' + JSON.stringify(res));\n }).catch(function(err) {\n console.error(err);\n alert('Error: ' + JSON.stringify(err));\n });\n}\n\nvar branchUniversalObj = null;\n\nfunction CreateBranchUniversalObject() {\n\n console.log('Trigger CreateBranchUniversalObject()');\n\n var properties = {\n canonicalIdentifier: 'testbed',\n title: 'testbed',\n contentDescription: 'Testbed Application',\n contentImageUrl: 'https://imgflip.com/s/meme/Derp.jpg',\n contentIndexingMode: 'public',\n contentMetadata: {}\n };\n\n Branch.createBranchUniversalObject(properties)\n .then(function(res) {\n console.log(res);\n alert('Response: ' + JSON.stringify(res));\n branchUniversalObj = res;\n })\n .catch(function(err) {\n console.error(err);\n alert('Error: ' + JSON.stringify(err));\n });\n\n}\n\nfunction RegisterView() {\n console.log('Trigger RegisterView()');\n\n branchUniversalObj.registerView().then(function(res) {\n console.log(res);\n alert('Response: ' + JSON.stringify(res));\n }).catch(function(err) {\n console.error(err);\n alert('Error: ' + JSON.stringify(err));\n });;\n}\n\nfunction GenerateShortUrl() {\n console.log('Trigger GenerateShortUrl()');\n\n var properties = {\n feature: 'test',\n alias: document.getElementById('alias').value,\n channel: 'test',\n stage: 'test',\n duration: 10000\n };\n var controlParams = {\n $fallback_url: 'www.another.com',\n $desktop_url: 'www.desktop.com',\n $android_url: 'test',\n $ios_url: 'ios',\n $ipad_url: 'ipad',\n $fire_url: 'fire',\n $blackberry_url: 'blackberry',\n $windows_phone_url: 'win-phone'\n };\n\n branchUniversalObj.generateShortUrl(properties, controlParams).then(function(res) {\n console.log(res);\n document.getElementById('generated-url').value = res.url;\n }).catch(function(err) {\n console.error(err);\n alert('Error: ' + JSON.stringify(err));\n });\n}\n\nfunction ShowShareSheet() {\n console.log('Trigger ShowShareSheet()');\n\n var properties = {\n feature: 'test',\n alias: document.getElementById('alias').value,\n channel: 'test',\n stage: 'test',\n duration: 10000\n };\n var controlParams = {\n $fallback_url: 'www.another.com',\n $desktop_url: 'www.desktop.com',\n $android_url: 'test',\n $ios_url: 'ios',\n $ipad_url: 'ipad',\n $fire_url: 'fire',\n $blackberry_url: 'blackberry',\n $windows_phone_url: 'win-phone'\n };\n\n console.log(branchUniversalObj);\n\n // Set listeners\n branchUniversalObj.onShareSheetLaunched(function() {\n console.log('Share sheet launched');\n });\n branchUniversalObj.onShareSheetDismissed(function() {\n console.log('Share sheet dismissed');\n });\n branchUniversalObj.onLinkShareResponse(function(res) {\n console.log('Share link response: ' + JSON.stringify(res));\n });\n branchUniversalObj.onChannelSelected(function(res) {\n console.log('Channel selected: ' + JSON.stringify(res));\n });\n\n branchUniversalObj.showShareSheet(properties, controlParams, 'Custom Text');\n\n}\n\nfunction ListOnSpotlight() {\n console.log('Trigger ListOnSpotlight()');\n branchUniversalObj.listOnSpotlight().then(function(res) {\n console.log(res);\n alert('Response: ' + JSON.stringify(res));\n }).catch(function(err) {\n console.error(err);\n alert('Error: ' + JSON.stringify(err));\n });\n}\n\nfunction LoadRewards() {\n console.log('Trigger LoadRewards()');\n Branch.loadRewards().then(function(res) {\n console.log(res);\n alert('Response: ' + JSON.stringify(res));\n }).catch(function(err) {\n console.error(err);\n alert('Error: ' + JSON.stringify(err));\n });\n}\n\nfunction RedeemRewards() {\n console.log('Trigger RedeemRewards()');\n var reward = 1000;\n\n Branch.redeemRewards(reward).then(function(res) {\n console.log(res);\n alert('Response: ' + JSON.stringify(res));\n }).catch(function(err) {\n console.error(err);\n alert('Error: ' + JSON.stringify(err));\n });\n}\n\nfunction CreditHistory() {\n console.log('Trigger CreditHistory()');\n Branch.creditHistory().then(function(res) {\n console.log(res);\n alert('Response: ' + JSON.stringify(res));\n }).catch(function(err) {\n console.error(err);\n alert('Error: ' + JSON.stringify(err));\n });\n}\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/tests/plugin.xml b/tests/plugin.xml new file mode 100644 index 00000000..9d61826c --- /dev/null +++ b/tests/plugin.xml @@ -0,0 +1,36 @@ + + + + + branch-cordova-sdk-tests + Apache 2.0 + + + + diff --git a/tests/tests.js b/tests/tests.js new file mode 100644 index 00000000..c49840ce --- /dev/null +++ b/tests/tests.js @@ -0,0 +1,213 @@ +'use strict'; + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Branch.IO Cordova Plugin Unit-Test + * ---------------------------------- + */ +/* jshint jasmine: true */ + +exports.defineAutoTests = function () { + + describe('Branch.IO SDK (Branch)', function () { + it('should exist', function () { + expect(window.Branch).toBeDefined(); + }); + it('should contain a method called getLatestReferringParams()', function () { + expect(window.Branch.getLatestReferringParams).toBeDefined(); + expect((0, _typeof3.default)(window.Branch.getLatestReferringParams)).toBe('function'); + }); + it('should contain a method called getFirstReferringParams()', function () { + expect(window.Branch.getFirstReferringParams).toBeDefined(); + expect((0, _typeof3.default)(window.Branch.getFirstReferringParams)).toBe('function'); + }); + it('should contain a method called setIdentity()', function () { + expect(window.Branch.setIdentity).toBeDefined(); + expect((0, _typeof3.default)(window.Branch.setIdentity)).toBe('function'); + }); + it('should contain a method called logout()', function () { + expect(window.Branch.logout).toBeDefined(); + expect((0, _typeof3.default)(window.Branch.logout)).toBe('function'); + }); + it('should contain a method called createBranchUniversalObject()', function () { + expect(window.Branch.createBranchUniversalObject).toBeDefined(); + expect((0, _typeof3.default)(window.Branch.createBranchUniversalObject)).toBe('function'); + }); + it('should contain a method called userCompletedAction()', function () { + expect(window.Branch.userCompletedAction).toBeDefined(); + expect((0, _typeof3.default)(window.Branch.userCompletedAction)).toBe('function'); + }); + it('should contain a method called loadRewards()', function () { + expect(window.Branch.loadRewards).toBeDefined(); + expect((0, _typeof3.default)(window.Branch.loadRewards)).toBe('function'); + }); + it('should contain a method called redeemRewards()', function () { + expect(window.Branch.redeemRewards).toBeDefined(); + expect((0, _typeof3.default)(window.Branch.redeemRewards)).toBe('function'); + }); + it('should contain a method called creditHistory()', function () { + expect(window.Branch.creditHistory).toBeDefined(); + expect((0, _typeof3.default)(window.Branch.creditHistory)).toBe('function'); + }); + }); + + describe('Branch.getLatestReferringParams()', function () { + beforeEach(function (done) { + window.Branch.initSession().then(function () { + done(); + }); + }, 3000); + it('should return an object response', function (done) { + window.Branch.getLatestReferringParams().then(function (res) { + expect(typeof res === 'undefined' ? 'undefined' : (0, _typeof3.default)(res)).toBe('object'); + done(); + }); + }, 10000); + }); + + describe('Branch.getFirstReferringParams()', function () { + beforeEach(function (done) { + window.Branch.initSession().then(function () { + done(); + }); + }, 3000); + it('should return an object response', function (done) { + window.Branch.getFirstReferringParams().then(function (res) { + // We expect false since we won't open this from a branch link + expect(res).toBe(false); + done(); + }); + }, 10000); + }); + + describe('Branch.setIdentity()', function () { + beforeEach(function (done) { + window.Branch.initSession().then(function () { + done(); + }); + }, 3000); + it('should return "Success" response', function (done) { + window.Branch.setIdentity('new_identity').then(function (res) { + expect(typeof res === 'undefined' ? 'undefined' : (0, _typeof3.default)(res)).toBe('object'); + done(); + }); + }, 10000); + }); + + describe('Branch.createBranchUniversalObject()', function () { + var branchUniversalObj; + + beforeEach(function (done) { + window.Branch.initSession().then(function () { + var properties = { + canonicalIdentifier: 'testbed', + title: 'testbed', + contentDescription: 'Testbed Application', + contentImageUrl: 'https://imgflip.com/s/meme/Derp.jpg', + contentIndexingMode: 'public', + contentMetadata: {} + }; + window.Branch.createBranchUniversalObject(properties).then(function (res) { + branchUniversalObj = res; + done(); + }); + }); + }, 3000); + it('should execute register view', function (done) { + branchUniversalObj.registerView().then(function (res) { + expect(typeof res === 'undefined' ? 'undefined' : (0, _typeof3.default)(res)).toBe('object'); + done(); + }); + }, 5000); + it('should execute generate short url', function (done) { + var properties = { + feature: 'test', + alias: 'testbed', + channel: 'test', + stage: 'test', + duration: 10000 + }; + var controlParams = { + $fallback_url: 'www.another.com', + $desktop_url: 'www.desktop.com', + $android_url: 'test', + $ios_url: 'ios', + $ipad_url: 'ipad', + $fire_url: 'fire', + $blackberry_url: 'blackberry', + $windows_phone_url: 'win-phone' + }; + branchUniversalObj.generateShortUrl(properties, controlParams).then(function (res) { + expect(typeof res === 'undefined' ? 'undefined' : (0, _typeof3.default)(res)).toBe('object'); + done(); + }); + }, 5000); + }); + + describe('Branch.userCompletedAction()', function () { + beforeEach(function (done) { + window.Branch.initSession().then(function () { + done(); + }); + }, 3000); + it('should successfully execute the method', function (done) { + window.Branch.userCompletedAction('login'); + expect('Success').toBe('Success'); + done(); + }, 10000); + }); + + describe('Branch.loadRewards()', function () { + beforeEach(function (done) { + window.Branch.initSession().then(function () { + done(); + }); + }, 3000); + it('should return an object response', function (done) { + window.Branch.loadRewards().then(function (res) { + expect(typeof res === 'undefined' ? 'undefined' : (0, _typeof3.default)(res)).toBe('number'); + done(); + }, function (err) { + expect(typeof err === 'undefined' ? 'undefined' : (0, _typeof3.default)(err)).toBe('string'); + done(); + }); + }, 10000); + }); + + describe('Branch.redeemRewards()', function () { + beforeEach(function (done) { + window.Branch.initSession().then(function () { + done(); + }); + }, 3000); + it('should return an object/string error response', function (done) { + window.Branch.redeemRewards(100).then(function (res) { + expect(typeof res === 'undefined' ? 'undefined' : (0, _typeof3.default)(res)).toBe('object'); + done(); + }, function (err) { + expect(typeof err === 'undefined' ? 'undefined' : (0, _typeof3.default)(err)).toBe('string'); + done(); + }); + }, 10000); + }); + + describe('Branch.creditHistory()', function () { + beforeEach(function (done) { + window.Branch.initSession().then(function () { + done(); + }); + }, 3000); + it('should return the credit balance', function (done) { + window.Branch.creditHistory().then(function (res) { + expect(typeof res === 'undefined' ? 'undefined' : (0, _typeof3.default)(res)).toBe('object'); + done(); + }); + }, 10000); + }); +}; +//# sourceMappingURL=tests.js.map diff --git a/tests/tests.js.map b/tests/tests.js.map new file mode 100644 index 00000000..ec603da7 --- /dev/null +++ b/tests/tests.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["tests.js"],"names":[],"mappings":"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","file":"tests.js","sourcesContent":["/**\n * Branch.IO Cordova Plugin Unit-Test\n * ----------------------------------\n */\n/* jshint jasmine: true */\n\nexports.defineAutoTests = function() {\n\n\tdescribe('Branch.IO SDK (Branch)', function() {\n\t\tit('should exist', function() {\n\t\t\texpect(window.Branch).toBeDefined();\n\t\t});\n\t\tit('should contain a method called getLatestReferringParams()', function() {\n\t\t\texpect(window.Branch.getLatestReferringParams).toBeDefined();\n\t\t\texpect(typeof(window.Branch.getLatestReferringParams)).toBe('function');\n\t\t});\n\t\tit('should contain a method called getFirstReferringParams()', function() {\n\t\t\texpect(window.Branch.getFirstReferringParams).toBeDefined();\n\t\t\texpect(typeof(window.Branch.getFirstReferringParams)).toBe('function');\n\t\t});\n\t\tit('should contain a method called setIdentity()', function() {\n\t\t\texpect(window.Branch.setIdentity).toBeDefined();\n\t\t\texpect(typeof(window.Branch.setIdentity)).toBe('function');\n\t\t});\n\t\tit('should contain a method called logout()', function() {\n\t\t\texpect(window.Branch.logout).toBeDefined();\n\t\t\texpect(typeof(window.Branch.logout)).toBe('function');\n\t\t});\n\t\tit('should contain a method called createBranchUniversalObject()', function() {\n\t\t\texpect(window.Branch.createBranchUniversalObject).toBeDefined();\n\t\t\texpect(typeof(window.Branch.createBranchUniversalObject)).toBe('function');\n\t\t});\n\t\tit('should contain a method called userCompletedAction()', function() {\n\t\t\texpect(window.Branch.userCompletedAction).toBeDefined();\n\t\t\texpect(typeof(window.Branch.userCompletedAction)).toBe('function');\n\t\t});\n\t\tit('should contain a method called loadRewards()', function() {\n\t\t\texpect(window.Branch.loadRewards).toBeDefined();\n\t\t\texpect(typeof(window.Branch.loadRewards)).toBe('function');\n\t\t});\n\t\tit('should contain a method called redeemRewards()', function() {\n\t\t\texpect(window.Branch.redeemRewards).toBeDefined();\n\t\t\texpect(typeof(window.Branch.redeemRewards)).toBe('function');\n\t\t});\n\t\tit('should contain a method called creditHistory()', function() {\n\t\t\texpect(window.Branch.creditHistory).toBeDefined();\n\t\t\texpect(typeof(window.Branch.creditHistory)).toBe('function');\n\t\t});\n\t});\n\n\tdescribe('Branch.getLatestReferringParams()', function() {\n\t\tbeforeEach(function(done) {\n\t\t\twindow.Branch.initSession().then(function() {\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 3000);\n\t\tit('should return an object response', function(done) {\n\t\t\twindow.Branch.getLatestReferringParams().then(function(res) {\n\t\t\t\texpect(typeof(res)).toBe('object');\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 10000);\n\t});\n\n\tdescribe('Branch.getFirstReferringParams()', function() {\n\t\tbeforeEach(function(done) {\n\t\t\twindow.Branch.initSession().then(function() {\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 3000);\n\t\tit('should return an object response', function(done) {\n\t\t\twindow.Branch.getFirstReferringParams().then(function(res) {\n\t\t\t\t// We expect false since we won't open this from a branch link\n\t\t\t\texpect(res).toBe(false);\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 10000);\n\t});\n\n\n\tdescribe('Branch.setIdentity()', function() {\n\t\tbeforeEach(function(done) {\n\t\t\twindow.Branch.initSession().then(function() {\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 3000);\n\t\tit('should return \"Success\" response', function(done) {\n\t\t\twindow.Branch.setIdentity('new_identity').then(function(res) {\n\t\t\t\texpect(typeof(res)).toBe('object');\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 10000);\n\t});\n\n\tdescribe('Branch.createBranchUniversalObject()', function() {\n\t\tvar branchUniversalObj;\n\n\t\tbeforeEach(function(done) {\n\t\t\twindow.Branch.initSession().then(function() {\n\t\t\t var properties = {\n\t\t\t canonicalIdentifier: 'testbed',\n\t\t\t title: 'testbed',\n\t\t\t contentDescription: 'Testbed Application',\n\t\t\t contentImageUrl: 'https://imgflip.com/s/meme/Derp.jpg',\n\t\t\t contentIndexingMode: 'public',\n\t\t\t contentMetadata: {}\n\t\t\t };\n\t\t\t\twindow.Branch.createBranchUniversalObject(properties).then(function(res) {\n\t\t\t\t\tbranchUniversalObj = res;\n\t\t\t\t\tdone();\n\t\t\t\t});\n\t\t\t});\n\t\t}, 3000);\n\t\tit('should execute register view', function(done) {\n\t\t\tbranchUniversalObj.registerView().then(function(res) {\n\t\t\t\texpect(typeof(res)).toBe('object');\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 5000);\n\t\tit('should execute generate short url', function(done) {\n\t\t var properties = {\n\t\t feature: 'test',\n\t\t alias: 'testbed',\n\t\t channel: 'test',\n\t\t stage: 'test',\n\t\t duration: 10000\n\t\t };\n\t\t var controlParams = {\n\t\t $fallback_url: 'www.another.com',\n\t\t $desktop_url: 'www.desktop.com',\n\t\t $android_url: 'test',\n\t\t $ios_url: 'ios',\n\t\t $ipad_url: 'ipad',\n\t\t $fire_url: 'fire',\n\t\t $blackberry_url: 'blackberry',\n\t\t $windows_phone_url: 'win-phone'\n\t\t };\n\t\t branchUniversalObj.generateShortUrl(properties, controlParams).then(function(res) {\n\t\t expect(typeof(res)).toBe('object');\n\t\t done();\n\t\t });\n\t\t}, 5000);\n\t});\n\n\tdescribe('Branch.userCompletedAction()', function() {\n\t\tbeforeEach(function(done) {\n\t\t\twindow.Branch.initSession().then(function() {\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 3000);\n\t\tit('should successfully execute the method', function(done) {\n\t\t\twindow.Branch.userCompletedAction('login');\n\t\t\texpect('Success').toBe('Success');\n\t\t\tdone();\n\t\t}, 10000);\n\t});\n\n\tdescribe('Branch.loadRewards()', function() {\n\t\tbeforeEach(function(done) {\n\t\t\twindow.Branch.initSession().then(function() {\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 3000);\n\t\tit('should return an object response', function(done) {\n\t\t\twindow.Branch.loadRewards().then(function(res) {\n\t\t\t\texpect(typeof(res)).toBe('number');\n\t\t\t\tdone();\n\t\t\t}, function(err) {\n\t\t\t\texpect(typeof(err)).toBe('string');\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 10000);\n\t});\n\n\tdescribe('Branch.redeemRewards()', function() {\n\t\tbeforeEach(function(done) {\n\t\t\twindow.Branch.initSession().then(function() {\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 3000);\n\t\tit('should return an object/string error response', function(done) {\n\t\t\twindow.Branch.redeemRewards(100).then(function(res) {\n\t\t\t\texpect(typeof(res)).toBe('object');\n\t\t\t\tdone();\n\t\t\t}, function(err) {\n\t\t\t\texpect(typeof(err)).toBe('string');\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 10000);\n\t});\n\n\tdescribe('Branch.creditHistory()', function() {\n\t\tbeforeEach(function(done) {\n\t\t\twindow.Branch.initSession().then(function() {\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 3000);\n\t\tit('should return the credit balance', function(done) {\n\t\t\twindow.Branch.creditHistory().then(function(res) {\n\t\t\t\texpect(typeof(res)).toBe('object');\n\t\t\t\tdone();\n\t\t\t});\n\t\t}, 10000);\n\t});\n\n};\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/www/branch.js b/www/branch.js new file mode 100644 index 00000000..ae6c26c8 --- /dev/null +++ b/www/branch.js @@ -0,0 +1,386 @@ +'use strict'; + +var _promise = require('babel-runtime/core-js/promise'); + +var _promise2 = _interopRequireDefault(_promise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Branch.IO SDK + * ------------- + * Method usage: + * All methods are promisified, therefore you can call .then(successCallback, errorCallback) for any of the method + * called for executing success or error callbacks. + */ + +var exec = require('cordova/exec'); +var deviceVendor = window.clientInformation.vendor; +var _API_CLASS = 'BranchSDK'; // SDK Class + +/** + * Execute SDK method using cordova.exec() + * + * @param (String) method - The class method to execute. + * @param (Array) params - Method parameter(s) to pass. + * + * @return (Promise) + */ +function execute(method, params) { + + params = !params ? [] : params; + + return new _promise2.default(function (resolve, reject) { + exec(function (res) { + resolve(res); + }, function (err) { + reject(err); + }, _API_CLASS, method, params); + }); +} + +/** + * Set listener callback for SDK method. + * + * @param (String) method - The class method to execute. + * @param (Function) callback - The method listener callback. + * @param (Array) params - The method listener parameters. + * + * @return (Promise) + */ +function executeCallback(method, callback, params) { + + params = !params ? [] : params; + + exec(callback, function (err) { + console.error(err); + }, _API_CLASS, method, params); +} + +/** + * @class Branch + */ +var Branch = function Branch() { + + this.debugMode = false; +}; + +/** + * Initialize the Branch instance. + * + * @return (Promise) + */ +Branch.prototype.initSession = function () { + + return execute('initSession'); +}; + +/** + * Get Mixpanel tolen/assisstance. + * NOTE: This must be called before initSession + * + * @param (String) token. Default = false + * + * @return (Promise) + */ +Branch.prototype.setMixpanelToken = function (token) { + + return execute('setMixpanelToken', [token]); +}; + +/** + * Retrieves the install session parameters. + * + * @return (Promise) + */ +Branch.prototype.getFirstReferringParams = function () { + + return execute('getFirstReferringParams'); +}; + +/** + * Retrieves the latest referring parameters. + * + * @return (Promise) + */ +Branch.prototype.getLatestReferringParams = function () { + + return execute('getLatestReferringParams'); +}; + +/** + * Sets the identity of a user and returns the data. + * + * @param (String) identity - A unique identifier for the user [REQUIRED] + * + * @return (Promise) + * + */ +Branch.prototype.setIdentity = function (identity) { + + if (identity) { + return execute('setIdentity', [identity]); + } else { + return new _promise2.default(function (resolve, reject) { + reject('Please set an identity'); + }); + } +}; + +/** + * Logout from the current session. Replace session and identity IDs. + * + * @return (Promise) + */ +Branch.prototype.logout = function () { + + return execute('logout'); +}; + +/** + * Register custom events. + * + * @param (String) action - Name of the custom action + * @param (Object) metaData - Data to pass with the action [OPTIONAL] + * + * @return (Promise) + */ +Branch.prototype.userCompletedAction = function (action, metaData) { + + var args = [action]; + + if (metaData) { + args.push(metaData); + } + + return execute('userCompletedAction', args); +}; + +/** + * Create an universal Branch object + * + * @params (Object) options + * + * @return (Promise) + * + * options: + * -------------------------------------------------------------- + * | KEY | TYPE | DESCRIPTION | + * -------------------------------------------------------------- + * | canonicalIdentifier | String | The object identifier | + * | title | String | The object title | + * | contentDescription | String | Object description | + * | contentImageUrl | String | The image URL | + * | contentIndexingMode | String | Indexing Mode | + * | | |('private' or 'public')| + * | contentMetadata | Object | Custom key/value | + * -------------------------------------------------------------- + */ +Branch.prototype.createBranchUniversalObject = function (options) { + + return new _promise2.default(function (resolve, reject) { + execute('createBranchUniversalObject', [options]).then(function (res) { + + var obj = { + message: res.message, + instanceId: res.branchUniversalObjectId + }; + + // Attach object functions + /** + * Register view count. + * + * @return (Promise) + */ + obj.registerView = function () { + + return execute('registerView', [obj.instanceId]); + }; + + /** + * Generates a short url. + * + * @param (Object) options + * @param (Object) controlParameters + * + * @return (Promise) + * + * options: + * -------------------------------------------------- + * | KEY | TYPE | DESCRIPTION | + * -------------------------------------------------- + * | feature | String | The link feature | + * | alias | String | The link alias | + * | channel | String | The link channel | + * | stage | String | The link stage | + * | duration | Int | The link duration | + * -------------------------------------------------- + * + * controlParameters: + * ------------------------------------------------------- + * | KEY | TYPE | DESCRIPTION | + * ------------------------------------------------------- + * | $fallback_url | String | Fallback URL | + * | $desktop_url | String | Desktop URL | + * | $android_url | String | Android URL | + * | $ios_url | String | iOS URL | + * | $ipad_url | String | iPad URL | + * | $fire_url | String | Kindle Fire URL | + * | $blackberry_url | String | Blackberry URL | + * | $windows_phone_url | String | Kindle Fire URL | + * ------------------------------------------------------- + */ + obj.generateShortUrl = function (options, controlParameters) { + + return execute('generateShortUrl', [obj.instanceId, options, controlParameters]); + }; + + /** + * Show the share dialog. + * + * @param (Object) options + * @param (Object) controlParameters + * @param (String) shareText [OPTIONAL] + * + * @return (Promise) + * + * options: + * -------------------------------------------------- + * | KEY | TYPE | DESCRIPTION | + * -------------------------------------------------- + * | feature | String | The link feature | + * | alias | String | The link alias | + * | channel | String | The link channel | + * | stage | String | The link stage | + * | duration | Int | The link duration | + * -------------------------------------------------- + * + * controlParameters: + * ------------------------------------------------------- + * | KEY | TYPE | DESCRIPTION | + * ------------------------------------------------------- + * | $fallback_url | String | Fallback URL | + * | $desktop_url | String | Desktop URL | + * | $android_url | String | Android URL | + * | $ios_url | String | iOS URL | + * | $ipad_url | String | iPad URL | + * | $fire_url | String | Kindle Fire URL | + * | $blackberry_url | String | Blackberry URL | + * | $windows_phone_url | String | Kindle Fire URL | + * ------------------------------------------------------- + */ + obj.showShareSheet = function (options, controlParameters, shareText) { + + if (!shareText) { + shareText = 'This stuff is awesome: '; + } + + return execute('showShareSheet', [obj.instanceId, options, controlParameters, shareText]); + }; + + /** + * Set on share sheet launched listener callback. + * + * @param (Function) callback + */ + obj.onShareSheetLaunched = function (callback) { + + if (deviceVendor.indexOf('Apple') < 0) { + executeCallback('onShareLinkDialogLaunched', callback, [obj.instanceId]); + } + }; + + obj.onShareSheetDismissed = function (callback) { + + executeCallback('onShareLinkDialogDismissed', callback, [obj.instanceId]); + }; + + /** + * Set on link share listener callback. + * + * @param (Function) callback + */ + obj.onLinkShareResponse = function (callback) { + + executeCallback('onLinkShareResponse', callback, [obj.instanceId]); + }; + + /** + * Set on channel select listener callback. + * + * @param (Function) callback + */ + obj.onChannelSelected = function (callback) { + + if (deviceVendor.indexOf('Apple') < 0) { + executeCallback('onChannelSelected', callback, [obj.instanceId]); + } + }; + + /** + * List item on Spotlight (iOS Only). + */ + obj.listOnSpotlight = function () { + + return execute('listOnSpotlight', [obj.instanceId]); + }; + + resolve(obj); + }, function (err) { + reject(err); + }); + }); +}; + +/** + * Retrieve the current reward balance. + * + * @return (Promise) + */ +Branch.prototype.loadRewards = function (bucket) { + + if (!bucket) { + bucket = ''; + } + + return execute('loadRewards', [bucket]); +}; + +/** + * Redeem rewards to your account. + * + * @param (Int) value - The amount to redeem. + * @param (String) bucket - The value containing the name of the referral bucket to attempt to redeem credits from. [OPTIONAL] + * + * @return (Promise) + */ +Branch.prototype.redeemRewards = function (value, bucket) { + + var params = [value]; + + if (bucket) { + params.push(bucket); + } + + return execute('redeemRewards', params); +}; + +/** + * Retrieve the entire history of credits and redemptions from the individual user. + * + * @return (Promise) + */ +Branch.prototype.creditHistory = function () { + + return execute('getCreditHistory'); +}; + +/** + * NonBranchLinkHandler callback placeholder. + * + * @param {String} response + */ +window.NonBranchLinkHandler = typeof NonBranchLinkHandler === 'undefined' ? function (response) {} : NonBranchLinkHandler; + +module.exports = new Branch(); +//# sourceMappingURL=branch.js.map diff --git a/www/branch.js.map b/www/branch.js.map new file mode 100644 index 00000000..486bf4af --- /dev/null +++ b/www/branch.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["branch.js"],"names":[],"mappings":"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","file":"branch.js","sourcesContent":["/**\n * Branch.IO SDK\n * -------------\n * Method usage:\n * All methods are promisified, therefore you can call .then(successCallback, errorCallback) for any of the method\n * called for executing success or error callbacks.\n */\n\nvar exec = require('cordova/exec');\nvar deviceVendor = window.clientInformation.vendor;\nvar _API_CLASS = 'BranchSDK'; // SDK Class\n\n/**\n * Execute SDK method using cordova.exec()\n *\n * @param (String) method - The class method to execute.\n * @param (Array) params - Method parameter(s) to pass.\n *\n * @return (Promise)\n */\nfunction execute(method, params) {\n\n params = (!params) ? [] : params;\n\n return new Promise(function(resolve, reject) {\n exec(function(res) {\n resolve(res);\n }, function(err) {\n reject(err);\n }, _API_CLASS, method, params);\n });\n\n}\n\n/**\n * Set listener callback for SDK method.\n *\n * @param (String) method - The class method to execute.\n * @param (Function) callback - The method listener callback.\n * @param (Array) params - The method listener parameters.\n *\n * @return (Promise)\n */\nfunction executeCallback(method, callback, params) {\n\n params = (!params) ? [] : params;\n\n exec(callback, function(err) {\n console.error(err);\n }, _API_CLASS, method, params);\n\n}\n\n/**\n * @class Branch\n */\nvar Branch = function() {\n\n this.debugMode = false;\n\n};\n\n/**\n * Initialize the Branch instance.\n *\n * @return (Promise)\n */\nBranch.prototype.initSession = function() {\n\n return execute('initSession');\n\n};\n\n/**\n * Get Mixpanel tolen/assisstance.\n * NOTE: This must be called before initSession\n *\n * @param (String) token. Default = false\n *\n * @return (Promise)\n */\nBranch.prototype.setMixpanelToken = function(token) {\n\n return execute('setMixpanelToken', [ token ]);\n\n};\n\n/**\n * Retrieves the install session parameters.\n *\n * @return (Promise)\n */\nBranch.prototype.getFirstReferringParams = function() {\n\n return execute('getFirstReferringParams');\n\n};\n\n/**\n * Retrieves the latest referring parameters.\n *\n * @return (Promise)\n */\nBranch.prototype.getLatestReferringParams = function() {\n\n return execute('getLatestReferringParams');\n\n};\n\n/**\n * Sets the identity of a user and returns the data.\n *\n * @param (String) identity - A unique identifier for the user [REQUIRED]\n *\n * @return (Promise)\n *\n */\nBranch.prototype.setIdentity = function(identity) {\n\n if (identity) {\n return execute('setIdentity', [ identity ]);\n }\n else {\n return new Promise(function(resolve, reject) {\n reject('Please set an identity');\n });\n }\n\n};\n\n/**\n * Logout from the current session. Replace session and identity IDs.\n *\n * @return (Promise)\n */\nBranch.prototype.logout = function() {\n\n return execute('logout');\n\n};\n\n/**\n * Register custom events.\n *\n * @param (String) action - Name of the custom action\n * @param (Object) metaData - Data to pass with the action [OPTIONAL]\n *\n * @return (Promise)\n */\nBranch.prototype.userCompletedAction = function(action, metaData) {\n\n var args = [ action ];\n\n if (metaData) {\n args.push(metaData);\n }\n\n return execute('userCompletedAction', args);\n\n};\n\n/**\n * Create an universal Branch object\n *\n * @params (Object) options\n *\n * @return (Promise)\n *\n * options:\n * --------------------------------------------------------------\n * | KEY | TYPE | DESCRIPTION |\n * --------------------------------------------------------------\n * | canonicalIdentifier | String | The object identifier |\n * | title | String | The object title |\n * | contentDescription | String | Object description |\n * | contentImageUrl | String | The image URL |\n * | contentIndexingMode | String | Indexing Mode |\n * | | |('private' or 'public')|\n * | contentMetadata | Object | Custom key/value |\n * --------------------------------------------------------------\n */\nBranch.prototype.createBranchUniversalObject = function(options) {\n\n return new Promise(function(resolve, reject) {\n execute('createBranchUniversalObject', [ options ]).then(function(res) {\n\n var obj = {\n message: res.message,\n instanceId: res.branchUniversalObjectId\n };\n\n // Attach object functions\n /**\n * Register view count.\n *\n * @return (Promise)\n */\n obj.registerView = function() {\n\n return execute('registerView', [ obj.instanceId ]);\n\n };\n\n /**\n * Generates a short url.\n *\n * @param (Object) options\n * @param (Object) controlParameters\n *\n * @return (Promise)\n *\n * options:\n * --------------------------------------------------\n * | KEY | TYPE | DESCRIPTION |\n * --------------------------------------------------\n * | feature | String | The link feature |\n * | alias | String | The link alias |\n * | channel | String | The link channel |\n * | stage | String | The link stage |\n * | duration | Int | The link duration |\n * --------------------------------------------------\n *\n * controlParameters:\n * -------------------------------------------------------\n * | KEY | TYPE | DESCRIPTION |\n * -------------------------------------------------------\n * | $fallback_url | String | Fallback URL |\n * | $desktop_url | String | Desktop URL |\n * | $android_url | String | Android URL |\n * | $ios_url | String | iOS URL |\n * | $ipad_url | String | iPad URL |\n * | $fire_url | String | Kindle Fire URL |\n * | $blackberry_url | String | Blackberry URL |\n * | $windows_phone_url | String | Kindle Fire URL |\n * -------------------------------------------------------\n */\n obj.generateShortUrl = function(options, controlParameters) {\n\n return execute('generateShortUrl', [ obj.instanceId, options, controlParameters ]);\n\n };\n\n /**\n * Show the share dialog.\n *\n * @param (Object) options\n * @param (Object) controlParameters\n * @param (String) shareText [OPTIONAL]\n *\n * @return (Promise)\n *\n * options:\n * --------------------------------------------------\n * | KEY | TYPE | DESCRIPTION |\n * --------------------------------------------------\n * | feature | String | The link feature |\n * | alias | String | The link alias |\n * | channel | String | The link channel |\n * | stage | String | The link stage |\n * | duration | Int | The link duration |\n * --------------------------------------------------\n *\n * controlParameters:\n * -------------------------------------------------------\n * | KEY | TYPE | DESCRIPTION |\n * -------------------------------------------------------\n * | $fallback_url | String | Fallback URL |\n * | $desktop_url | String | Desktop URL |\n * | $android_url | String | Android URL |\n * | $ios_url | String | iOS URL |\n * | $ipad_url | String | iPad URL |\n * | $fire_url | String | Kindle Fire URL |\n * | $blackberry_url | String | Blackberry URL |\n * | $windows_phone_url | String | Kindle Fire URL |\n * -------------------------------------------------------\n */\n obj.showShareSheet = function(options, controlParameters, shareText) {\n\n if (!shareText) {\n shareText = 'This stuff is awesome: ';\n }\n\n return execute('showShareSheet', [ obj.instanceId, options, controlParameters, shareText ]);\n\n };\n\n /**\n * Set on share sheet launched listener callback.\n *\n * @param (Function) callback\n */\n obj.onShareSheetLaunched = function(callback) {\n\n if (deviceVendor.indexOf('Apple') < 0) {\n executeCallback('onShareLinkDialogLaunched', callback, [ obj.instanceId ]);\n }\n\n };\n\n obj.onShareSheetDismissed = function(callback) {\n\n executeCallback('onShareLinkDialogDismissed', callback, [ obj.instanceId ]);\n\n }\n\n /**\n * Set on link share listener callback.\n *\n * @param (Function) callback\n */\n obj.onLinkShareResponse = function(callback) {\n\n executeCallback('onLinkShareResponse', callback, [ obj.instanceId ]);\n\n };\n\n /**\n * Set on channel select listener callback.\n *\n * @param (Function) callback\n */\n obj.onChannelSelected = function(callback) {\n\n if (deviceVendor.indexOf('Apple') < 0) {\n executeCallback('onChannelSelected', callback, [ obj.instanceId ]);\n }\n\n };\n\n /**\n * List item on Spotlight (iOS Only).\n */\n obj.listOnSpotlight = function() {\n\n return execute('listOnSpotlight', [ obj.instanceId ]);\n\n };\n\n resolve(obj);\n\n }, function(err) {\n reject(err);\n });\n });\n\n};\n\n/**\n * Retrieve the current reward balance.\n *\n * @return (Promise)\n */\nBranch.prototype.loadRewards = function(bucket) {\n\n if (!bucket) {\n bucket = '';\n }\n\n return execute('loadRewards', [ bucket ]);\n\n};\n\n/**\n * Redeem rewards to your account.\n *\n * @param (Int) value - The amount to redeem.\n * @param (String) bucket - The value containing the name of the referral bucket to attempt to redeem credits from. [OPTIONAL]\n *\n * @return (Promise)\n */\nBranch.prototype.redeemRewards = function(value, bucket) {\n\n var params = [ value ];\n\n if (bucket) {\n params.push(bucket);\n }\n\n return execute('redeemRewards', params);\n\n};\n\n/**\n * Retrieve the entire history of credits and redemptions from the individual user.\n *\n * @return (Promise)\n */\nBranch.prototype.creditHistory = function() {\n\n return execute('getCreditHistory');\n\n};\n\n/**\n * NonBranchLinkHandler callback placeholder.\n *\n * @param {String} response\n */\nwindow.NonBranchLinkHandler = (typeof NonBranchLinkHandler === 'undefined') ? function(response) {} : NonBranchLinkHandler;\n\nmodule.exports = new Branch;\n"],"sourceRoot":"/source/"} \ No newline at end of file