原来Android还可以这样通过反射,获取jar包属性及方法

1、写一个java类,生成Jar

2、初始Jar的转换

3、创建一个android工程

4、复制Jar

5、反射获取属性和方法

5、完整Demo

6、补充

 

 

摘要:在Android中可以动态加载,但无法像Java中那样方便动态加载jar

原因:Android的虚拟机(Dalvik VM)是不认识Java打出jarbyte code,需要通过dx工具来优化转换成Dalvik byte code才行。这一点在咱们Android项目打包的apk中可以看出:引入其他Jar的内容都被打包进了classes.dex。所以无法像javajar文件直接进行的反射。所以要用android sdk 自带的dx.bat (位于\adt-bundle-windows-x86-20131030\sdk\build-tools下)进行 jar-->dex-->jar的过程。

步骤说明:

  1. 1.写一个java类,生成Jar包

publicclass Hello{

publicstatic String Hello(Strings) {

         return s;

}

public String sayHello(){

         return"HelloWorld";

}

}

使用Fatjar工具进行对java类生成jar文件

原来Android还可以这样通过反射,获取jar包属性及方法_第1张图片

  1. 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目录下。

  1. 3.创建一个android工程

在activity中的oncreate方法中执行如下操作:

    protectedvoid onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_reflect);

        copyFileToInternalStorage ("utils-r1204.jar");

        jarToReflect();

}

  1. 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();

}

}

}

}

  1. 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 length; 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();

        }

   }

执行结果如图: 

原来Android还可以这样通过反射,获取jar包属性及方法_第2张图片

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 length; 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 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();

         }

     }

}

7.补充:

1.不需要在本工程里面导出jar,自己新建一个Java工程导出来也行。

如果你觉得好,可以分享此公众号给你更多的人,原创不易。

------------华丽分割线--------------

长按二维码,关注公众号原来Android还可以这样通过反射,获取jar包属性及方法_第3张图片

你可能感兴趣的:(原来Android还可以这样通过反射,获取jar包属性及方法)