android动态加载已安装apk中的方法

       在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 stub
		mActivity = activity;
	}
	public void showDialog() {
		// TODO Auto-generated method stub
		Toast.makeText(mActivity, "show dialog test gaga",Toast.LENGTH_LONG).show();
	}
	public void showWindow() {
		// TODO Auto-generated method stub
		Toast.makeText(mActivity, "show window test gaga",Toast.LENGTH_LONG).show();
	}
	public int addMethod(int a, int b) {
		// TODO Auto-generated method stub
		return a + b;
	}

}
可以看到init方法中,我们为其mActivity赋值,这是为了得到context对象,好让toast可以执行。

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

 
       
            
            
        
        
            
        
 

             安装plugproj工程。

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

              //创建一个意图,用来找到指定的apk    
		Intent intent = new Intent("com.haha.android.plugin", null);    
		//获得包管理器    
		PackageManager pm = getPackageManager();    
		List 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 block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
接下来是执行上面三个方法的onclick事件:

        @Override
	public void onClick(View arg0) {
		// TODO Auto-generated method stub
		try {
			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 stub
try {
	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:
		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);
		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();
}
}
最后千万要记住,添加读写sd卡的权限。

 源码下载

动态加载jar




你可能感兴趣的:(android,android,加载)