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

相關文章
相關標籤/搜索