Created
February 23, 2015 19:06
-
-
Save sr105/504aaf344030076f40c0 to your computer and use it in GitHub Desktop.
Dynamic Library Loader for Android
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.rdm.neocastapp; | |
import android.content.ContextWrapper; | |
import android.util.Log; | |
import java.io.File; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import dalvik.system.DexClassLoader; | |
public class DynamicLibLoader { | |
protected final File mDexDir; | |
public DynamicLibLoader(ContextWrapper contextWrapper) { | |
mDexDir = contextWrapper.getDir("dex", 0); | |
} | |
public DynamicLibLoader(String dexCacheDir) { | |
mDexDir = new File(dexCacheDir); | |
} | |
public static Class<?>[] toParameterTypes(Class<?>... parameterTypes) { | |
return parameterTypes; | |
} | |
public static Object[] toArgs(Object... args) { | |
return args; | |
} | |
// Run method "main(String[])" in fullClassName | |
// found in the dexed jar file, libraryFileName, | |
// with no command line arguments | |
public void runMain(String libraryFileName, | |
String fullClassName, | |
String... args) { | |
final Class<?>[] parameterTypes = toParameterTypes(String[].class); | |
//final Object[] args = toArgs(new String[0]); | |
runMethod(libraryFileName, fullClassName, "main", parameterTypes, args); | |
} | |
// Find methodName(parameterTypes) in fullClassName inside | |
// the dexed jar file, libraryFileName and run it with args | |
// - parameterTypes and args can be null | |
// - use the toParameterTypes() and toArgs() methods for convenience | |
public Object runMethod(String libraryFileName, | |
String fullClassName, | |
String methodName, | |
Class<?>[] parameterTypes, | |
Object[] args) throws IllegalArgumentException { | |
try { | |
@SuppressWarnings("unchecked") | |
final Class<Object> classToLoad = (Class<Object>) getClass(libraryFileName, fullClassName); | |
final Object instance = classToLoad.newInstance(); | |
final Method main = classToLoad.getMethod(methodName, parameterTypes); | |
//final String[] args = new String[0]; | |
//main.invoke(instance, (Object) args); | |
return main.invoke(instance, args); | |
} catch (InstantiationException | IllegalAccessException | | |
NoSuchMethodException | InvocationTargetException e) { | |
throw new IllegalArgumentException(e); | |
} | |
} | |
// Find methodName(parameterTypes) in fullClassName inside | |
// the dexed jar file, libraryFileName and run it with args | |
// - parameterTypes and args can be null | |
// - use the toParameterTypes() and toArgs() methods for convenience | |
public Object newInstance(String libraryFileName, | |
String fullClassName) throws IllegalArgumentException { | |
try { | |
@SuppressWarnings("unchecked") | |
final Class<Object> classToLoad = (Class<Object>) getClass(libraryFileName, fullClassName); | |
return classToLoad.newInstance(); | |
} catch (InstantiationException | IllegalAccessException e) { | |
throw new IllegalArgumentException(e); | |
} | |
} | |
public final Class<?> getClass(String libraryFileName, | |
String fullClassName) throws IllegalArgumentException { | |
try { | |
deleteCachedDexFiles(libraryFileName); | |
Log.i("DLL", "exists? " + new File(libraryFileName).exists()); | |
final DexClassLoader classLoader = new DexClassLoader( | |
libraryFileName, mDexDir.getAbsolutePath(), null, | |
this.getClass().getClassLoader()); | |
return classLoader.loadClass(fullClassName); | |
} catch (ClassNotFoundException e) { | |
throw new IllegalArgumentException(e); | |
} | |
} | |
// Note: About re-loading a jar file in the same process' lifetime | |
// | |
// If we try to load the same jar file by name, | |
// but not by content (different file, same name) | |
// as previously loaded in this current process, | |
// this process will crash with a SIGBUS error. | |
// While setIntentRedelivery(true) above *will* | |
// cause Android to restart us and re-send the | |
// current Intent, this is not very graceful. | |
// Instead, it seems that if you clear out the | |
// dex cache, all is good. | |
// | |
// TODO: Only delete the cache file for the library we're loading | |
void deleteCachedDexFiles(String libraryFileName) { | |
String libName = new File(libraryFileName).getName(); | |
if (libName.endsWith(".apk") || libName.endsWith(".jar")) | |
libName = libName.substring(0, libName.length() - 4); | |
Log.i("DynamicLibLoader", "deleteCacheDexFiles(" + libName + ") from " + mDexDir.getAbsolutePath()); | |
for (File f : mDexDir.listFiles()) { | |
Log.i("DLL", "Dex File: " + f.getName()); | |
// only delete the dex file matching the library file name? | |
if (f.isFile() && f.getName() | |
.endsWith(".dex")) { | |
f.delete(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment