/**
*
*/
package com.example.dex;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import dalvik.system.DexClassLoader;
import android.app.Application;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
/**
* @author simsun
*
*/
public class MyApplication extends Application {
private static final String TAG = "MyApplication";
private static final String SECONDARY_DEX_NAME = "secondary_dex.jar";
private static final int BUF_SIZE = 8 * 1024;
private File dexInternalStoragePath;
public ClassLoader class_loader;
static {
Log.e(TAG, "load MyApplication class");
}
@Override
public void onCreate() {
load_external_dex(SECONDARY_DEX_NAME);
super.onCreate();
}
public void load_external_dex(String file_name) {
// Before the secondary dex file can be processed by the DexClassLoader,
// it has to be first copied from asset resource to a storage location.
dexInternalStoragePath = new File(getDir("dex", Context.MODE_PRIVATE),
SECONDARY_DEX_NAME);
if (!dexInternalStoragePath.exists()) {
// Perform the file copying in an AsyncTask.
(new PrepareDexTask()).execute(dexInternalStoragePath);
} else {
Log.d(TAG, "[onCreate]dexInternalStoragePath:" + dexInternalStoragePath.getAbsolutePath());
changeSystemClassLoader(this);
}
}
//FIXME: load duplicated
private void changeSystemClassLoader(Application app) {
try {
Context mBase = new Smith<Context>(app, "mBase").get();
Object package_info = new Smith<Object>(mBase, "mPackageInfo").get();
Smith<ClassLoader> package_class_loader = new Smith<ClassLoader>(package_info, "mClassLoader");
ClassLoader with_second_dex_dcl = buildDexClassLoader(dexInternalStoragePath, package_class_loader.get());
package_class_loader.set(with_second_dex_dcl);
class_loader = with_second_dex_dcl;
try {
Class<?> clazz = with_second_dex_dcl.loadClass("com.example.dex.lib.LibraryProvider");
if (clazz != null)
Log.d(TAG, "this is " + clazz.getName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private DexClassLoader buildDexClassLoader(File dex_file, ClassLoader parent) {
File optimized_dex_path = getDir("optDex", Context.MODE_PRIVATE);
optimized_dex_path.mkdirs();
DexClassLoader dcl = new DexClassLoader(dex_file.getAbsolutePath(), optimized_dex_path.getAbsolutePath(), null, parent);
return dcl;
}
private class PrepareDexTask extends AsyncTask<File, Void, File> {
@Override
protected void onCancelled() {
super.onCancelled();
}
@Override
protected void onPostExecute(File dexInternalStoragePath) {
super.onPostExecute(dexInternalStoragePath);
Log.d(TAG, "[AsyncTask]dexInternalStoragePath:" + dexInternalStoragePath.getAbsolutePath());
changeSystemClassLoader(MyApplication.this);
}
@Override
protected File doInBackground(File... dexInternalStoragePaths) {
prepareDex(dexInternalStoragePaths[0]);
return dexInternalStoragePaths[0];
}
}
// File I/O code to copy the secondary dex file from asset resource to internal storage.
private boolean prepareDex(File dexInternalStoragePath) {
BufferedInputStream bis = null;
OutputStream dexWriter = null;
try {
bis = new BufferedInputStream(getAssets().open(SECONDARY_DEX_NAME));
dexWriter = new BufferedOutputStream(new FileOutputStream(dexInternalStoragePath));
byte[] buf = new byte[BUF_SIZE];
int len;
while((len = bis.read(buf, 0, BUF_SIZE)) > 0) {
dexWriter.write(buf, 0, len);
}
dexWriter.close();
bis.close();
return true;
} catch (IOException e) {
if (dexWriter != null) {
try {
dexWriter.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
if (bis != null) {
try {
bis.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
return false;
}
}
}