[转]Android动态加载jar/dex
本文轉自:http://www.cnblogs.com/over140/archive/2011/11/23/2259367.html
?
前言
在目前的軟硬件環境下,Native App與Web App在用戶體驗上有著明顯的優勢,但在實際項目中有些會因為業務的頻繁變更而頻繁的升級客戶端,造成較差的用戶體驗,而這也恰恰是Web App的優勢。本文對網上Android動態加載jar的資料進行梳理和實踐在這里與大家一起分享,試圖改善頻繁升級這一弊病。
?
聲明
歡迎轉載,但請保留文章原始出處:)?
博客園:http://www.cnblogs.com
農民伯伯: http://over140.cnblogs.com ?Android中文翻譯組:http://androidbox.sinaapp.com/
?
正文
一、 基本概念和注意點
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
這個可以加載jar/apk/dex,也可以從SD卡中加載,也是本文的重點。
1.2.3 PathClassLoader
只能加載已經安裝到Android系統中的apk文件。
?
二、 準備
本文主要參考"四、參考文章"中第一篇文章,補充細節和實踐過程。
2.1 下載開源項目
http://code.google.com/p/goodev-demo
將項目導入工程,工程報錯的話應該是少了gen文件夾,手動添加即可。注意這個例子是從網上下載優化好的jar(已經優化成dex然后再打包成的jar)到本地文件系統,然后再從本地文件系統加載并調用的。本文則直接改成從SD卡加載。
?
三、實踐
3.1 編寫接口和實現
3.1.1 接口IDynamic
package?com.dynamic;public?interface?IDynamic?{
????public?String?helloWorld();
}
? 3.1.2 實現類DynamicTest
package?com.dynamic;public?class?DynamicTest?implements?IDynamic?{
????@Override
????public?String?helloWorld()?{
????????return?"Hello?World!";
????}
}
?
3.2 打包并轉成dex
3.2.1 選中工程,常規流程導出即可,如圖:
注意:在實踐中發現,自己新建一個Java工程然后導出jar是無法使用的,這一點大家可以根據文章一來了解相關原因,也是本文的重點之一。這里打包導出為dynamic.jar
(后期修復:打包請不要把接口文件打進來,參見文章末尾后續維護!)
3.2.2 將打包好的jar拷貝到SDK安裝目錄android-sdk-windows\platform-tools下,DOS進入這個目錄,執行命名:
dx?--dex?--output=test.jar dynamic.jar?
3.3 修改調用例子
修改MainActivity,如下:
@Override????public?void?onCreate(Bundle?savedInstanceState)?{
????????super.onCreate(savedInstanceState);
????????setContentView(R.layout.main);
????????mToastButton?=?(Button)?findViewById(R.id.toast_button);
????????
????????//?Before?the?secondary?dex?file?can?be?processed?by?the?DexClassLoader,
????????//?it?has?to?be?first?copied?from?asset?resource?to?a?storage?location.
//????????final?File?dexInternalStoragePath?=?new?File(getDir("dex",?Context.MODE_PRIVATE),SECONDARY_DEX_NAME);
//????????if?(!dexInternalStoragePath.exists())?{
//????????????mProgressDialog?=?ProgressDialog.show(this,
//????????????????????getResources().getString(R.string.diag_title),?
//????????????????????getResources().getString(R.string.diag_message),?true,?false);
//????????????//?Perform?the?file?copying?in?an?AsyncTask.
//????????????//?從網絡下載需要的dex文件
//????????????(new?PrepareDexTask()).execute(dexInternalStoragePath);
//????????}?else?{
//????????????mToastButton.setEnabled(true);
//????????}
????????
????????mToastButton.setOnClickListener(new?View.OnClickListener()?{
????????????public?void?onClick(View?view)?{
????????????????//?Internal?storage?where?the?DexClassLoader?writes?the?optimized?dex?file?to.
????????????????//final?File?optimizedDexOutputPath?=?getDir("outdex",?Context.MODE_PRIVATE);
????????????????final?File?optimizedDexOutputPath?=?new?File(Environment.getExternalStorageDirectory().toString()
????????????????????+?File.separator?+?"test.jar");
????????????????//?Initialize?the?class?loader?with?the?secondary?dex?file.
//????????????????DexClassLoader?cl?=?new?DexClassLoader(dexInternalStoragePath.getAbsolutePath(),
//????????????????????????optimizedDexOutputPath.getAbsolutePath(),
//????????????????????????null,
//????????????????????????getClassLoader());
????????????????DexClassLoader?cl?=?new?DexClassLoader(optimizedDexOutputPath.getAbsolutePath(),
????????????????????Environment.getExternalStorageDirectory().toString(),?null,?getClassLoader());
????????????????Class?libProviderClazz?=?null;
????????????????
????????????????try?{
????????????????????//?Load?the?library?class?from?the?class?loader.
????????????????????//?載入從網絡上下載的類
//????????????????????libProviderClazz?=?cl.loadClass("com.example.dex.lib.LibraryProvider");
????????????????????libProviderClazz?=?cl.loadClass("com.dynamic.DynamicTest");
????????????????????
????????????????????//?Cast?the?return?object?to?the?library?interface?so?that?the
????????????????????//?caller?can?directly?invoke?methods?in?the?interface.
????????????????????//?Alternatively,?the?caller?can?invoke?methods?through?reflection,
????????????????????//?which?is?more?verbose?and?slow.
????????????????????//LibraryInterface?lib?=?(LibraryInterface)?libProviderClazz.newInstance();
????????????????????IDynamic?lib?=?(IDynamic)libProviderClazz.newInstance();
????????????????????
????????????????????//?Display?the?toast!
????????????????????//lib.showAwesomeToast(view.getContext(),?"hello?世界!");
????????????????????Toast.makeText(MainActivity.this,?lib.helloWorld(),?Toast.LENGTH_SHORT).show();
????????????????}?catch?(Exception?exception)?{
????????????????????//?Handle?exception?gracefully?here.
????????????????????exception.printStackTrace();
????????????????}
????????????}
????????});
????}
?
3.4 執行結果
?
?
四、參考文章
[推薦]在Android中動態載入自定義類
Android app中加載jar插件
關于Android的ClassLoader探索
Android App 如何動態加載類
?
五、補充
大家可以看看DexClassLoader的API文檔,里面不提倡從SD卡加載,不安全。此外,我也正在組織翻譯組盡快把這個命名空間下的幾個類都翻譯出來,以供大家參考。
工程下載:這里,Dex文件下載:這里。大家可以直接把Dex文件拷貝到SD卡,然后運行例子。
?
六、后期維護
6.1 2011-12-1 修復本文錯誤
感謝網友ppp250和liuzhaocn的反饋,基本按照評論2來修改:
6.1.1 不需要在本工程里面導出jar,自己新建一個Java工程然后導出來也行。
6.1.2 導出jar時不能帶接口文件,否則會報以下錯:
? java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
6.1.3 將jar優化時應該重新成jar(jar->dex->jar),如果如下命令:
dx?--dex?--output=test.jar?dynamic.jar?
?
?
6.2 2012-3-29 本文升級版:
Android應用開發提高系列(4)——Android動態加載(上)——加載未安裝APK中的類
請大家參照最新的文章來做動態加載!
?
結束
除了翻譯組的工作和自己本職的工作以外,很難抽時間出來分享一些開發心得,但正所謂擠擠總是有的,歡迎交流!
?
轉載于:https://www.cnblogs.com/freeliver54/archive/2012/06/26/2563051.html
總結
以上是生活随笔為你收集整理的[转]Android动态加载jar/dex的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 两个字有寓意的网名73个
- 下一篇: 水星 MW305R+ V1 无线路由器管