android动态加载(二)

上一篇说了android中的动态加载,即在android工程中动态加载经过dx操作以后的jar文件和没有安装的apk文件,今天我们来看看怎么执行已经安装的apk中的类中的方法。

所以,我们会需要两个工程,一个是plugone,这个是我们暴露给外面的方法的一个android工程。另外一个我们暂且给他起名为useplugone吧。

先来看看plugone工程,我们在plugone工程中有这样一个类,用来暴露给调用者一个方法:

package com.example.plugone;

public class Plugin1 {
	public int add(int a,int b) {
		return a + b;
	}
}

另外,还需要在清单文件中为MainActivity中添加一个action,这样做是为了在useplugone工程中,找到该apk中的资源,代码如下如下:

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

接下来就是我们的useplugone工程了,主要的代码如下:

 //创建一个意图,用来找到指定的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;  //  /data/app/com.example.plugone-1.apk

        //native代码的目录
        String libPath = actInfo.applicationInfo.nativeLibraryDir;  //  /data/app-lib/com.example.plugone-1
        //创建类加载器,把dex加载到虚拟机中
        DexClassLoader calssLoader = new DexClassLoader(apkPath, dexOutputDir, libPath,
                this.getClass().getClassLoader());  

        //利用反射调用插件包内的类的方法  

        try {
            Class<?> clazz = calssLoader.loadClass(pacageName+".Plugin1");  

            Object obj = clazz.newInstance();
            Class[] param = new Class[2];
            param[0] = Integer.TYPE;
            param[1] = Integer.TYPE;  

            Method method = clazz.getMethod("add", param);  

            Integer ret = (Integer)method.invoke(obj, 1,12);
            int result = ret.intValue();
            System.out.println(result);

        } catch (Exception e) {
            e.printStackTrace();
        }

源码下载

下面我们在重新看看在android工程中动态加载jar文件,同样该jar文件是需要经过dx处理的,不懂得可以看看上一篇文章android动态加载,在上一篇中我们导出jar文件时用的java工程,并且当时还指明导出jar文件时不要选择将接口导出,这是因为在这个android工程中同样声明了该接口,所以如果将接口导出,会出现接口冲突,这次我们改为将android工程导出为jar文件,并且可以导出接口,这次我们创建一个android工程plugtwo,然后导出jar文件,经过dx处理以后,将其放入另一个useplugtwo工程的asset文件夹下,来让程序自动运行。下面分别来看看plugtwo和useplugtwo工程的代码:

首先是plugtwo:

首先我们声明一个接口文件:

package com.example.plugtwo;

public interface Iinterface {
    public void call();
    public String getData();
}  

然后创建一个实体类实现该接口,这次我们让该实体类可以弹出toast,所以需要创建一个context成员变量

package com.example.plugtwo;

import android.content.Context;
import android.widget.Toast;  

public class IClass implements Iinterface {  

    private Context context;  

    public IClass(Context context) {
        super();
        this.context = context;
    }  

    @Override
    public void call() {
        Toast.makeText(context, "call method", 0).show();
    }  

    @Override
    public String getData() {
        return "hello,i am from IClass";
    }  

} 

程序比较简单,我就不细说了。然后将该程序导出为jar文件,这里我们同样导出为load.jar,然后将该load.jar文件拷贝到具有dx命令的sdk的文件夹下,执行dx --dex --output=testdex.jar
load.jar  ,成功以后会发现在该文件夹下生成了一个testdex.jar文件,这个jar文件就是我们的android工程可以直接调用的jar文件。

现在我们新建一个名为useplugtwo的android工程,并且将该testdex.jar文件拷贝到useplugtwo的asset工程中,接下来看看我们的useplugtwo中的MainActivity代码:

首先我们调用copyFromAsset方法将asset文件夹下的testdex.jar文件拷贝到sdcard的指定目录,代码如下:

             public void copyFromAsset() {
		InputStream ins = null;
		FileOutputStream fos = null;
			try {
				ins = getAssets().open("testdex.jar");
				//				String getStr = "/storage/sdcard0/liuhang/";
				File file = new File(dir+"/testjar/");
				if (!file.exists()) {
					file.mkdirs();
				}
				file = new File(file,"testdex.jar");
				fos = new FileOutputStream(file);
				int count = 0;
				byte[]b = new byte[1024];
				while ((count = ins.read(b)) != -1) {
					fos.write(b,0,count);
				}

			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				try {
					if (fos != null) {
						fos.flush();
						fos.close();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

然后就是利用反射动态执行生成的testdex.jar文件中的方法,如下:

 File file = new File("/storage/sdcard0/testjar/testdex.jar");  
        final File optimizedDexOutputPath = getDir("temp", Context.MODE_PRIVATE);
        String filePath = file.getAbsolutePath();
        String optimizedPath = optimizedDexOutputPath.getAbsolutePath();
        //optimizedPath == data/data/com.example.useplugtwo/app_temp
        DexClassLoader classLoader = new DexClassLoader(file.getAbsolutePath(),  
                optimizedDexOutputPath.getAbsolutePath(), null,  
                getClassLoader());  
        try {  
            Class<?> iclass = classLoader.loadClass("com.example.plugtwo.IClass");  
            Constructor<?> istructor = iclass.getConstructor(Context.class);  
            //利用反射原理去调用   
            Method method = iclass.getMethod("call", null);  
            String data = (String) method.invoke(istructor.newInstance(this), null);  
            System.out.println(data);  
        } catch (Exception e) {  
            // TODO Auto-generated catch block   
            e.printStackTrace();  
        }  

今天就到这里,该休息了。

源码连接

时间: 2024-08-05 15:32:56

android动态加载(二)的相关文章

Android动态加载jar/dex

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

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动态加载框架DL的架构与基本原理解析

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

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

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

Android动态加载代码技术

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

Android动态加载那些事儿

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

Android动态加载ListView中的Item

我这周上网看到动态增加listview的每一项item的布局,今天抽空自己写了一个,方便自己日后使用,这个效果还是很不错的,用到了Adapter的notifyDataSetChanged()方法,当点击每一个Item的时候,就通知adapter更新getView,系统得到通知就相应的加载一遍布局,就达到了动态加载item布局的效果.希望给大家带来点启迪,有问题或想要代码的可以留言,欢迎大家留言谈论listview的一些知识,以求共同进步,转载请标明出处: http://blog.csdn.net

Android动态加载及hook资料汇总

Android  Java Hook http://www.52pojie.cn/thread-288128-2-1.html http://www.52pojie.cn/thread-426890-1-2.html apk加固 http://blog.csdn.net/jiangwei0910410003/article/details/48415225 Android自动打包程序 http://www.jizhuomi.com/android/environment/281.html 360