Skip to content

Commit

Permalink
[TIMOB-18082] Android: Enable --multi-dex for android builds (#8095)
Browse files Browse the repository at this point in the history
* [TIMOB-18082] Android: Enable --multi-dex for android builds

* Add android-support-multidex JAR

* Make the directory to hold dex files during build

* Fix adding dex files to APK

* Add android-support-multidex.jar to dependency list

* Hack gathering the main dex class listing to feed to dexer. Can't use the build-tools mainDexClasses script (because it's a bash script, and because it doesn't handle args with spaces correctly). So we need to use proguard and MainDexListBuilder class in dx.jar ourselves - since it looks liek gradle now does it for you?

* Don't do intermediate main dex class listing steps on API level 21+
  • Loading branch information
sgtcoolguy committed Jul 20, 2016
1 parent b6e2cbe commit 550e6a5
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 11 deletions.
103 changes: 93 additions & 10 deletions android/cli/commands/_build.js
Original file line number Diff line number Diff line change
Expand Up @@ -1790,7 +1790,7 @@ AndroidBuilder.prototype.initialize = function initialize(next) {
this.buildBinAssetsDir = path.join(this.buildBinDir, 'assets');
this.buildBinAssetsResourcesDir = path.join(this.buildBinAssetsDir, 'Resources');
this.buildBinClassesDir = path.join(this.buildBinDir, 'classes');
this.buildBinClassesDex = path.join(this.buildBinDir, 'classes.dex');
this.buildBinClassesDex = path.join(this.buildBinDir, 'dexfiles');
this.buildGenDir = path.join(this.buildDir, 'gen');
this.buildGenAppIdDir = path.join(this.buildGenDir, this.appid.split('.').join(path.sep));
this.buildResDir = path.join(this.buildDir, 'res');
Expand Down Expand Up @@ -3915,16 +3915,21 @@ AndroidBuilder.prototype.runDexer = function runDexer(next) {
done();
}.bind(this));
}),
injars = [
this.buildBinClassesDir,
path.join(this.platformPath, 'lib', 'titanium-verify.jar')
].concat(Object.keys(this.moduleJars)).concat(Object.keys(this.jarLibraries)),
dexArgs = [
'-Xmx' + this.dxMaxMemory,
'-XX:-UseGCOverheadLimit',
'-Djava.ext.dirs=' + this.androidInfo.sdk.platformTools.path,
'-jar', this.androidInfo.sdk.dx,
'--dex',
'--dex', '--multi-dex',
'--output=' + this.buildBinClassesDex,
this.buildBinClassesDir,
path.join(this.platformPath, 'lib', 'titanium-verify.jar')
].concat(Object.keys(this.moduleJars)).concat(Object.keys(this.jarLibraries));
],
shrinkedAndroid = path.join(path.dirname(this.androidInfo.sdk.dx), 'shrinkedAndroid.jar'),
baserules = path.join(path.dirname(this.androidInfo.sdk.dx), '..', 'mainDexClasses.rules'),
outjar = path.join(this.buildDir, 'mainDexClasses.jar');

// inserts the -javaagent arg earlier on in the dexArgs to allow for proper dexing if
// dexAgent is set in the module's timodule.xml
Expand All @@ -3933,14 +3938,84 @@ AndroidBuilder.prototype.runDexer = function runDexer(next) {
}

if (this.allowDebugging && this.debugPort) {
dexArgs.push(path.join(this.platformPath, 'lib', 'titanium-debug.jar'));
injars.push(path.join(this.platformPath, 'lib', 'titanium-debug.jar'));
}

if (this.allowProfiling && this.profilerPort) {
dexArgs.push(path.join(this.platformPath, 'lib', 'titanium-profiler.jar'));
injars.push(path.join(this.platformPath, 'lib', 'titanium-profiler.jar'));
}

dexerHook(this.jdkInfo.executables.java, dexArgs, {}, next);
// nuke and create the folder holding all the classes*.dex files
if (fs.existsSync(this.buildBinClassesDex)) {
wrench.rmdirSyncRecursive(this.buildBinClassesDex);
}
wrench.mkdirSyncRecursive(this.buildBinClassesDex);

// Wipe existing outjar
fs.existsSync(outjar) && fs.unlinkSync(outjar);

this.logger.error(JSON.stringify(this.androidTargetSDK));

