Skip to content

Commit

Permalink
- Added hooks to update android manifest and generate app associate f…
Browse files Browse the repository at this point in the history
…ile for iOS

- Bugfix get params from deep links on iOS
- Added Branch framework instead of lib/ lib folders
  • Loading branch information
Harsha Bonthu committed Mar 11, 2016
1 parent a30665d commit 61a4605
Show file tree
Hide file tree
Showing 96 changed files with 1,749 additions and 7,091 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ There's a full demo app embedded in this repository. It should serve as an examp
**Install parameters:**
* `BRANCH_LIVE_KEY` - Your Branch live API key. You can sign up for your own Branch key at [https://dashboard.branch.io](https://dashboard.branch.io).
* `URI_SCHEME` - It could be your app name or the URI set in your Branch dashboard. As a reminder, the URI scheme is what you use to open your app from a browser, i.e. `yourapp://`.
* [optional] `ENCODED_ID` - This is for supporting App Links (6.0+) on Android. You can obtain the encodied id from the Branch dashboard. Just append `--variable ENCODED_ID=your-encoded-id` to the plugin install command below. For more info about App Links, please see [this](https://github.com/BranchMetrics/Android-Deferred-Deep-Linking-SDK/blob/master/README.md#leverage-android-app-links-for-deep-linking) section of the Android readme.
* [optional] `ENCODED_ID` - This is for supporting App Links (6.0+) on Android. You can obtain the encodied id from the Branch dashboard. For more info about App Links, please see [this](https://github.com/BranchMetrics/Android-Deferred-Deep-Linking-SDK/blob/master/README.md#leverage-android-app-links-for-deep-linking) section of the Android readme.

#### Cordova

Expand Down
86 changes: 86 additions & 0 deletions hooks/afterPrepareHook.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
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 <universal-links>
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'),
// iosAppSiteAssociationFile = require('./lib/ios/appleAppSiteAssociationFile.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 <universal-links> tag.
*/
function activateUniversalLinksInAndroid(cordovaContext, pluginPreferences) {
// inject preferenes into AndroidManifest.xml
androidManifestWriter.writePreferences(cordovaContext, pluginPreferences);

// generate html file with the <link> tags that you should inject on the website.
// androidWebHook.generate(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 <universal-links> tag.
*/
function activateUniversalLinksInIos(cordovaContext, pluginPreferences) {
// modify xcode project preferences
iosProjectPreferences.enableAssociativeDomainsCapability(cordovaContext);

// generate entitlements file
iosProjectEntitlements.generateAssociatedDomainsEntitlements(cordovaContext, pluginPreferences);

// generate apple-site-association-file
// iosAppSiteAssociationFile.generate(cordovaContext, pluginPreferences);
}
154 changes: 154 additions & 0 deletions hooks/beforePluginInstallHook.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/**
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);
};
78 changes: 78 additions & 0 deletions hooks/iosBeforePrepareHook.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
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
Loading

0 comments on commit 61a4605

Please sign in to comment.