Android 使用DexClassLoader來運行其他apk中的方法
來源:程序員人生 發(fā)布時間:2014-11-21 08:55:28 閱讀次數(shù):2342次
Android中apk文件里的dex文件是對java編譯出來的.class文件進行重新打包,固然在打包之前會利用自己的協(xié)議做1些數(shù)據(jù)處理,例如優(yōu)化函數(shù)表和變量表。在java程序中是使用classloader來加載這些編譯生成的.class文件,但是在android程序中是通過DexClassLoader來裝載這些文件的.這里我們就能夠通過DexClassLoader在程序A里面動態(tài)裝載程序B中的類,并且來調(diào)用B程序中的方法.
1.首先先建立1個普通的Android工程,在這個工程中定義1個叫做plugin的類,類中實現(xiàn)1個簡單的方法,以下所示:
<span style="font-size:14px;">public class PluginClass {
private static String TAG = PluginClass.class.getSimpleName();
public PluginClass(){
Log.i(TAG, "initialized");
}
public void invoke(String s){
Log.i(TAG, s);
}
}</span>
2.將這個Android工程運行到安卓裝備當中去
3.再重新建立1個Android工程,其中定義1個叫做host的類,在這個類中實現(xiàn)DexClassLoader動態(tài)加載第1個工程中的plugin類,以下所示:
<span style="font-size:14px;">public class HostClass {
private static String TAG = HostClass.class.getSimpleName();
private Context mContext = null;
public HostClass(Context contect){
mContext = contect;
}
public void useDexClassLoader(){
Intent intent = new Intent();
intent.setPackage("com.example.plugin");
PackageManager pm = mContext.getPackageManager();
final List<ResolveInfo> plugins = pm.queryIntentActivities(intent,0);
if(plugins.size() <= 0){
Log.i(TAG, "resolve info size is:" + plugins.size());
return;
}
ResolveInfo resolveInfo = plugins.get(0);
ActivityInfo activityInfo = resolveInfo.activityInfo;
String div = System.getProperty("path.separator");
String packageName = activityInfo.packageName;
String dexPath = activityInfo.applicationInfo.sourceDir;
//目標類所在的apk或jar的路徑,class loader會通過這個路徑來加載目標類文件
String dexOutputDir = mContext.getApplicationInfo().dataDir;
//由于dex文件是包括在apk或jar文件中的,所以在加載class之前就需要先將dex文件解壓出來,dexOutputDir為解壓路徑
String libPath = activityInfo.applicationInfo.nativeLibraryDir;
//目標類可能使用的c或c++的庫文件的寄存路徑
Log.i(TAG, "div:" + div + " " +
"packageName:" + packageName + " " +
"dexPath:" + dexPath + " " +
"dexOutputDir:" + dexOutputDir + " " +
"libPath:" + libPath);
DexClassLoader dcLoader = new DexClassLoader(dexPath,dexOutputDir,libPath,this.getClass().getClassLoader());
try {
Class<?> clazz = dcLoader.loadClass(packageName + ".PluginClass");
Object obj = clazz.newInstance();
Class[] param = new Class[1];
param[0] = String.class;
Method action = clazz.getMethod("invoke", param);
action.invoke(obj, "test this function");
} catch (ClassNotFoundException e) {
Log.i(TAG, "ClassNotFoundException");
} catch (InstantiationException e) {
Log.i(TAG, "InstantiationException");
} catch (IllegalAccessException e) {
Log.i(TAG, "IllegalAccessException");
} catch (NoSuchMethodException e) {
Log.i(TAG, "NoSuchMethodException");
} catch (IllegalArgumentException e) {
Log.i(TAG, "IllegalArgumentException");
} catch (InvocationTargetException e) {
Log.i(TAG, "InvocationTargetException");
}
}
}</span>
4.運行第2個工程以后查看log就會發(fā)現(xiàn)host通過DexClassLoader加載了pluginclass類,并成功調(diào)用了plugin中的方法
<span style="font-size:14px;">I/HostClass( 8341): div:: packageName:com.example.plugin dexPath:/data/app/com.example.plugin⑴.apk dexOutputDir:/data/data/com.example.host libPath:/data/app-lib/com.example.plugin⑴
D/dalvikvm( 8341): DexOpt: --- BEGIN 'com.example.plugin⑴.apk' (bootstrap=0) ---
D/dalvikvm( 8341): DexOpt: --- END 'com.example.plugin⑴.apk' (success) ---
D/dalvikvm( 8341): DEX prep '/data/app/com.example.plugin⑴.apk': unzip in 39ms, rewrite 723ms
I/PluginClass( 8341): initialized
I/PluginClass( 8341): test this function
D/libEGL ( 8341): loaded /system/lib/egl/libEGL_mali.so
D/libEGL ( 8341): loaded /system/lib/egl/libGLESv1_CM_mali.so
D/libEGL ( 8341): loaded /system/lib/egl/libGLESv2_mali.so
D/OpenGLRenderer( 8341): Enabling debug mode 0
I/HostClass( 8341): div:: packageName:com.example.plugin dexPath:/data/app/com.example.plugin⑴.apk dexOutputDir:/data/data/com.example.host libPath:/data/app-lib/com.example.plugin⑴
I/PluginClass( 8341): initialized
I/PluginClass( 8341): test this function</span>
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學習有所幫助,可以手機掃描二維碼進行捐贈