当前位置: 代码迷 >> Android >> android动态加载已安装跟未安装的apk资源
  详细解决方案

android动态加载已安装跟未安装的apk资源

热度:54   发布时间:2016-04-28 01:38:44.0
android动态加载已安装和未安装的apk资源

           在android开发中动态加载已安装和未安装的apk资源,是很有用的,可以用来实现换肤功能等等。今天我们来学习。

           首先新建一个工程plugpicinstall,我们需要往该工程的asset目录和drawable目录下拷贝一些呆会需要加载的图片。运行该工程,即安装。

           我们先看看如何实现加载已经安装的apk中的资源:

           我们需要先写两个方法,用来获取对应的已安装的apk的context对象和resource对应的id,如下:

	/**	 * 该方法用来获取已经安装的apk对应的context对象	 * @return	 * @throws NameNotFoundException	 */	private Context getInstalledContext() throws NameNotFoundException {		return createPackageContext("com.example.plugpicinstall",Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);	}	/**	 * 该方法用来获取已经安装的apk中对应的resource对象	 * @param resources	 * @param resType	 * @param resName	 * @return	 */	private int getResourceId(Resources resources,String resType,String resName) {		return resources.getIdentifier(resName, resType,"com.example.plugpicinstall");	}
             接下来是加载drawable文件加下图片和加载string.xml中的字符串的代码:

