Android 插件化之动态加载jar

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

打比方说,相似eclipse 能够经过预留接口,安装各类插件同样。java

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

注意:首先须要了解一点:在Android中能够动态加载,但没法像Java中那样方便动态加载jargit

缘由:Dalvik虚拟机如同其余Java虚拟机同样,在运行程序时首先须要将对应的类加载到内存中。而在Java标准的虚拟机中,类加载github

能够从class文件中读取,也能够是其余形式的二进制流,所以,咱们经常利用这一点,在程序运行时手动加载Class,从而达到windows

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

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

我们Android项目打包的apk中能够看出:引入其余Jar的内容都被打包进了classes.dex。ide

 

 

重点:工具

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里是能够被调用到的

 

欢迎 Star Fork

demo 地址:https://github.com/yemahuang/Dynamic_jar

 

参考文章:

Android动态加载jar/dex

相关文章
相关标签/搜索