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资源就实现了。

源码下载

时间: 2024-12-28 16:56:55

android动态加载已安装和未安装的apk资源的相关文章

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

在android开发中,有很多时候是需要用到动态加载的,今天学习在android中动态加载已安装的apk中的方法. 首先,我们需要新建一个用来被加载的android工程,暂且给他取名叫做:plugproj 在plugproj中新建一个类Dynamic,在这个类中,我们新建一些方法,等会我们会分别在该工程安装和没有安装的情况下加载这些方法,Dynamic.java如下: package com.example.plugproj; import android.app.Activity; impor

Android动态加载那些事儿

基础 1.Java 类加载器 类加载器(class loader)是 Java?中的一个很重要的概念.类加载器负责加载 Java 类的字节代码到 Java 虚拟机中.本文首先详细介绍了 Java 类加载器的基本概念,包括代理模式.加载类的具体过程和线程上下文类加载器等,接着介绍如何开发自己的类加载器,最后介绍了类加载器在 Web 容器和 OSGi?中的应用. 2.反射原理 Java 提供的反射機制允許您於執行時期動態載入類別.檢視類別資訊.生成物件或操作生成的物件,要舉反射機制的一個應用實例,就

Android动态加载框架DL的架构与基本原理解析

转载请注明出处,本文来自[ Mr.Simple的博客 ]. 我正在参加博客之星,点击这里投我一票吧,谢谢~ 前言 最近这一两年,Android App使用插件化技术开发的数量越来越大,其实还是业务地快速膨胀导致,需求越来越多,App越来越臃肿.虽然手机的内存空间不断地的增大,但是太大的安装包给用户也造成了心理压力.于是大家都会想到插件化的开发方式,把App做成一个平台,而不是一个独立的app.平台上可以集成各种各样的功能,功能模块也插件的形式添加进来,这些插件不需要安装,只需要用户按需下载到某个

Android动态加载jar/dex

http://www.cnblogs.com/over140/archive/2011/11/23/2259367.html 前言 在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本文对网上Android动态加载jar的资料进行梳理和实践在这里与大家一起分享,试图改善频繁升级这一弊病. 声明 欢迎转载,但请保留文章原始出处:) 博客园:http:/

Android动态加载技术三个关键问题详解

编者按:InfoQ开设新栏目“品味书香”,精选技术书籍的精彩章节,以及分享看完书留下的思考和收获,欢迎大家关注.本文节选自任玉刚著<Android开发艺术探索>中的章节“Android的动态加载技术”,探讨了Android动态加载的三个关键问题. 动态加载技术(也叫插件化技术)在技术驱动型的公司中扮演着相当重要的角色,当项目越来越庞大的时候,需要通过插件化来减轻应用的内存和CPU占用,还可以实现热插拔,即在不发布新版本的情况下更新某些模块.动态加载是一项很复杂的技术,这里主要介绍动态加载技术中

Android动态加载Dex机制解析

1.什么是类加载器? 类加载器(class loader)是 Java?中的一个很重要的概念.类加载器负责加载 Java 类的字节代码到 Java 虚拟机中. Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件).类加载器负责读取 Java 字节代码,并转换成java.lang.Class类的一个实例.每个这样的实例用来表示一个 Java 类.通过此实例的 newInstance()

实现Android 动态加载APK(Fragment or Activity实现)

尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38565345 最近由于项目太大了,导致编译通不过(Android对一个应用中的方法个数貌似有限制),所以一直琢磨着能否将某些模块的APK不用安装,动态加载,通过在网上查找资料和网友的帮助,终于实现了APK的动态加载,网络上介绍APK动态加载的文章非常多,但是我觉得写得非常好的就是这位大牛的,我基本上就是使用他的这种方案,然后加入了自己的元素.这位大牛是通过Activity实现的,我稍作修改

android动态加载(二)

上一篇说了android中的动态加载,即在android工程中动态加载经过dx操作以后的jar文件和没有安装的apk文件,今天我们来看看怎么执行已经安装的apk中的类中的方法. 所以,我们会需要两个工程,一个是plugone,这个是我们暴露给外面的方法的一个android工程.另外一个我们暂且给他起名为useplugone吧. 先来看看plugone工程,我们在plugone工程中有这样一个类,用来暴露给调用者一个方法: package com.example.plugone; public c

Android动态加载代码技术

Android动态加载代码技术 在开发Android App的过程当中,可能希望实现插件式软件架构,将一部分代码以另外一个APK的形式单独发布,而在主程序中加载并执行这个APK中的代码. 实现这个任务的一般方法是: // 加载类cls Context pluginContext = mainContext.createPackageContext(PLUGIN_PKG, Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE)