1. 程式人生 > >Android動態載入Dex過程

Android動態載入Dex過程

 一、綜述

       Android使用Dalvik虛擬機器載入可執行程式,所以不能直接載入基於class的jar,而是需要將class轉化為dex位元組碼,從而執行程式碼。優化後的位元組碼檔案可以存在一個*.jar中,只要其內部存放的是*.dex即可使用。

       將class的jar包轉化為dex需要用到命令dx(在*\android-sdk\build-tools\version[23.0.1] 或 *\android-sdk\platform-tools下能找到);命令使用方式為:dx --dex --output=output.jar origin.jar,該命令將包含class的origin.jar轉化為包含dex的output.jar檔案。

        Android支援動態載入的兩種方式是:DexClassLoader和PathClassLoader,DexClassLoader可載入jar/apk/dex,且支援從SD卡載入;PathClassLoader據說只能載入已經安裝在Android系統內APK檔案

 PathClassLoader 的限制要更多一些,它只能載入已經安裝到 Android 系統中的 apk 檔案,也就是 /data/app 目錄下的 apk 檔案。其它位置的檔案載入的時候都會出現 ClassNotFoundException. 例如:

PathClassLoader cl = new PathClassLoader(jarFile.toString(), "/data/app/", ClassLoader.getSystemClassLoader());  

二、實驗步驟

假如你已經有一個工程,需要把一些功能程式碼什麼用於動態加載於其他應用上,則可以新建一個module,或者你可以選擇  新建一個Android工程,並進行如下操作:

            2.1 定義一個介面IShowToast.java

/**
 * 動態載入測試介面
 */
public interface IShowToast {
    int showToast(Context context);
}

   2.2 再定義一個簡單實現ShowToastImpl.java

/**
 * 動態載入測試實現
 */
public class ShowToastImpl implements IShowToast {
    @Override
public int showToast(Context context) { Toast.makeText(context, "我來自另一個dex檔案", Toast.LENGTH_LONG).show(); return 100; } }
很簡單輸出一句話,"我來自另一個dex檔案"

整體工程目錄如下:


假如是新建的module,則點選Build--make module,不然點選make Project。


這時會在對應module或者project的build--intermediates--生成classes資料夾,內部結構如下:


好了我們要把IShowToastImpl這個class轉換成Dalvik可識別的dex檔案,分兩步:1.先匯出IShowToastImpl這個類為jar包的形式;2.通過android sdk自帶的dx.jar工具轉換jar包為dex檔案。完成第一步,當時遇到點麻煩,由於eclipse是基於ant並且有視覺化工具,可以直接匯出指定檔案的jar包,但是android studio不行,那怎麼辦呢?我程式執行的效果圖如下:們可以通過gradle task來打包,開啟app目錄下的build.gradle檔案,切記不是根目錄的build.gradle檔案,加上以下程式碼:

(注:假如是新建module,則在該module下的build.gradle下加入程式碼)

//刪除isshowtoast.jar包任務
task clearJar(type: Delete) {
    delete 'libs/ishowtoast.jar'
}
task makeJar(type:org.gradle.api.tasks.bundling.Jar){
    //指定生成的jar名
baseName 'ishowtoast'
//從哪裡打包class檔案
from('build/intermediates/classes/debug/com/example/dexlibs/')
    //打包到jar後的目錄結構
into('com/example/dexlibs/')
    //去掉不需要打包的目錄和檔案
exclude('test/','IShowToast.class','BuildConfig.class','R.class')
    //去掉R$開頭的檔案
exclude{it.name.startsWith('R$')}
}
makeJar.dependsOn(clearJar,build)

開啟AS的 terminal視窗: cd app進入app目錄,執行gradlew makeJar,然後等待直到出現Build Successfully,這時會在build目錄下出現libs/ishowtoast.jar檔案,這個檔案就是我們要用的jar包。

第二步,使用sdk提供的dx.jar將匯出的ishowtoast.jar轉換成Dalvik可識別的dex格式,新版的sdk已經將dx.jar放到build-tools\23.0.2\lib目錄下,我們在dos下或者在Android studio terminal下面進入到此目錄,然後執行下面的命令:(備註;請把ishowtoast.jar複製到C:\Android\android-sdk-windows\build-tools\23.0.2目錄下,不然會提示找不到該檔案)

output是你的輸出目錄,預設就是在當前的根目錄下,執行完成後我們就在當前目錄下生成了Davilk虛擬機器可執行的dex檔案,因為這條命令同時會打包dex檔案,因此後綴是jar,如圖所示,生成了ishowtoast_dex的jar檔案,右鍵使用WinRaR即可看到有class.dex檔案



接著我們再新建一個專案,準備動態載入剛才的ishowtoast_dex的jar檔案。


