因为项目需要,分析了DexClassLoader相关的源码实现,为了看看实际效果,参考网上例子,做了一个apk,使用DexClassLoader来做类加载器。
参考文章:
http://blog.csdn.net/u013478336/article/details/50734108
1,制作一个被调用的dex文件
1.1 按照建helloworldapk的方法新建一个android项目就行,包名或在建立的时候按下面代码来建,或者在已有项目新建下面的包名
文件1,
IShowToast.java
package com.example.testdextoast;
import android.content.Context;
public interface IShowToast {
public int showToast(Context context);
}
文件2,
IShowToast.java
package com.example.testdextoast;
import android.content.Context;
import android.widget.Toast;
public class ShowToastImpl implements IShowToast {
@Override
public int showToast(Context context) {
Toast.makeText(context, "我来自另一个dex文件", Toast.LENGTH_LONG).show();
return 100;
}
}
1.2 对IShowToast.java文件,在Eclipse工程右键->Export->Java->Jar file,导出一个jar包,如命名origin.jar,
1.3 在android的SDK目录下,找到类似目录Android\sdk\build-tools\22.0.1, 找到dx.bat
1.4 在命令行下,进入dx所在目录,将jar文件拷到该目录下,执行dx --dex --output=output.jar origin.jar,得到内含class.dex的output.jar
因为使用level24的工具报错,所以暂使用22.0.1的
C:\Users\sssAppData\Local\Android\sdk\build-tools\24.0.0>dx --dex --output=out
put.jar origin.jar
Exception in thread "main" java.lang.UnsupportedClassVersionError: com/android/d
x/command/Main : Unsupported major.minor version 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:14
2)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at java.lang.ClassLoader.loadClass(ClassLoader.java:412)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482)
1.5 将output.jar文件放到SD卡下adb push output.jar sdcard/output.jar
2. 制作一个主控apk,来动态加载dex
2.1 也是按照建helloworldapk的方法新建一个android项目就行
2.2 主代码如下
package com.example.testshowtoastdex;
import android.view.Menu;
import android.view.MenuItem;
import java.io.File;
import com.example.testdextoast.IShowToast;
import dalvik.system.DexClassLoader;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
File dexOutputDir = getDir("dex1", 0);
String dexPath = Environment.getExternalStorageDirectory().toString() + File.separator + "output.jar";
Log.d("TEST111", "showToast"+dexPath);
DexClassLoader loader = new DexClassLoader(dexPath,
dexOutputDir.getAbsolutePath(),
null, getClassLoader());
try {
Class clz = loader.loadClass("com.example.testdextoast.ShowToastImpl");
IShowToast impl = (IShowToast) clz.newInstance();
impl.showToast(this);
Log.d("TEST111", "showToast");
} catch (Exception e) {
Log.d("TEST111", "error happened", e);
}
}
}
2.3 因为要访问SD卡,所以要在manifest加权限<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testshowtoastdex"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
如果没加权限,会出现如下报错
09-20 23:48:26.599: D/TEST111(4440): Suppressed: java.lang.ClassNotFoundException: Didn't find class "com.example.testdextoast.ShowToastImpl" on path: DexPathList[[zip file "/data/app/com.example.testshowtoastdex-1/base.apk"],nativeLibraryDirectories=[/data/app/com.example.testshowtoastdex-1/lib/arm, /vendor/lib, /system/lib]]
09-20 23:48:26.599: D/TEST111(4440): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
09-20 23:48:26.599: D/TEST111(4440): at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
09-20 23:48:26.599: D/TEST111(4440): at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
2.3 按IShowToast.java的原来的路径,将它复制到新工程,不要改变文件
编译、安装到手机,就能看到toast。