Android 使用DexClassLoader来运行其他apk中的方法

Android中apk文件里的dex文件是对java编译出来的.class文件进行重新打包,当然在打包之前会利用自己的协议做一些数据处理,例如优化函数表和变量表。在java程序中是使用classloader来加载这些编译生成的.class文件,然而在android程序中是通过DexClassLoader来装载这些文件的.这里我们就可以通过DexClassLoader在程序A里面动态装载程序B中的类,并且来调用B程序中的方法.

1.首先先建立一个普通的Android工程,在这个工程中定义一个叫做plugin的类,类中实现一个简单的方法,如下所示:

<span style="font-size:14px;">public class PluginClass {
	private static String TAG = PluginClass.class.getSimpleName();
	public PluginClass(){
		Log.i(TAG, "initialized");
	}
	public void invoke(String s){
		Log.i(TAG, s);
	}
}</span>

2.将这个Android工程运行到安卓设备当中去

3.再重新建立一个Android工程,其中定义一个叫做host的类,在这个类中实现DexClassLoader动态加载第一个工程中的plugin类,如下所示:

<span style="font-size:14px;">public class HostClass {
	private static String TAG = HostClass.class.getSimpleName();
	private Context mContext = null;
	public HostClass(Context contect){
		mContext = contect;
	}
	public void useDexClassLoader(){
		Intent intent = new Intent();
		intent.setPackage("com.example.plugin");
		PackageManager pm = mContext.getPackageManager();
		final List<ResolveInfo> plugins = pm.queryIntentActivities(intent,0);
		if(plugins.size() <= 0){
			Log.i(TAG, "resolve info size is:" + plugins.size());
			return;
		}
		ResolveInfo resolveInfo = plugins.get(0);
		ActivityInfo activityInfo = resolveInfo.activityInfo;

		String div = System.getProperty("path.separator");
		String packageName = activityInfo.packageName;
		String dexPath = activityInfo.applicationInfo.sourceDir;
		//目标类所在的apk或者jar的路径,class loader会通过这个路径来加载目标类文件
		String dexOutputDir = mContext.getApplicationInfo().dataDir;
		//由于dex文件是包含在apk或者jar文件中的,所以在加载class之前就需要先将dex文件解压出来,dexOutputDir为解压路径
		String libPath = activityInfo.applicationInfo.nativeLibraryDir;
		//目标类可能使用的c或者c++的库文件的存放路径

		Log.i(TAG, "div:" + div + "   " +
					"packageName:" + packageName + "   " +
					"dexPath:" + dexPath + "   " +
					"dexOutputDir:" + dexOutputDir + "   " +
					"libPath:" + libPath);

		DexClassLoader dcLoader = new DexClassLoader(dexPath,dexOutputDir,libPath,this.getClass().getClassLoader());
		try {
			Class<?> clazz = dcLoader.loadClass(packageName + ".PluginClass");
			Object obj = clazz.newInstance();
			Class[] param = new Class[1];
			param[0] = String.class;
			Method action = clazz.getMethod("invoke", param);
			action.invoke(obj, "test this function");
		} catch (ClassNotFoundException e) {
			Log.i(TAG, "ClassNotFoundException");
		} catch (InstantiationException e) {
			Log.i(TAG, "InstantiationException");
		} catch (IllegalAccessException e) {
			Log.i(TAG, "IllegalAccessException");
		} catch (NoSuchMethodException e) {
			Log.i(TAG, "NoSuchMethodException");
		} catch (IllegalArgumentException e) {
			Log.i(TAG, "IllegalArgumentException");
		} catch (InvocationTargetException e) {
			Log.i(TAG, "InvocationTargetException");
		}
	}
}</span>

4.运行第二个工程之后查看log就会发现host通过DexClassLoader加载了pluginclass类,并成功调用了plugin中的方法

<span style="font-size:14px;">I/HostClass( 8341): div::   packageName:com.example.plugin   dexPath:/data/app/com.example.plugin-1.apk   dexOutputDir:/data/data/com.example.host   libPath:/data/app-lib/com.example.plugin-1
D/dalvikvm( 8341): DexOpt: --- BEGIN 'com.example.plugin-1.apk' (bootstrap=0) ---
D/dalvikvm( 8341): DexOpt: --- END 'com.example.plugin-1.apk' (success) ---
D/dalvikvm( 8341): DEX prep '/data/app/com.example.plugin-1.apk': unzip in 39ms, rewrite 723ms
I/PluginClass( 8341): initialized
I/PluginClass( 8341): test this function
D/libEGL  ( 8341): loaded /system/lib/egl/libEGL_mali.so
D/libEGL  ( 8341): loaded /system/lib/egl/libGLESv1_CM_mali.so
D/libEGL  ( 8341): loaded /system/lib/egl/libGLESv2_mali.so
D/OpenGLRenderer( 8341): Enabling debug mode 0
I/HostClass( 8341): div::   packageName:com.example.plugin   dexPath:/data/app/com.example.plugin-1.apk   dexOutputDir:/data/data/com.example.host   libPath:/data/app-lib/com.example.plugin-1
I/PluginClass( 8341): initialized
I/PluginClass( 8341): test this function</span>

