Android 外掛程式化之動態載入jar

來源:互聯網
上載者:User

標籤:

有時候會看到一些應用對應的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

Android 外掛程式化之動態載入jar

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.