上一篇说了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应用程序进程启动过程的源代码分析
  2. 爱奇艺Android移动客户端app瘦身经验
  3. Android系统编译―Android.mk文件的简单介绍
  4. Android之Adapter用法总结
  5. 【安卓开发】Facebook工程师是如何改进他们Android客户端的
  6. Android应用程序进程启动过程的源代码分析
  7. android AIDL服务
  8. Android中的资源与国际化!
  9. 由安装Busybox到Android过程中想到的

随机推荐

  1. Android动画之 Alpha与Translate结合使用
  2. RelativeLayout(相对布局)
  3. android语音识别之科大讯飞语音API的使用
  4. Tegra Android(安卓)Development Pack |
  5. RelativeLayout用到的一些重要的属性:
  6. Android入门:ImageView介绍
  7. shape的使用
  8. Android(安卓)之 Gallery画廊用法
  9. Android(安卓)Activity 常用功能设置(全屏
  10. Binder解析