时间: 2024-07-31 07:14:48

Android 使用DexClassLoader来运行其他apk中的方法的相关文章

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

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

【Android】Could not find XXX.apk!的解决方法

昨天在Eclipse中导入一个Android工程后点击运行时出现了Could not find XXX.apk!的错误信息,具体错误提示如下: 到网上搜了好多方法,挨个尝试,最后都没解决但是,重启Eclipse居然好了,    观察发现在bin目录下没有apk文件,可能是因为工程没有完全编译通过无法生成apk,所以project-->clean,然后rebuild就可以了~ 另外可以手动导出无签名的apk然后在导入到模拟器中,对于如何将apk导入到模拟器中可以参考这篇文章: http://wan

Android插件化开发---运行未安装apk中的Service

如果你还不知道什么叫插件化开发,那么你应该先读一读之前写的这篇博客:Android插件化开发,初入殿堂 上一篇博客主要从整体角度分析了一下Android插件化开发的几个难点与动态加载没有被安装的apk中的Activity和资源的方法.其实一般的插件开发主要也就是加载个Activity,读取一些资源图片之类的.但是总有遇到特殊情况的时候,比如加载Service. 要动态加载Service,有两种思路:一是通过NDK的形式,将Service通过C++运行起来(这种方法我没有尝试,只听群里的朋友说实现

Android插件化(二):使用DexClassLoader动态加载assets中的apk

Android插件化(二):使用DexClassLoader动态加载assets中的apk 简介 上一篇博客讲到,我们可以使用MultiDex.java加载离线的apk文件.需要注意的是,apk中的类是加载到当前的PathClassLoader当中的,如果apk文件过多,可能会出现ANR的情况.那么,我们能不能使用DexClassLoader加载apk呢?当然是可以的!首先看一下Doc文档. A class loader that loads classes from .jar and .apk

Android插件化(三)加载插件apk中的Resource资源

Android加载插件apk中的Resource资源 简介 如何加载未安装apk中的资源文件呢?我们从android.content.res.AssetManager.java的源码中发现,它有一个私有方法addAssetPath,只需要将apk的路径作为参数传入,我们就可以获得对应的AssetsManager对象,然后我们就可以使用AssetsManager对象,创建一个Resources对象,然后就可以从Resource对象中访问apk中的资源了.总结如下: 1.新建一个AssetManag

Android逆向之旅---运行时修改内存中的Dalvik指令来改变代码逻辑

一.前言 最近在弄脱壳的时候发现有些加固平台的加固方式是修改了dex文件结构,然后在加载dex到内存的时候,在进行dex格式修复,从而达到了apk保护的效果,那么在dex加载到内存的时候,如何进行dex格式的修复呢?其实原理就是基于运行时修改内存中的Dalvik数据,本文就来用一个简单的例子来介绍一下如何在内存中去修改Dalvik指令代码来改变代码本生的运行逻辑.在讲解本文之前,一定要先看这篇文章:Android中Dex文件格式详解 这篇文章主要介绍了关于Dex文件的格式介绍,这个对于后面修改内

(转)从android一个apk中启动第三方apk应用

从android一个apk中启动第三方apk应用 我们在开发中,经常遇到遇到在一个apk中要去运行另外一个apk,就像我们windows一样,搞一个快捷方式一样,那怎么实现呢? 问题的核心点在于我们要拿到第三方apk的package名称跟class名称,这两个至关重要!比如笔者做测试用的qq apk,package名称是com.tencent.pad.qq,class名称是com.tencent.pad.qq.login.QQLoginActivity.从一个apk启动到另外一个apk,当然也是

Android动态部署五:如何从插件apk中启动Service

转载请注明出处:http://blog.csdn.net/ximsfei/article/details/51072332 github地址:https://github.com/ximsfei/DynamicDeploymentApk Android动态部署一:Google原生Split APK浅析 Android动态部署二:APK安装及AndroidManifest.xml解析流程分析 Android动态部署三:如何从插件apk中启动Activity(一) Android动态部署四:如何从插

android读取apk中已经存在的数据库信息

在android数据库编程方面,大家有没有遇到过,我要从指定位置的已经存在的数据库来进行操作的问题.之前我尝试了很多方法都没有成功,后来找到了解决的方法.   下面说明下这段代码的意思,第一步先判断在指定的路劲是否存在,不存在就创建设计素材大全.第二步将android的资源下的数据库复制到指定路径下面.第三步就是根据指定路径打开或者创建数据库,然后得到操作数据库的对象,得到操作数据库的对象了,自然就可以对数据库中的表进行增删改查等操作了. 1. [代码]android程序读取项目中已经存在的数据