Android 插件化之动态加载jar

有时候会看到一些应用对应的SDcard里的文件夹里有 ***.jar 等文件,现在明白这些文件大概是用来做应用内自动更新用的。

打比方说,类似eclipse 可以通过预留接口,安装各种插件一样。

  Android 也可以通过动态加载jar 来实现类似的业务代码更新:(这里所说的jar要通过dx工具来转化成Dalvik byte code,下文会讲到)

注意:首先需要了解一点:在Android中可以动态加载,但无法像Java中那样方便动态加载jar

原因:Dalvik虚拟机如同其他Java虚拟机一样,在运行程序时首先需要将对应的类加载到内存中。而在Java标准的虚拟机中,类加载

可以从class文件中读取,也可以是其他形式的二进制流,因此,我们常常利用这一点,在程序运行时手动加载Class,从而达到

代码动态加载执行的目的。
       然而Dalvik虚拟机毕竟不算是标准的Java虚拟机,因此在类加载机制上,它们有相同的地方,也有不同之处。我们必须区别对待

Android的虚拟机(Dalvik VM)是不认识Java打出jar的byte code,需要通过dx工具来优化转换成Dalvik byte code才行。这一点在

咱们Android项目打包的apk中可以看出:引入其他Jar的内容都被打包进了classes.dex。

重点:

DexClassLoader类, 这个可以加载jar/apk/dex,也可以从SD卡中加载。

接口类 IDynamic

实现类 Dynamic (打包成jar的类)

Variable类是用来测试这个里面的testValue 变量经过外部定义的变量在jar里能否访问到

别忘记在AndroidManifest.xml 添加权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

开始上代码:

1.IDynamic

package com.example.test;

import android.content.Context;

public interface IDynamic {
    //预留接口方法
    public void init(Context context);

}

2.Dynamic

package com.example.test;

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

/**
 * 接口实现类,即打包成jar的代码
 * @author yema
 *
 */
public class Dynamic implements IDynamic{

    @Override
    public void init(Context context) {
        // TODO Auto-generated method stub
        Toast.makeText(context, Constant.testValue, Toast.LENGTH_LONG).show();
    }

}

3.Variable

package com.example.test;

public class Variable {

    //用来测试的变量
    public static String testValue = "123456";

}

4.MainActivity

package com.example.test;

import java.io.File;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import dalvik.system.DexClassLoader;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Variable.testValue = "天地不仁,以万物为刍狗";

        TextView click = (TextView) findViewById(R.id.click);
        click.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                LoadClass().init(MainActivity.this);
            }
        });

    }

    /**
     * 加载sdcard 跟目录的test.jar
     * @return IDynamic
     */
    public IDynamic LoadClass(){
        IDynamic lib = null;
        String dexPath = Environment.getExternalStorageDirectory().toString() + File.separator + "test.jar";
        File dexOutputDirs = this.getApplicationContext().getDir("dex", 0); 

        /**
         *
        dexPath    需要装载的APK或者Jar文件的路径。包含多个路径用File.pathSeparator间隔开,在Android上默认是 ":"
        optimizedDirectory    优化后的dex文件存放目录,不能为null
        libraryPath    目标类中使用的C/C++库的列表,每个目录用File.pathSeparator间隔开; 可以为 null
        parent    该类装载器的父装载器,一般用当前执行类的装载器
         */
        DexClassLoader cl = new DexClassLoader(dexPath,dexOutputDirs.getAbsolutePath(),null,this.getClassLoader());
        try {
            Class<?> libProviderClazz = cl.loadClass("com.example.test.Dynamic");
            lib = (IDynamic)libProviderClazz.newInstance();

        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return lib;
    }
}

5.打包并转化成dex

选中Dynamic 类,右键 --> Export --> Jar file

将打包好的jar 拷贝到SDK安装目录android-sdk-windows\platform-tools下,

但是发现现在的SDK这个目录下已经没有dx 文件了,被转移到\build-tools\21.1.1 下

我的目录是:D:\android_sdk\build-tools\21.1.1,这个视个人具体而定,每个人安装的位置不一定一样

接着说,运行Dos cmd命令行进入这个目录

执行命令:

dx --dex --output=dynamic.jar test.jar

完后把test.jar 拷贝到SDcard根目录。

贴MainActivity 加载jar代码

    /**
     * 加载sdcard 跟目录的test.jar
     * @return IDynamic
     */
    public IDynamic LoadClass(){
        IDynamic lib = null;
        String dexPath = Environment.getExternalStorageDirectory().toString() + File.separator + "test.jar";
        File dexOutputDirs = this.getApplicationContext().getDir("dex", 0); 

        /**
         *
        dexPath    需要装载的APK或者Jar文件的路径。包含多个路径用File.pathSeparator间隔开,在Android上默认是 ":"
        optimizedDirectory    优化后的dex文件存放目录,不能为null
        libraryPath    目标类中使用的C/C++库的列表,每个目录用File.pathSeparator间隔开; 可以为 null
        parent    该类装载器的父装载器,一般用当前执行类的装载器
         */
        DexClassLoader cl = new DexClassLoader(dexPath,dexOutputDirs.getAbsolutePath(),null,this.getClassLoader());
        try {
            Class<?> libProviderClazz = cl.loadClass("com.example.test.Dynamic");
            lib = (IDynamic)libProviderClazz.newInstance();

        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return lib;
    }

贴MainActivity 调用jar里init()方法的代码

        Variable.testValue = "天地不仁,以万物为刍狗";

        TextView click = (TextView) findViewById(R.id.click);
        click.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                LoadClass().init(MainActivity.this);
            }
        });