Resources installedResource = null;try {	//得到已经安装的apk的resource对象	installedResource = getInstalledContext().getResources();} catch (NameNotFoundException e) {	e.printStackTrace();}imageViewInstall.setImageDrawable(installedResource.getDrawable(getResourceId(installedResource,"drawable","three")));String app_name = installedResource.getString(getResourceId(installedResource, "string","app_name"));String hello_world = installedResource.getString(getResourceId(installedResource, "string","hello_world"));Toast.makeText(MainActivity.this,"app_name is :"+app_name+"===hello_world is :"+hello_world,Toast.LENGTH_LONG).show();
           下面是加载已经安装的apk中的asset中的资源:

AssetManager assetManager = getInstalledContext().getResources().getAssets();InputStream ins = assetManager.open("six.jpg");Bitmap bitmap = BitmapFactory.decodeStream(ins);imageViewInstall.setImageBitmap(bitmap);
这样就实现了加载已经安装好的apk中的资源文件。


            接下来看看,加载没有安装的apk中对应的文件,首先将刚才的plugpicinstall工程从手机上卸载,然后将bin目录下生成的apk拷贝到手机sd卡相应的目录下:

同样,首先新建一个方法用来获取没有安装的apk对应的resource对象:

	/**	 * 该方法用来获取未安装的apk的reosurces对象	 * @return	 */	private Resources getUnInstalledResource() {		 // 反射出资源管理器          try {			Class<?> assetManager_clazz = Class  			        .forName("android.content.res.AssetManager");			//生成assetManager对象			Object assetObj = assetManager_clazz.newInstance();			//因为addAssetPath是隐藏的,所以只能通过反射来获取			Method addAssetMethod = assetManager_clazz.getDeclaredMethod("addAssetPath",String.class);			addAssetMethod.invoke(assetObj,"/storage/sdcard0/183/plugpicinstall.apk");			Resources resources = getResources();			Constructor<?>resources_constructor = Resources.class.getConstructor(assetManager_clazz,resources.getDisplayMetrics().getClass(),resources.getConfiguration().getClass());			resources = (Resources) resources_constructor.newInstance(assetObj,resources.getDisplayMetrics(),resources.getConfiguration());			//返回/storage/sdcard0/183/plugpicinstall.apk的resources实例			return resources;		} catch (ClassNotFoundException e) {			e.printStackTrace();		} catch (InstantiationException e) {			e.printStackTrace();		} catch (IllegalAccessException e) {			e.printStackTrace();		} catch (NoSuchMethodException e) {			e.printStackTrace();		} catch (IllegalArgumentException e) {			e.printStackTrace();		} catch (InvocationTargetException e) {			e.printStackTrace();		}  		return null;	}
           下面的代码实现加载未安装的apk中的资源:

String apkPath = "/storage/sdcard0/183/plugpicinstall.apk";String dexPath = MainActivity.this.getDir("dex",Context.MODE_PRIVATE).getAbsolutePath();DexClassLoader classLoader = new DexClassLoader(apkPath, dexPath, null, getClassLoader());try {	//反射得到R文件的内部类drawable	Class<?> drawable_clazz = classLoader.loadClass("com.example.plugpicinstall.R$drawable");	//得到drawable类的所有属性	Field[]fields = drawable_clazz.getDeclaredFields();	for (Field field : fields) {		field.setAccessible(true);		if (field.getName().equals("ten")) {		<span style="white-space:pre">	</span>int id = field.getInt(new R.id());			imageViewInstall.setBackground(getUnInstalledResource().getDrawable(id));		}	}	//反射得到R文件的内部类string	Class<?>string_clazz = classLoader.loadClass("com.example.plugpicinstall.R$string");	StringBuffer sb = new StringBuffer();	//得到string内部类的所有属性,这些属性就是我们在string.xml文件中生命的字符串资源	Field[]fields2 = string_clazz.getDeclaredFields();	int id = 0;	for (Field field : fields2) {		//得到对应的字符串资源的id值		id = field.getInt(new R.id());		sb.append(getUnInstalledResource().getString(id));	}	Toast.makeText(MainActivity.this,sb.toString(),Toast.LENGTH_SHORT).show();} catch (ClassNotFoundException e) {	e.printStackTrace();} catch (IllegalAccessException e) {	e.printStackTrace();} catch (IllegalArgumentException e) {	e.printStackTrace();}
          同样的,下面是获取未安装apk的asset资源的方法:

AssetManager assetManager = getUnInstalledResource().getAssets();InputStream ins;try {	ins = assetManager.open("five.jpg");	Bitmap bitmap = BitmapFactory.decodeStream(ins);	imageViewInstall.setImageBitmap(bitmap);} catch (IOException e) {	e.printStackTrace();}

       到现在为止我们的动态加载资源就结束了。

        

       复习一下动态加载,在plugpicinstall工程中新建一个类DynamicClass.java如下:

package com.example.plugpicinstall;import android.app.Activity;import android.widget.Toast;public class DynamicClass {		private Activity mActivity = null;		public void init(Activity activity) {		this.mActivity = activity;	}		public void showHello(String name) {		Toast.makeText(mActivity,"your name is :"+name, Toast.LENGTH_SHORT).show();	}		public void showAddResult(int a,int b) {		Toast.makeText(mActivity,"the result is :"+(a+b),Toast.LENGTH_SHORT).show();	}}
这个类中定义的方法,就是等会需要加载运行的。

再次将该工程plugpicinstall打包成apk,将该apk放入到sdcard的某一个目录下。


下面是加载该类DynamicClass.java类中方法的代码:

运行showAddResult方法:

String apkPath = "/storage/sdcard0/183/plugpicinstall.apk";String dexPath = MainActivity.this.getDir("dex",Context.MODE_PRIVATE).getAbsolutePath();DexClassLoader classLoader = new DexClassLoader(apkPath, dexPath, null, getClassLoader());try {	Class<?> clazz = classLoader.loadClass("com.example.plugpicinstall.DynamicClass");	Object obj = clazz.newInstance();	Method initMeghod = clazz.getDeclaredMethod("init",Activity.class);	initMeghod.invoke(obj,MainActivity.this);						//利用反射运行showAddResult方法	Class[]params = new Class[2];	params[0] = Integer.TYPE;	params[1] = Integer.TYPE;	Method showAddMethod = clazz.getDeclaredMethod("showAddResult",params);	showAddMethod.invoke(obj, 1,33);} catch (ClassNotFoundException e) {	e.printStackTrace();} catch (InstantiationException e) {	e.printStackTrace();} catch (IllegalAccessException e) {	e.printStackTrace();} catch (NoSuchMethodException e) {	e.printStackTrace();} catch (IllegalArgumentException e) {		e.printStackTrace();} catch (InvocationTargetException e) {	e.printStackTrace();}
运行showHello方法:

//apk文件的存放路径String apkPath = "/storage/sdcard0/183/plugpicinstall.apk";//dex文件的路径String dexPath = MainActivity.this.getDir("dex",Context.MODE_PRIVATE).getAbsolutePath();DexClassLoader classLoader = new DexClassLoader(apkPath, dexPath, null, getClassLoader());try {	//加载需要的类	Class<?> clazz = classLoader.loadClass("com.example.plugpicinstall.DynamicClass");	Object obj = clazz.newInstance();<span style="white-space:pre">	</span>//利用反射调用init方法,将context对象赋值	Method initMeghod = clazz.getDeclaredMethod("init",Activity.class);	initMeghod.invoke(obj,MainActivity.this);	//利用反射执行showHello方法,传入一个string参数	Method helloMethod = clazz.getDeclaredMethod("showHello",String.class);	helloMethod.invoke(obj,"李磊");} catch (ClassNotFoundException e) {	e.printStackTrace();} catch (InstantiationException e) {	e.printStackTrace();} catch (IllegalAccessException e) {	e.printStackTrace();} catch (NoSuchMethodException e) {	e.printStackTrace();} catch (IllegalArgumentException e) {	e.printStackTrace();} catch (InvocationTargetException e) {	e.printStackTrace();}

   好了,至此动态加载已安装和未安装的apk资源就实现了。


源码下载









  相关解决方案