Create a gist now

Instantly share code, notes, and snippets.

Embed
What would you like to do?
// The following is in addition to the build.gradle for a normal application, not a library
afterEvaluate { project ->
android.applicationVariants.each { variant ->
File outputFile = new File(variant.mergeAssets.outputDir, "dexter.dex")
def dexterExternalLibraries = task "dexter${variant.name}ExternalLibraries" {
dependsOn variant.mergeAssets
inputs.files configurations.provided
outputs.file outputFile
doLast {
def builder = getPlugins().findPlugin('android').getAndroidBuilder(variant.mergeAssets.variant)
builder.convertByteCode([], configurations.provided, null, outputFile.absolutePath, variant.dex.dexOptions, true)
}
}
variant.processResources.dependsOn.add(dexterExternalLibraries)
variant.javaCompile.classpath += configurations.provided
}
}
configurations {
provided
}
dependencies {
provided 'group:module:version'
}
public class Dexter {
private static String optimizedDirectory = "optimized";
private static String workDirectory = "working";
public static void loadFromAssets(Context context, String fileName) throws Exception {
File optimized = new File(optimizedDirectory);
optimized = context.getDir(optimized.toString(), Context.MODE_PRIVATE);
optimized = new File(optimized, fileName);
optimized.mkdir();
File work = context.getDir(workDirectory, Context.MODE_PRIVATE);
work = new File(work, fileName);
InputStream inputDex = context.getAssets().open(fileName);
FileOutputStream outputDex = new FileOutputStream(work);
byte[] buf = new byte[0x1000];
while (true) {
int r = inputDex.read(buf);
if (r == -1)
break;
outputDex.write(buf, 0, r);
}
outputDex.close();
inputDex.close();
ClassLoader localClassLoader = Dexter.class.getClassLoader();
BaseDexClassLoader classLoader = new DexClassLoader(work.getAbsolutePath(), optimized.getAbsolutePath(), null, localClassLoader);
if(localClassLoader instanceof BaseDexClassLoader) {
Object existing = getDexClassLoaderElements((BaseDexClassLoader) localClassLoader);
Object incoming = getDexClassLoaderElements(classLoader);
Object joined = joinArrays(incoming, existing);
setDexClassLoaderElements((BaseDexClassLoader) localClassLoader, joined);
} else {
throw new UnsupportedOperationException("Class loader not supported");
}
}
private static void setDexClassLoaderElements(BaseDexClassLoader classLoader, Object elements) throws Exception {
Class<BaseDexClassLoader> dexClassLoaderClass = BaseDexClassLoader.class;
Field pathListField = dexClassLoaderClass.getDeclaredField("pathList");
pathListField.setAccessible(true);
Object pathList = pathListField.get(classLoader);
Field dexElementsField = pathList.getClass().getDeclaredField("dexElements");
dexElementsField.setAccessible(true);
dexElementsField.set(pathList, elements);
}
private static Object getDexClassLoaderElements(BaseDexClassLoader classLoader) throws Exception {
Class<BaseDexClassLoader> dexClassLoaderClass = BaseDexClassLoader.class;
Field pathListField = dexClassLoaderClass.getDeclaredField("pathList");
pathListField.setAccessible(true);
Object pathList = pathListField.get(classLoader);
Field dexElementsField = pathList.getClass().getDeclaredField("dexElements");
dexElementsField.setAccessible(true);
Object dexElements = dexElementsField.get(pathList);
return dexElements;
}
private static Object joinArrays(Object o1, Object o2) {
Class<?> o1Type = o1.getClass().getComponentType();
Class<?> o2Type = o2.getClass().getComponentType();
if(o1Type != o2Type)
throw new IllegalArgumentException();
int o1Size = Array.getLength(o1);
int o2Size = Array.getLength(o2);
Object array = Array.newInstance(o1Type, o1Size + o2Size);
int offset = 0, i;
for(i = 0; i < o1Size; i++, offset++)
Array.set(array, offset, Array.get(o1, i));
for(i = 0; i < o2Size; i++, offset++)
Array.set(array, offset, Array.get(o2, i));
return array;
}
}
public class MainActivity extends Activity {
private static String[] DEX_FILES = {"dexter.dex"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
for (String dex : DEX_FILES)
Dexter.loadFromAssets(this, dex);
} catch (Exception e) {
throw new RuntimeException("Unable to load DEX files", e);
}
try {
startActivity(new Intent(MainActivity.this, getClassLoader().loadClass("the real activity")));
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unable to start application", e);
}
}
}
@hamen

This comment has been minimized.

Show comment
Hide comment
@hamen

hamen May 12, 2014

I'm getting on Gradle Sync:

Unresolved dependencies
Error:group:module:version (double-click here to find usages.)

Any help?

hamen commented May 12, 2014

I'm getting on Gradle Sync:

Unresolved dependencies
Error:group:module:version (double-click here to find usages.)

Any help?

@danielgoncharov

This comment has been minimized.

Show comment
Hide comment
@danielgoncharov

danielgoncharov May 19, 2014

Hi hamen,
You should put inside your own dependency for example
provided 'com.google.code.gson:gson:2.2.4'

Hi hamen,
You should put inside your own dependency for example
provided 'com.google.code.gson:gson:2.2.4'

@creativepsyco

This comment has been minimized.

Show comment
Hide comment
@creativepsyco

creativepsyco May 21, 2014

Does this approach work for library projects?

Does this approach work for library projects?

@hamen

This comment has been minimized.

Show comment
Hide comment
@hamen

hamen Jul 2, 2014

Unfortunately no luck until now. I'm getting

"Could not find property 'variant' on task"

Any idea?

hamen commented Jul 2, 2014

Unfortunately no luck until now. I'm getting

"Could not find property 'variant' on task"

Any idea?

@VishalNehra

This comment has been minimized.

Show comment
Hide comment
@VishalNehra

VishalNehra Nov 17, 2014

Same here...

Same here...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment