上一篇说了android中的动态加载,即在android工程中动态加载经过dx操作以后的jar文件和没有安装的apk文件,今天我们来看看怎么执行已经安装的apk中的类中的方法。

所以,我们会需要两个工程,一个是plugone,这个是我们暴露给外面的方法的一个android工程。另外一个我们暂且给他起名为useplugone吧。

先来看看plugone工程,我们在plugone工程中有这样一个类,用来暴露给调用者一个方法:

package com.example.plugone;public class Plugin1 {public int add(int a,int b) {return a + b;}}

另外,还需要在清单文件中为MainActivity中添加一个action,这样做是为了在useplugone工程中,找到该apk中的资源,代码如下如下:

<activity            android:name="com.example.plugone.MainActivity"            android:label="@string/app_name" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>             <intent-filter><action android:name="com.haha.android.plugin"/>            </intent-filter>        </activity>


接下来就是我们的useplugone工程了,主要的代码如下:

 //创建一个意图,用来找到指定的apk          Intent intent = new Intent("com.haha.android.plugin", null);          //获得包管理器          PackageManager pm = getPackageManager();          List<ResolveInfo> resolveinfoes =  pm.queryIntentActivities(intent, 0);          //获得指定的activity的信息          ActivityInfo actInfo = resolveinfoes.get(0).activityInfo;                    //获得包名          String pacageName = actInfo.packageName;          //获得apk的目录或者jar的目录          String apkPath = actInfo.applicationInfo.sourceDir;          //dex解压后的目录,注意,这个用宿主程序的目录,android中只允许程序读取写自己          //目录下的文件          String dexOutputDir = getApplicationInfo().dataDir;  //  /data/app/com.example.plugone-1.apk                  //native代码的目录          String libPath = actInfo.applicationInfo.nativeLibraryDir;  //  /data/app-lib/com.example.plugone-1        //创建类加载器,把dex加载到虚拟机中          DexClassLoader calssLoader = new DexClassLoader(apkPath, dexOutputDir, libPath,                  this.getClass().getClassLoader());                    //利用反射调用插件包内的类的方法                    try {              Class<?> clazz = calssLoader.loadClass(pacageName+".Plugin1");                            Object obj = clazz.newInstance();              Class[] param = new Class[2];              param[0] = Integer.TYPE;              param[1] = Integer.TYPE;                            Method method = clazz.getMethod("add", param);                            Integer ret = (Integer)method.invoke(obj, 1,12);              int result = ret.intValue();            System.out.println(result);                      } catch (Exception e) {              e.printStackTrace();          }

源码下载


下面我们在重新看看在android工程中动态加载jar文件,同样该jar文件是需要经过dx处理的,不懂得可以看看上一篇文章 android动态加载,在上一篇中我们导出jar文件时用的java工程,并且当时还指明导出jar文件时不要选择将接口导出,这是因为在这个android工程中同样声明了该接口,所以如果将接口导出,会出现接口冲突,这次我们改为将android工程导出为jar文件,并且可以导出接口,这次我们创建一个android工程plugtwo,然后导出jar文件,经过dx处理以后,将其放入另一个useplugtwo工程的asset文件夹下,来让程序自动运行。下面分别来看看plugtwo和useplugtwo工程的代码:


首先是plugtwo:

首先我们声明一个接口文件:

package com.example.plugtwo;public interface Iinterface {      public void call();      public String getData();  }  
然后创建一个实体类实现该接口,这次我们让该实体类可以弹出toast,所以需要创建一个context成员变量

package com.example.plugtwo;import android.content.Context;  import android.widget.Toast;    public class IClass implements Iinterface {        private Context context;        public IClass(Context context) {          super();          this.context = context;      }        @Override      public void call() {          Toast.makeText(context, "call method", 0).show();      }        @Override      public String getData() {          return "hello,i am from IClass";      }    } 
程序比较简单,我就不细说了。然后将该程序导出为jar文件,这里我们同样导出为 load.jar,然后将该load.jar文件拷贝到具有dx命令的sdk的文件夹下,执行dx--dex--output=testdex.jar load.jar ,成功以后会发现在该文件夹下生成了一个testdex.jar文件,这个jar文件就是我们的android工程可以直接调用的jar文件。

现在我们新建一个名为useplugtwo的android工程,并且将该testdex.jar文件拷贝到useplugtwo的asset工程中,接下来看看我们的useplugtwo中的MainActivity代码:

首先我们调用copyFromAsset方法将asset文件夹下的testdex.jar文件拷贝到sdcard的指定目录,代码如下:

             public void copyFromAsset() {InputStream ins = null;FileOutputStream fos = null;try {ins = getAssets().open("testdex.jar");//String getStr = "/storage/sdcard0/liuhang/";File file = new File(dir+"/testjar/");if (!file.exists()) {file.mkdirs();}file = new File(file,"testdex.jar");fos = new FileOutputStream(file);int count = 0;byte[]b = new byte[1024];while ((count = ins.read(b)) != -1) {  fos.write(b,0,count);}} catch (Exception e) {e.printStackTrace();}finally{try {if (fos != null) {fos.flush();fos.close();}} catch (Exception e) {e.printStackTrace();}}}

然后就是利用反射动态执行生成的testdex.jar文件中的方法,如下:

File file = new File("/storage/sdcard0/testjar/testdex.jar");     final File optimizedDexOutputPath = getDir("temp", Context.MODE_PRIVATE);    String filePath = file.getAbsolutePath();    String optimizedPath = optimizedDexOutputPath.getAbsolutePath();    //optimizedPath == data/data/com.example.useplugtwo/app_temp    DexClassLoader classLoader = new DexClassLoader(file.getAbsolutePath(),         optimizedDexOutputPath.getAbsolutePath(), null,         getClassLoader());     try {       Class<?> iclass = classLoader.loadClass("com.example.plugtwo.IClass");       Constructor<?> istructor = iclass.getConstructor(Context.class);       //利用反射原理去调用       Method method = iclass.getMethod("call", null);       String data = (String) method.invoke(istructor.newInstance(this), null);       System.out.println(data);     } catch (Exception e) {       // TODO Auto-generated catch block       e.printStackTrace();     } 

今天就到这里,该休息了。
源码连接


更多相关文章

  1. Android系统编译―Android.mk文件的简单介绍
  2. 【安卓开发】Facebook工程师是如何改进他们Android客户端的
  3. android 工程中重新生成gen文件夹或R.java 文件
  4. [转载]Android布局文件中命名空间的解析
  5. Android Layout布局文件里的android:layout_height等属性不起作
  6. Android 下载的三种实现方式(文件流的读写方式下载,用DownloadMan
  7. Android 自定义View及其在布局文件中的使用示例
  8. Android Training - 创建一个Android工程

随机推荐

  1. jdbc连接数据库步骤深刻分析
  2. windows系统php环境安装swoole具体步骤
  3. 模态框案例实战
  4. 透视怎么绘画?漫画背景透视画法步骤
  5. 通过vue学习react(四) - watch,computed,
  6. 初学者如何画脚部?动漫人物脚部画法步骤
  7. 移动端布局思路与三种视口的关系 ,仿淘宝
  8. 移动端布局的基本思路
  9. php中文网布局实战
  10. 仿PHP中文网首页