1、写一个java类,生成Jar包
2、初始Jar的转换
3、创建一个android工程
4、复制Jar包
5、反射获取属性和方法
5、完整Demo
6、补充
摘要:在Android中可以动态加载,但无法像Java中那样方便动态加载jar
原因:Android的虚拟机(Dalvik VM)是不认识Java打出jar的byte code,需要通过dx工具来优化转换成Dalvik byte code才行。这一点在咱们Android项目打包的apk中可以看出:引入其他Jar的内容都被打包进了classes.dex。所以无法像java对jar文件直接进行的反射。所以要用android sdk 自带的dx.bat (位于\adt-bundle-windows-x86-20131030\sdk\build-tools下)进行 jar-->dex-->jar的过程。
步骤说明:
1.写一个java类,生成Jar包
publicclass Hello{
publicstatic String Hello(Strings) {
return s;
}
public String sayHello(){
return"HelloWorld";
}
}
使用Fatjar工具进行对java类生成jar文件
2.初始Jar的转换
对于assets目录下一般存放的是大文件,它在随apk打包时,并不会被压缩。我们可以将我们要
转化后的jar(经历过jar-->dex-->jar)放在该目录下。
以我们的多屏互动jar包为例:下面是完成jar-->dex-->jar的过程
命令:dx --dex --output = utils-r1204.jar utils.jar
Output输出为一个名叫“utils-r1204.jar”的文件,名字可以随便起,把这个输出jar文件放到工程的assets目录下。
3.创建一个android工程
在activity中的oncreate方法中执行如下操作:
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reflect);
copyFileToInternalStorage ("utils-r1204.jar");
jarToReflect();
}
4.复制Jar包
对输出的utils-r1204.jar进入复制到internal storage(就是data/data/当前工程/files目录下)中去,主要是为了方便反射,就好像我们的db文件通常也要经过这种方式到internal storage中,(另外如果有SD卡,可以直接把utils-r1204.jar拷贝到SD卡,方法是一样的)
public void copyFileToInternalStorage(final String filename) {
InputStream is = null;
FileOutputStream fos = null;
File file = new File(getApplicationContext().getFilesDir(), filename);
//getFileDir()目录就是data/data/当前工程/files 目录
if (file.exists()) {
System.out.println("file is exist! cannot to copy again");
} else {
try {
is = getAssets().open(filename);
fos = new FileOutputStream(file);
int len = 0;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.反射获取属性和方法
@SuppressLint("NewApi")
publicvoid jarToReflect(){
Stringspath=getFilesDir()+"/utils-r1204.jar";
final File path = new File(spath);
DexClassLoader dexloader = new DexClassLoader(
path.getAbsolutePath(),
getFilesDir().toString(),
null,
getClassLoader());
Class> libClazz = null;
try {
// Load the libraryclass from the class loader.
libClazz= dexloader.loadClass("com.example.demo.Hello");
Methodsm=libClazz.getMethod("startHello", new Class[]{String.class});
Stringsinvoke = (String) sm.invoke(libClazz, new Object[]{"aaaa"});
System.out.println("sinvoke ="+sinvoke);
Constructor[]constructors = libClazz.getDeclaredConstructors();
AccessibleObject.setAccessible(constructors,true);
for (Constructor con :constructors) {
if (con.isAccessible()){
ObjectclassObject = con.newInstance();
Methodnsm = libClazz.getMethod("sayHello");
Stringresult = (String) nsm.invoke(classObject);
System.out.println("nsminvoke =" +result);
}
}
Method[]methods = libClazz.getMethods();
for (int i = 0; i
methods[i].setAccessible(true);//if the method is private,it must be use setAccessible
System.out.println(methods[i].getName());
}
Field[] fields = libClazz.getFields();
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);//if the field is private,it must be use setAccessible
System.out.println(fields[i].getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
执行结果如图:
6.完整Demo
package com.example.test.voice.bat;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import dalvik.system.DexClassLoader;
import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
publicclass ReflectActivity extends Activity {
@Override
protectedvoid onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reflect);
copyFileToInternalStorage("utils-r1204.jar");
jarToReflect();
}
publicvoidcopyFileToInternalStorage(final String filename) {
InputStreamis = null;
FileOutputStreamfos = null;
Filefile = newFile(getApplicationContext().getFilesDir(), filename);
if (file.exists()) {
System.out.println("file is exist! cannot to copy again");
}else {
try {
is= getAssets().open(filename);
fos= newFileOutputStream(file);
int len = 0;
byte[] buffer = newbyte[1024];
while ((len =is.read(buffer)) != -1) {
fos.write(buffer,0, len);
}
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
is.close();
fos.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
publicvoid jarToReflect(){
Stringspath=getFilesDir()+"/utils-r1204.jar";
//if use SD
// final File path = newFile(Environment.getExternalStorageDirectory().toString()+"/test.jar");
final File path = new File(spath);
DexClassLoader dexloader = new DexClassLoader(
path.getAbsolutePath(),
getFilesDir().toString(),
null,
getClassLoader());
Class> libClazz = null;
try {
// Load the library class from the class loader.
libClazz= dexloader.loadClass("com.example.demo.Hello");
Methodsm=libClazz.getMethod("startHello", new Class[]{String.class});
Stringsinvoke = (String) sm.invoke(libClazz, new Object[]{"aaaa"});
System.out.println("sinvoke ="+sinvoke);
Constructor[]constructors = libClazz.getDeclaredConstructors();
AccessibleObject.setAccessible(constructors,true);
for (Constructor con :constructors) {
if (con.isAccessible()){
ObjectclassObject = con.newInstance();
Methodnsm = libClazz.getMethod("sayHello");
Stringresult = (String) nsm.invoke(classObject);
System.out.println("nsminvoke =" +result);
}
}
Method[]methods = libClazz.getMethods();
for (int i = 0; i
methods[i].setAccessible(true);//if the method is private,it must be use setAccessible
System.out.println(methods[i].getName());
}
Field[] fields = libClazz.getFields();
for (int i = 0; i
fields[i].setAccessible(true);//if the field is private,it must be use setAccessible
System.out.println(fields[i].getName());
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
7.补充:
1.不需要在本工程里面导出jar,自己新建一个Java工程导出来也行。
如果你觉得好,可以分享此公众号给你更多的人,原创不易。
------------华丽分割线--------------