務必要注意,需要複製過來的介面IShowToast所在的包名需要跟前一個app一樣,不然會報錯

fileUtils是一個工具類,用於讀取sssets中我們複製過來的那個ishowtoast_dex的jar檔案,上圖所示,下圖則是具體fileUtils的程式碼

/**
 * 將assets檔案copy到app/data/cache目錄
 */
public class FileUtils {
    public static void copyFiles(Context context, String fileName, File desFile){
        InputStream in=null;
OutputStream out=null;
        try {
            in=context.getApplicationContext().getAssets().open(fileName);
out=new FileOutputStream(desFile.getAbsolutePath());
            byte[] bytes=new byte[1024];
            int len=0;
            while ((len=in.read(bytes))!=-1)
                out.write(bytes,0,len);
out.flush();
} catch (IOException e) {
            e.printStackTrace();
}finally {
            try {
                if (in!=null)
                    in.close();
                if (out!=null)
                    out.close();
} catch (IOException e) {
                e.printStackTrace();
}
        }
    }
}

開啟MainActivity:

public class MainActivity extends AppCompatActivity {

    @Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//  //新增一個點選事件
findViewById(R.id.tv_click).setOnClickListener(new View.OnClickListener() {
            @Override
public void onClick(View v) {
                loadDexClass();
}
        });
}
    /**
     * 載入dex檔案中的class,並呼叫其中的showToast方法
     */
private void loadDexClass() {
        File cacheFile = getDir("dex",0);
String internalPath = cacheFile.getAbsolutePath() + File.separator + "ishowtoast_dex.jar";
File desFile=new File(internalPath);
        try {
            if (!desFile.exists()) {
                desFile.createNewFile();
FileUtils.copyFiles(this,"ishowtoast_dex.jar",desFile);
}
        } catch (IOException e) {
            e.printStackTrace();
}

        //下面開始載入dex class
        //1.待載入的dex檔案路徑,如果是外存路徑,一定要加上讀外存檔案的許可權,
        //2.解壓後的dex存放位置,此位置一定要是可讀寫且僅該應用可讀寫
        //3.指向包含本地庫(so)的資料夾路徑,可以設為null
        //4.父級類載入器,一般可以通過Context.getClassLoader獲取到,也可以通過ClassLoader.getSystemClassLoader()取到。
DexClassLoader dexClassLoader=new DexClassLoader(internalPath,cacheFile.getAbsolutePath(),null,getClassLoader());
        try {
            //該name就是internalPath路徑下的dex檔案裡面的ShowToastImpl這個類的包名+類名
Class<?> clz = dexClassLoader.loadClass("com.example.dexlibs.ShowToastImpl");
IShowToast impl= (IShowToast) clz.newInstance();//通過該方法得到IShowToast類
if (impl!=null)
                impl.showToast(this);//呼叫開啟彈窗
} catch (Exception e) {
            e.printStackTrace();
}
    }
}

程式執行的效果圖如下:



動圖不好搞,mp4轉gif還要下格式工廠,所以就用圖片代替了

至此,我們關於Android Dex動態載入機制的過程就結束了。

Demo原始碼地址:https://download.csdn.net/download/a2923790861/10452976

相關推薦

Android動態載入Dex過程

 一、綜述       Android使用Dalvik虛擬機器載入可執行程式,所以不能直接載入基於class的jar,而是需要將class轉化為dex位元組碼,從而執行程式碼。優化後的位元組碼檔案可以存在一個*.jar中,只要其內部存放的是*.dex即可使用。       將

Android 動態載入dex

為什麼要學習這個,動態載入dex,因為學習android外掛化必須要了解這個才行。   Android使用Dalvik虛擬機器載入可執行程式,所以不能直接載入基於class的jar,而是需要將class轉化為dex位元組碼,從而執行程式碼。優化後的位元組碼檔案可以存在一個*

Android動態載入dex技術初探

     今天不忙,研究了下Android動態載入dex的技術,主要參考:            1、http://www.cnblogs.com/over140/archive/2011/11/23/2259367.html             2、http://ww

Android應用安全之外部動態載入DEX檔案風險

1. 外部動態載入DEX檔案風險描述 Android 系統提供了一種類載入器DexClassLoader,其可以在執行時動態載入並解釋執行包含在JAR或APK檔案內的DEX檔案。外部動態載入DEX檔案的安全風險源於:Anroid4.1之前的系統版本容許Android應用將動態載入的DEX檔案儲存

關於apk加殼之動態載入dex檔案

由於自己之前做了一個關於手機令牌的APK軟體,在實現的過程中儘管使用了native so進行一定的邏輯演算法保護,但是在自己逆向破解的過程中發現我的手機令牌關鍵資料能夠“輕易地”暴露出來,所以我就想進一步的對其進行加固。於是,我使用的網上常用的梆梆加固、愛加密和阿里的聚安全應用來對我的apk進行一個