6.运行效果图

运行前:把工程里的 Dynamic.java 文件删除掉,这时便知道代码成功调用到jar里的Dynamic.java 了

"天地不仁,以万物为刍狗" 显示,说明 Variable里的 testValue 变量在jar里是可以被调用到的

参考文章:

Android动态加载jar/dex

时间: 2024-10-11 16:02:29

Android 插件化之动态加载jar的相关文章

携程Android App插件化和动态加载实践

携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实现细节,回顾携程Android App的架构演化过程,期望我们的经验能帮助到更多的Android工程师. 需求驱动 2014年,随着业务发展需要和携程无线部门的拆分,各业务产品模块归属到各业务BU,原有携程无线App开发团队被分为基础框架.酒店.机票.火车票等多个开发团队,从此携程App的开发和发布

类加载器(DexClassLoader)与插件化(动态加载)

类加载器与插件化解析 2.1 类装载器 DexClassLoader 首先,我们需要了解关于java代码本地import的一些知识: import中所引用的类有两个特点: 1.必须存在于本地,当程序运行时需要该类时,内部类装载器会自动装载该类,这对程序员来讲是透明的,即程序员感知不到该过程 2.编译时必须在现场,否则编译过程会因为找不到引用文件而不能正常编译. 使用ClassLoader的必要说明,多用于动态加载一些自定义的类. 一般情况下,应用程序不需要创建一个全新的ClassLoader,而

Android动态加载jar/dex

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

关于Android 动态加载 jar 文件

1.1 首先需要了解一点:在Android中可以动态加载,但无法像Java中那样方便动态加载jar 原因:Android的虚拟机(Dalvik VM)是不认识Java打出jar的byte code,需要通过dx工具来优化转换成Dalvik byte code才行.这一点在咱们Android项目打包的apk中可以看出:引入其他Jar的内容都被打包进了classes.dex. 所以这条路不通,请大家注意. 1.2 当前哪些API可用于动态加载 1.2.1 DexClassLoader 这个可以加载j

Android 插件开发,做成动态加载

为什么需要插件开发: 相信你对Android方法数不能超过65K的限制应该有所耳闻,随着应用程序功能不断的丰富,总有一天你会遇到一个异常: Conversion to Dalvik format failed:Unable toexecute dex: method ID not in [0, 0xffff]: 65536 可能有些同学会说,解决这个问题很简单,我们只需要在Project.proterty中配置一句话就Ok啦, dex.force.jumbo=true 是的,加入了这句话,确实可

Java中动态加载jar文件和class文件

概述 诸如tomcat这样的服务器,在启动的时候会加载应用程序中lib目录下的jar文件以及classes目录下的class文件,另外像spring这类框架,也可以根据指定的路径扫描并加载指定的类文件,这个技术可以实现一个容器,容纳各类不同的子应用. Java类由于需要加载和编译字节码,动态加载class文件较为麻烦,不像C加载动态链接库只要一个文件名就可以搞定,但JDK仍提供了一整套方法来动态加载jar文件和class文件. 动态加载jar文件 // 系统类库路径 File libPath =

Java_Java中动态加载jar文件和class文件

转自:http://blog.csdn.net/mousebaby808/article/details/31788325 概述 诸如tomcat这样的服务器,在启动的时候会加载应用程序中lib目录下的jar文件以及classes目录下的class文件,另外像spring这类框架,也可以根据指定的路径扫描并加载指定的类文件,这个技术可以实现一个容器,容纳各类不同的子应用. Java类由于需要加载和编译字节码,动态加载class文件较为麻烦,不像C加载动态链接库只要一个文件名就可以搞定,但JDK仍

Android之根布局动态加载子布局时边距设置无效问题

Android大部分的控件都会有padding和layout_margin两个属性,一般来说它们的区别是: padding:控件中的内容离控件边缘的距离. margin:  控件离它的父控件边缘的距离. 今天做了一个由根布局动态加载子布局的实验,结果发现子布局中的这两个属性可以按预期的效果显示,但是给根布局设置的padding并没有对被加载的子布局产生效果. 代码如下: 根布局文件名为activity_main.xml,其xml文件定义的内容为: <LinearLayout xmlns:andr

[转载] Java中动态加载jar文件和class文件

转载自http://blog.csdn.net/mousebaby808/article/details/31788325 概述 诸如tomcat这样的服务器,在启动的时候会加载应用程序中lib目录下的jar文件以及classes目录下的class文件,另外像spring这类框架,也可以根据指定的路径扫描并加载指定的类文件,这个技术可以实现一个容器,容纳各类不同的子应用. Java类由于需要加载和编译字节码,动态加载class文件较为麻烦,不像C加载动态链接库只要一个文件名就可以搞定,但JDK仍