Skip to content

Commit

Permalink
Merge pull request #9275 from janvennemann/TIMOB-24446-6_2_X
Browse files Browse the repository at this point in the history
[TIMOB-24446](6_2_X) Allow replacing bundled Android Support Libraries
  • Loading branch information
Lokesh Choudhary committed Aug 3, 2017
2 parents d31b285 + 0ff16e5 commit 5b4f617
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 8 deletions.
22 changes: 18 additions & 4 deletions android/cli/commands/_build.js
Original file line number Diff line number Diff line change
Expand Up @@ -2818,7 +2818,7 @@ AndroidBuilder.prototype.getNativeModuleBindings = function getNativeModuleBindi
};

AndroidBuilder.prototype.processTiSymbols = function processTiSymbols(next) {
var depMap = JSON.parse(fs.readFileSync(path.join(this.platformPath, 'dependency.json'))),
var depMap = this.dependencyMap,
modulesMap = JSON.parse(fs.readFileSync(path.join(this.platformPath, 'modules.json'))),
modulesPath = path.join(this.platformPath, 'modules'),
moduleBindings = {},
Expand Down Expand Up @@ -2878,7 +2878,9 @@ AndroidBuilder.prototype.processTiSymbols = function processTiSymbols(next) {
var jar = moduleJarMap[namespace];
if (jar) {
jar = jar == 'titanium.jar' ? path.join(this.platformPath, jar) : path.join(this.platformPath, 'modules', jar);
if (fs.existsSync(jar) && !jarLibraries[jar]) {
if (this.isExternalAndroidLibraryAvailable(jar)) {
this.logger.debug('Excluding library ' + jar.cyan);
} else if (fs.existsSync(jar) && !jarLibraries[jar]) {
this.logger.debug(__('Adding library %s', jar.cyan));
jarLibraries[jar] = 1;
}
Expand All @@ -2887,7 +2889,13 @@ AndroidBuilder.prototype.processTiSymbols = function processTiSymbols(next) {
}

depMap.libraries[namespace] && depMap.libraries[namespace].forEach(function (jar) {
if (fs.existsSync(jar = path.join(this.platformPath, jar)) && !jarLibraries[jar]) {
jar = path.join(this.platformPath, jar)
if (this.isExternalAndroidLibraryAvailable(jar)) {
this.logger.debug('Excluding dependency library ' + jar.cyan);
return;
}

if (fs.existsSync(jar) && !jarLibraries[jar]) {
this.logger.debug(__('Adding dependency library %s', jar.cyan));
jarLibraries[jar] = 1;
}
Expand Down Expand Up @@ -3067,7 +3075,13 @@ AndroidBuilder.prototype.copyModuleResources = function copyModuleResources(next
resPkgFile = jarFile.replace(/\.jar$/, '.respackage');

if (fs.existsSync(resPkgFile) && fs.existsSync(resFile)) {
this.resPackages[resFile] = fs.readFileSync(resPkgFile).toString().split('\n').shift().trim();
var packageName = fs.readFileSync(resPkgFile).toString().split(/\r?\n/).shift().trim();
if (!this.hasAndroidLibrary(packageName)) {
this.resPackages[resFile] = packageName;
} else {
this.logger.info(__('Excluding core module resources of %s (%s) because Android Library with same package name is available.', jarFile, packageName));
return done();
}
}

if (!fs.existsSync(jarFile) || !fs.existsSync(resFile)) return done();
Expand Down
34 changes: 30 additions & 4 deletions android/cli/commands/_buildModule.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ AndroidModuleBuilder.prototype.run = function run(logger, config, cli, finished)
cli.emit('build.module.pre.compile', this, next);
},

'replaceBundledSupportLibraries',
'processResources',
'compileAidlFiles',
'compileModuleJavaSrc',
Expand Down Expand Up @@ -268,7 +269,6 @@ AndroidModuleBuilder.prototype.initialize = function initialize(next) {
}, this);
}, this);

this.dependencyJsonFile = path.join(this.platformPath, 'dependency.json');
this.templatesDir = path.join(this.platformPath, 'templates', 'build');
this.moduleIdSubDir = this.manifest.moduleid.split('.').join(path.sep);

Expand Down Expand Up @@ -354,6 +354,27 @@ AndroidModuleBuilder.prototype.loginfo = function loginfo() {
this.logger.info(__('Resources Dir: %s', this.resourcesDir.cyan));
};

/**
* Replaces any .jar file in the Class Path that comes bundled with our SDK
* with a user provided one if available.
*
* We need to do this in this in an extra step because by the time our bundled
* Support Libraries will be added, we haven't parsed any other Android
* Libraries yet.
*
* @param {Function} next Callback function
*/
AndroidModuleBuilder.prototype.replaceBundledSupportLibraries = function replaceBundledSupportLibraries(next) {
Object.keys(this.classPaths).forEach(function(libraryPathAndFilename) {
if (this.isExternalAndroidLibraryAvailable(libraryPathAndFilename)) {
this.logger.debug('Excluding library ' + libraryPathAndFilename.cyan);
delete this.classPaths[libraryPathAndFilename];
}
}, this);

next();
};

/**
* Processes resources for this module.
*
Expand Down Expand Up @@ -421,8 +442,13 @@ AndroidModuleBuilder.prototype.processResources = function processResources(next
var resArchivePathAndFilename = path.join(modulesPath, file.replace(/\.jar$/, '.res.zip'));
var respackagePathAndFilename = path.join(modulesPath, file.replace(/\.jar$/, '.respackage'));
if (fs.existsSync(resArchivePathAndFilename) && fs.existsSync(respackagePathAndFilename)) {
extraPackages.push(fs.readFileSync(respackagePathAndFilename).toString().split('\n').shift().trim());
resArchives.push(resArchivePathAndFilename);
var packageName = fs.readFileSync(respackagePathAndFilename).toString().split(/\r?\n/).shift().trim();
if (!this.hasAndroidLibrary(packageName)) {
extraPackages.push(packageName);
resArchives.push(resArchivePathAndFilename);
} else {
this.logger.info(__('Excluding core module resources of %s (%s) because Android Library with same package name is available.', file, packageName));
}
}
}, this);

Expand Down Expand Up @@ -1121,7 +1147,7 @@ AndroidModuleBuilder.prototype.compileJsClosure = function (next) {

this.logger.info(__('Generating v8 bindings'));

var dependsMap = JSON.parse(fs.readFileSync(this.dependencyJsonFile));
var dependsMap = this.dependencyMap;
Array.prototype.push.apply(this.metaData,dependsMap.required);

Object.keys(dependsMap.dependencies).forEach(function (key) {
Expand Down
37 changes: 37 additions & 0 deletions android/cli/hooks/aar-transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,43 @@ exports.init = function (logger, config, cli, appc) {
scanModuleAndStartTransform(builder, logger, callback);
}
});

cli.on('build.android.dexer', {
priority: 1100,
/**
* Fixes an issue with Hyperloop 2.1.0 which causes a crash when trying to
* override the Android Support Libraries with local .aar files. Hyperloop
* 2.1.0 will always manually add our bundled Android Support Libraries
* to the dexer paths even if they were replaced by the builder. To fix this
* we check the altered dexer paths again and remove any replaced libraries.
*
* @param {Object} data Hook data
* @param {Function} callback Callback function
*/
pre: function(data, callback) {
var builder= data.ctx;
var dexerOptions = data.args[1].slice(0, 6);
var dexerPaths = data.args[1].slice(6);
var hyperloopModule = null;
builder.nativeLibModules.forEach(function (module) {
if (module.id === 'hyperloop' && module.version === '2.1.0') {
hyperloopModule = module;
}
});
if (hyperloopModule && builder.androidLibraries.length > 0) {
var fixedDexerPaths = [];
dexerPaths.forEach(function (entryPathAndFilename) {
if (!this.isExternalAndroidLibraryAvailable(entryPathAndFilename)) {
fixedDexerPaths.push(entryPathAndFilename);
} else {
logger.trace('Removed duplicate library ' + entryPathAndFilename + ' from dexer paths.');
}
}, builder);
data.args[1] = dexerOptions.concat(fixedDexerPaths);
}
callback();
}
});
};

/**
Expand Down
76 changes: 76 additions & 0 deletions android/cli/lib/base-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,30 @@ var i18nLib = appc.i18n(__dirname);
var __ = i18nLib.__;
var xml = appc.xml;

/**
* The base Android builder that includes common functionality that is used
* in both app and module builds.
*/
function AndroidBaseBuilder() {
Builder.apply(this, arguments);

this.androidLibraries = [];
this.dependencyMap = JSON.parse(fs.readFileSync(path.join(this.platformPath, 'dependency.json')));
}

util.inherits(AndroidBaseBuilder, Builder);

/**
* Utility function to merge the contents of XML files.
*
* If the destination file does not exists, the source file will simply
* be copied over. If both source and destination already exists AND the source
* document contains Android resources, the files will be merged. Otherwise the
* destination file will be overwritten.
*
* @param {string|Document} srcOrDoc Path to source XML file or already parsed Document object
* @param {string} dest Path of the destination XML file
*/
AndroidBaseBuilder.prototype.writeXmlFile = function writeXmlFile(srcOrDoc, dest) {
var filename = path.basename(dest),
destExists = fs.existsSync(dest),
Expand Down Expand Up @@ -101,4 +117,64 @@ AndroidBaseBuilder.prototype.writeXmlFile = function writeXmlFile(srcOrDoc, dest
fs.writeFileSync(dest, '<?xml version="1.0" encoding="UTF-8"?>\n' + dom.documentElement.toString());
};

/**
* Checks wether an Android Library with the given package name is available.
*
* @param {string} packageName Package name of the Android Library to search for
* @return {Boolean} True if the Android Library is available, false if not
*/
AndroidBaseBuilder.prototype.hasAndroidLibrary = function hasAndroidLibrary(packageName) {
return this.androidLibraries.some(function(libraryInfo) {
return libraryInfo.packageName === packageName;
});
};

/**
* Checks if one of our bundled Android Support Libraries (.jar) is also available
* as an Android Library (.aar) provided by the user.
*
* This is used during the build prodess to allow users to replace any of our
* bundled Android Support Libraries with one of their own choosing. Currently
* supported Android Support Library versions are 24.2.0 - 25.x.
*
* To find out which .jar library can be replaces by which Android Library,
* we depend on a hardcoded list of Android Library package names and the bundled
* library filenames they can replace. This list is manually taken from
* android/dependency.json and needs to be maintained if anything changes there.
*
* @param {string} libraryPathAndFilename Path and filename to the .jar file to check
* @type {Boolean} True if the given library is available as an Android Library, false if not
*/
AndroidBaseBuilder.prototype.isExternalAndroidLibraryAvailable = function isExternalAndroidLibraryAvailable(libraryPathAndFilename) {
var replaceableAndroidLibraries = {
'android.support.graphics.drawable': ['android-support-vector-drawable.jar'],
'android.support.graphics.drawable.animated': ['android-support-animated-vector-drawable.jar'],
'android.support.v4': ['android-support-v4.jar'],
'android.support.compat': ['android-support-compat.jar'],
'android.support.coreui': ['android-support-core-ui.jar'],
'android.support.coreutils': ['android-support-core-utils.jar'],
'android.support.design': ['android-support-design.jar'],
'android.support.fragment': ['android-support-fragment.jar'],
'android.support.mediacompat': ['android-support-media-compat.jar'],
'android.support.transition': ['android-support-transition.jar'],
'android.support.v7.appcompat': ['android-support-v7-appcompat.jar'],
'android.support.v7.cardview': ['android-support-v7-cardview.jar'],
'android.support.v7.recyclerview': ['android-support-v7-recyclerview.jar']
};
return this.androidLibraries.some(function(libraryInfo) {
if (!replaceableAndroidLibraries[libraryInfo.packageName]) {
return false;
}

var libraryFilename = path.basename(libraryPathAndFilename);
var shouldExcludeLibrary = replaceableAndroidLibraries[libraryInfo.packageName].indexOf(libraryFilename) !== -1;
if (shouldExcludeLibrary) {
this.logger.trace(__('Android library %s (%s) available, marking %s to be excluded.', libraryInfo.task.aarPathAndFilename, libraryInfo.packageName.cyan, libraryPathAndFilename.cyan));
return true;
}

return false;
}, this);
};

module.exports = AndroidBaseBuilder;

0 comments on commit 5b4f617

Please sign in to comment.