// We need to hack multidex for APi level < 21 to generate the list of classes that *need* to go into the first dex file
// We skip these intermediate steps if 21+ and eventually just run dexer
async.series([
// Run: java -jar $this.androidInfo.sdk.proguard -injars "${@}" -dontwarn -forceprocessing -outjars ${tmpOut} -libraryjars "${shrinkedAndroidJar}" -dontoptimize -dontobfuscate -dontpreverify -include "${baserules}"
function (done) {
// 'api-level' and 'sdk' properties both seem to hold apiLevel
if (this.androidTargetSDK.sdk >= 21) {
return done();
}

appc.subprocess.run(this.jdkInfo.executables.java, [
'-jar',
this.androidInfo.sdk.proguard,
'-injars', injars.join(':'),
'-dontwarn', '-forceprocessing',
'-outjars', outjar,
'-libraryjars', shrinkedAndroid,
'-dontoptimize', '-dontobfuscate', '-dontpreverify', '-include',
baserules
], {}, function (code, out, err) {
if (code) {
this.logger.error(__('Failed to run dexer:'));
this.logger.error();
err.trim().split('\n').forEach(this.logger.error);
this.logger.log();
process.exit(1);
}
done();
}.bind(this));
}.bind(this),
// Run: java -cp $this.androidInfo.sdk.dx com.android.multidex.MainDexListBuilder "$outjar" "$injars"
function (done) {
// 'api-level' and 'sdk' properties both seem to hold apiLevel
if (this.androidTargetSDK.sdk >= 21) {
return done();
}

appc.subprocess.run(this.jdkInfo.executables.java, ['-cp', this.androidInfo.sdk.dx, 'com.android.multidex.MainDexListBuilder', outjar, injars.join(':')], {}, function (code, out, err) {
var mainDexClassesList = path.join(this.buildDir, 'main-dex-classes.txt');
if (code) {
this.logger.error(__('Failed to run dexer:'));
this.logger.error();
err.trim().split('\n').forEach(this.logger.error);
this.logger.log();
process.exit(1);
}
// Record output to a file like main-dex-classes.txt
fs.writeFileSync(mainDexClassesList, out);
// Pass that file into dex, like so:
dexArgs.push('--main-dex-list');
dexArgs.push(mainDexClassesList);

done();
}.bind(this));
}.bind(this),
function (done) {
dexArgs = dexArgs.concat(injars);
dexerHook(this.jdkInfo.executables.java, dexArgs, {}, done);
}.bind(this)
], next);
};

AndroidBuilder.prototype.createUnsignedApk = function createUnsignedApk(next) {
Expand All @@ -3951,6 +4026,7 @@ AndroidBuilder.prototype.createUnsignedApk = function createUnsignedApk(next) {
jsonRegExp = /\.json$/,
javaRegExp = /\.java$/,
classRegExp = /\.class$/,
dexRegExp = /^classes(\d+)?\.dex$/,
soRegExp = /\.so$/,
trailingSlashRegExp = /\/$/,
nativeLibs = {},
Expand Down Expand Up @@ -4001,8 +4077,15 @@ AndroidBuilder.prototype.createUnsignedApk = function createUnsignedApk(next) {
}, this);
}, this);

this.logger.debug(__('Adding %s', 'classes.dex'.cyan));
dest.append(fs.createReadStream(this.buildBinClassesDex), { name: 'classes.dex' });
// Add dex files
this.logger.info(__('Processing %s', this.buildBinClassesDex.cyan));
fs.readdirSync(this.buildBinClassesDex).forEach(function (name) {
var file = path.join(this.buildBinClassesDex, name);
if (dexRegExp.test(name)) {
this.logger.debug(__('Adding %s', name.cyan));
dest.append(fs.createReadStream(file), { name: name });
}
}, this);

this.logger.info(__('Processing %s', this.buildSrcDir.cyan));
(function copyDir(dir, base) {
Expand Down
2 changes: 1 addition & 1 deletion android/dependency.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"required": ["analytics","android","app","ui","locale","network"],
"libraries":
{
"android":["jaxen-1.1.1.jar","ti-commons-codec-1.3.jar","kroll-common.jar","titanium.jar","filesystem.jar"],
"android":["jaxen-1.1.1.jar","ti-commons-codec-1.3.jar","kroll-common.jar","titanium.jar","filesystem.jar","android-support-multidex.jar"],
"xml":["jaxen-1.1.1.jar"],
"ui":["nineoldandroids-appc-2.4.0.jar"],
"appcompat":["android-support-v4.jar", "android-support-v7-appcompat.jar"],
Expand Down
1 change: 1 addition & 0 deletions android/titanium/.classpath
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
<classpathentry combineaccessrules="false" kind="src" path="/kroll-common"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry exported="true" kind="lib" path="lib/aps-analytics.jar"/>
<classpathentry exported="true" kind="lib" path="lib/android-support-multidex.jar"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>
Binary file added android/titanium/lib/android-support-multidex.jar
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import android.content.IntentFilter;
import android.os.Build;
import android.os.Looper;
import android.support.multidex.MultiDex;
import android.util.DisplayMetrics;
import android.view.accessibility.AccessibilityManager;

Expand Down Expand Up @@ -352,6 +353,12 @@ public void loadAppProperties() {
}
}

@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}

@Override
public void onCreate()
{
Expand Down

0 comments on commit 550e6a5

Please sign in to comment.