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