在android开发中,有很多时候是需要用到动态加载的,今天学习在android中动态加载已安装的apk中的方法。

首先,我们需要新建一个用来被加载的android工程,暂且给他取名叫做:plugproj

在plugproj中新建一个类Dynamic,在这个类中,我们新建一些方法,等会我们会分别在该工程安装和没有安装的情况下加载这些方法,Dynamic.java如下:

package com.example.plugproj;import android.app.Activity;import android.widget.Toast;public class Dynamic {Activity mActivity = null;public void init(Activity activity) {// TODO Auto-generated method stubmActivity = activity;}public void showDialog() {// TODO Auto-generated method stubToast.makeText(mActivity, "show dialog test gaga",Toast.LENGTH_LONG).show();}public void showWindow() {// TODO Auto-generated method stubToast.makeText(mActivity, "show window test gaga",Toast.LENGTH_LONG).show();}public int addMethod(int a, int b) {// TODO Auto-generated method stubreturn a + b;}}
可以看到init方法中,我们为其mActivity赋值,这是为了得到context对象,好让toast可以执行。

这里还需要注意,我们需要为plugproj工程的启动的activity中配置一个action,好让我们可以通过这个action来加载对应的包,如下:

 <activity       android:name="com.example.plugproj.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>

安装plugproj工程。

接下来看看另一个主工程,即加载plugproj的工程,主要代码如下:

              //创建一个意图,用来找到指定的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;  //native代码的目录    String libPath = actInfo.applicationInfo.nativeLibraryDir;  //创建类加载器,把dex加载到虚拟机中    DexClassLoader calssLoader = new DexClassLoader(apkPath, dexOutputDir, libPath,    this.getClass().getClassLoader());   try {clazz = calssLoader.loadClass(pacageName+".Dynamic");  obj = clazz.newInstance();Method initMethod = clazz.getDeclaredMethod("init",Activity.class);initMethod.invoke(obj,MainActivity.this);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (NoSuchMethodException e) {// TODO Auto-generated catch blocke.printStackTrace();} 
接下来是执行上面三个方法的onclick事件:

        @Overridepublic void onClick(View arg0) {// TODO Auto-generated method stubtry {switch (arg0.getId()) {case R.id.id_dialog:Method dialogMethod = clazz.getDeclaredMethod("showDialog",null);dialogMethod.invoke(obj, null);Log.d("Tag","show dialog runs ...");break;case R.id.id_window:Method windowMethod = clazz.getDeclaredMethod("showWindow",null);windowMethod.invoke(obj,null);Log.d("Tag","show window runs ...");break;case R.id.id_plus:Class[] param = new Class[2];              param[0] = Integer.TYPE;              param[1] = Integer.TYPE; Method method = clazz.getDeclaredMethod("addMethod",param); int result = (Integer) method.invoke(obj, 22,33);Toast.makeText(MainActivity.this,"result is :"+result,Toast.LENGTH_SHORT).show();Log.d("Tag","add  runs ...");break;default:Toast.makeText(MainActivity.this,"no property id",Toast.LENGTH_LONG).show();}} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}} 

这样就实现了加载已经安装的apk中的方法。


接下来看看加载已经打包成为jar文件的方式:

首先需要将plugproj导出为jar文件,我们这里导出为plugproj.jar,注意这时候的jar文件在android手机上是不能直接加载的,我们需要将他转换成dex文件,怎么转换呢,在sdk下有一个dx工具,可以用它来实现,将plugproj.jar拷贝到拥有dx文件的目录下,一般是在platform_tool有时在build_tools文件夹下,然后用命令进入该文件下:

执行如下命令:

dx --dex --output 优化过的jar 没有优化过的jar

此时就会生成一个优化过的jar文件,这个jar文件就是我们的android手机可以直接加载的。将该jar文件拷贝到手机指定的目录下:

以下是关键代码:

                String path = "/storage/sdcard0/183/mydynamic_help.jar";dexPath = getDir("dex", Context.MODE_PRIVATE).getAbsolutePath();dexClassLoader = new DexClassLoader(path, dexPath, null, getClassLoader());try {clazz = dexClassLoader.loadClass("com.example.plugproj.Dynamic");try {obj = clazz.newInstance();Method method = clazz.getDeclaredMethod("init",Activity.class);method.invoke(obj, MainActivity.this);Log.d("Tag","dynamic init runs ...");} catch (InstantiationException e1) {e1.printStackTrace();} catch (IllegalAccessException e1) {e1.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}} catch (ClassNotFoundException e) {e.printStackTrace();}
为按钮绑定onclick事件:

public void onClick(View arg0) {// TODO Auto-generated method stubtry {switch (arg0.getId()) {case R.id.id_dialog:Method method = clazz.getDeclaredMethod("showDialog",null);method.invoke(obj, null);Log.d("Tag","show dialog runs ...");break;case R.id.id_window:method = clazz.getDeclaredMethod("showWindow",null);method.invoke(obj, null);Log.d("Tag","show window runs ...");break;case R.id.id_plus:<span style="white-space:pre"></span>Class[]param = new Class[2];param[0] = Integer.TYPE;param[1] = Integer.TYPE; method = clazz.getDeclaredMethod("addMethod",param);int result = (Integer) method.invoke(obj,23,25);<span style="white-space:pre"></span>Toast.makeText(MainActivity.this,"result is :"+result,Toast.LENGTH_SHORT).show();Log.d("Tag","add  runs ...");break;<span style="white-space:pre"></span>default:Toast.makeText(MainActivity.this,"no property id",Toast.LENGTH_LONG).show();}} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}
最后千万要记住,添加读写sd卡的权限。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

源码下载

动态加载jar




更多相关文章

  1. android启动过程及各个镜像间的关系
  2. Android自适应不同屏幕几种方法
  3. Android:异步调用详解
  4. Android与H5交互,以及WebView加载进度条
  5. Android(安卓)应用没有桌面图标
  6. 浅谈Java中Collections.sort对List排序的两种方法
  7. NPM 和webpack 的基础使用
  8. Python list sort方法的具体使用
  9. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程

随机推荐

  1. android -------- 混淆打包报错(warning
  2. android 网络图片与网页读取
  3. Android(安卓)关闭所有的Activity
  4. android 代码中设置字体大小
  5. Android(安卓)日期选择器、日期范围选择
  6. download android kernel for galaxy nex
  7. Android(安卓)使用正则表达式
  8. Android中的“再按一次返回键退出程序”
  9. Android(安卓)调用快递鸟api 实现物流跟
  10. Android(安卓)Timer,TimerTask简单的使用