Sql server動態載入儲存過程--分頁

create procedure [dbo].[pro_getStu] ( @pindex int,  --最小是1,第1頁 @psize int, @name nvarchar, @dbcount int&n

Android 動態載入sd卡里面so庫

有些so檔案太大,可以從手機記憶體或者sd卡里面拷貝到執行的應用程式裡面。介面都是之前打包在裡面了。還可以做so更新,就是把之前拷貝進行刪除,然後進行不重新打包apk,進行重新拷貝進去。 1,封裝好的類 package com.rtcmdemo.until; impor

Android動態載入基礎 ClassLoader工作機制

基本資訊 類載入器ClassLoader 早期使用過Eclipse等Java編寫的軟體的同學可能比較熟悉,Eclipse可以載入許多第三方的外掛(或者叫擴充套件),這就是動態載入。這些外掛大多是一些Jar包,而使用外掛其實就是動態載入Jar包裡的Class進行工作。這其實

Android動態載入輪播圖BannerView

輪播圖在每個app中扮演著一個點綴的角色,在獨立做了三款app後都有這個需求,所以我決定把它單獨抽出來。以後只需copy,然後再根據需求改一下即可。 /** * 載入網路輪播圖 *@author jiangrongtao * *csdn

Android動態載入Activity原理

activity的啟動流程 載入一個Activity肯定不會像載入一般的類那樣,因為activity作為系統的元件有自己的生命週期,有系統的很多回調控制,所以自定義一個DexClassLoader類載入器來載入外掛中的Activity肯定是不可以的。 首先不得不瞭解一下ac

Android動態載入入坑指南

private static Element[] makeDexElements(List<File> files, File optimizedDirectory, List<IOException&g

Android動態載入Jar

定義介面, 把實現介面的部分打包成jar 在 將打包好的jar拷貝到SDK安裝目錄android-sdk-windows\platform-tools下,DOS進入這個目錄,執行命名: dx --dex --output=test.jar update.jar 核心載入

Android 動態載入佈局檔案

本文轉自:原文地址 Android的基本UI介面一般都是在xml檔案中定義好,然後通過activity的setContentView來顯示在介面上,這是Android UI的最簡單的構建方式。其實,為了實現更加複雜和更加靈活的UI介面,往往需要動態生成UI介面,甚至根

Android 動態載入二維碼檢視生成快照

1.需求背景 需要實現一個動態載入但不顯示出來的檢視,且該檢視上有個動態生成的二維碼,最後用其去生成一張快照(也就是圖片)。 (常見這種情況是來源於“圖片分享”的功能需求,與普通圖片分享不同在於,該快照圖片是動態載入不顯示的。) 2.需求功能拆解 動態二維碼的實現動態檢

android 動態載入sd卡的jar檔案

下面以一個例子列出Android程式執行時動態載入sd卡jar包的步驟: 1. 首先要準備好jar包。 本例中要對com.test.dynamic包進行打包,com.test.dynamic包下面有一個MyClass類.程式碼如下: package com.test.dynamic;   impo

android動態載入外部類

基本資訊  我們很早開始就在Android專案中採用了動態載入技術,主要目的是為了達到讓使用者不用重新安裝APK就能升級應用的功能,這樣一來不但可以大大提高應用新版本的覆蓋率,也減少了伺服器對舊版本介面相容的壓力,同時如果也可以快速修復一些線上的BUG。  這種技術並

Android動態載入jar檔案

這裡用個例子來演示,具體流程是用Android Studio建一個Android專案並編寫相應程式碼,然後用Eclipse編寫一個java程式碼並打成jar包,再轉換成Android能識別的dexjar包,最後先安裝好APP,然後把jar包放到APP目錄下,ap

【收藏】Android動態載入classLoader工作機制 & QQ空間熱補丁hotFix原理

收藏一下             Android動態載入classLoader工作機制:https://segmentfault.com/a/1190000004062880 &nb

Android-動態載入外掛化的兩種實現方式(二):介面

上一篇部落格中http://blog.csdn.net/lxping51/article/details/71480239,主要通過反射的方式來實現動態載入外掛化,今天我們以介面的方式來達到目的。介面的實現比反射更為簡單,而且直接呼叫對效能有很大的提高。但是這也

ANDROID動態載入 使用SO庫時要注意的一些問題

基本資訊 Android專案裡的SO庫 正好動態載入系列文章談到了載入SO庫的地方,我覺得這裡可以順便談談使用SO庫時需要注意的一些問題。或許這些問題對於經常和SO庫開發打交道的同學來說已經是老生長談,但是既然要討論一整個動態載入系列,我想還是有必要說說使用SO庫時的一些問題。 在專案裡使用SO庫非常簡