日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

DexClassLoader的使用

發布時間:2023/12/4 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 DexClassLoader的使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
版權聲明:您好,轉載請留下本人博客的地址,謝謝 https://blog.csdn.net/hongbochen1223/article/details/47146613

在Java環境中,有個概念叫做”類裝載器(Class Loader)”,其作用是動態加載Class文件.標準的Java SDK中有一個ClassLoader類,借助他可以裝載想要的Class文件,每個ClassLoader對象在初始化的時候必須指定Class文件的路徑.

但我們在使用java的時候,基本上沒有使用過ClassLoader,僅僅使用import就可以加載類文件了,簡單的講,import中所引用的類文件有兩個特點:

1:必須存在于本地,當程序運行需要該類的時候,內部類裝載器會自動裝載該類,這對程序員來說是透明的,即程序員感知不到該過程
2:編譯時必須在現場,否則編譯過程會因找不到引用文件而不能正常編譯.

但在有些情況下,所需要的類卻不能滿足以上兩個條件.比如當該類是從遠程下載并在本地執行的時候,典型的例子就是通過瀏覽器中的AppletLet執行的java程序,這些要執行的程序是在服務器端.另一種情況是,要引用的Class文件不方便在編譯的時候直接參與,而只能在運行時動態調用.例如,在Android Framework中,所包含的Class文件是一些通用的類文件,但對于一些設備商而言,他們需要擴充Framework,擴充的具體工作包括兩點:

1:需要增加一些額外的類文件,這些類文件提供廠商自定義的功能,這些文件一般以獨立的jar包存在

2:需要修改Framework中的已有的類文件,比如WindowManagerService類,在該類中添加使用自定義jar包中的代碼.使用自定義jar常用的方法是使用import關鍵字包含自定義的類,但為了保持和原生Framework的兼容性,對原聲Framework最少化修改,可以使類裝載器動態裝載自定義jar包.

這就是使用ClassLoader的原因.

在一般情況下,應用程序不需要創建一個全新的ClassLoader對象,而是使用當前環境已經存在的ClassLoader.因為java的Runtime環境在初始化時,其內部會創建一個ClassLoader對象用于加載Runtime所需的各種java類.

每個ClassLoader必須有一個父ClasLoader,在裝載Class文件的時候,子ClassLoader會先請求其父ClassLoader加載該Class文件,只有當其父ClassLoader找不到該Class的時候,子ClassLoader才會急促裝載該類,這是一種安全機制.

對于Android的應用程序,本質上雖然也是用Java開發,并且使用標準的Java編譯器編譯出Class文件,但最終的APK文件中包含的確實dex類型的文件.dex文件是將所需的所有Class文件重新打包,打包的規則不是簡單的壓縮,而是完全對Class文件內部的各種函數表,變量表等進行優化,并產生一個新的文件,這就是dex文件.由于dex文件是一種經過優化的Class文件,因此要加載這樣特殊的Class文件就需要特殊的類裝載器,這就是DexClassLoader.Android SDK中提供了DexClassLoader類就是處于這個目的.

下面我們就來看一下DexClassLoader的調用.

首先我們新建一個Android Project,命名為Plugin.我們的包名設置為:
com.chen.plugin

在我們的包com.chen.plugin中創建一個activity,這個隨便創建,我們用不到這個,該activity的用處僅僅就是用于啟動android程序的.

在包com.chen.plugin中創建一個新的class,命名為PluginClass.

在類PluginClass中我們添加一個函數,名稱為function1(int a,int b).

看一下我們的代碼:

package com.chen.plugin;import android.util.Log;public class PluginClass {public PluginClass(){Log.e("Plugin","PluginClass client initialized");}public int function1(int a,int b){return a+b;} }

然后運行我們這個項目,在手機中安裝.

第二步,我們創建一個新的Android Project,命名為Host.同樣創建一個新的Activity.

在MainActivity中添加一個方法,useDexClassLoader(),下面看一下這個方法的具體實現.

public void useDexClassLoader(){Intent intent = new Intent(Intent.ACTION_MAIN,null);intent.addCategory(Intent.CATEGORY_LAUNCHER); PackageManager pm = getPackageManager();final List<ResolveInfo> plugins = pm.queryIntentActivities(intent, 0);ResolveInfo rinfo = null;if(plugins != null){for(int i = 0;i < plugins.size();i++){ResolveInfo r = plugins.get(i);ActivityInfo ainfo = r.activityInfo;String div = System.getProperty("path.seperator");String packageName = ainfo.packageName;if(packageName.equals("com.chen.plugin")){rinfo = plugins.get(i);}}}ActivityInfo ainfo = rinfo.activityInfo;String div = System.getProperty("path.seperator");String packageName = ainfo.packageName;String dexPath = ainfo.applicationInfo.sourceDir;String dexOutputDir = getApplicationInfo().dataDir;String libPath = ainfo.applicationInfo.nativeLibraryDir;DexClassLoader cl = new DexClassLoader(dexPath, dexOutputDir, libPath, this.getClass().getClassLoader());try{Class<?> clazz = cl.loadClass(packageName+".PluginClass");Object obj = clazz.newInstance();Class[] params = new Class[2];params[0] = Integer.TYPE;params[1] = Integer.TYPE;Method action = clazz.getMethod("function1", params);Integer ret = (Integer)action.invoke(obj, 12,34);Log.e("Host","return value is"+ret);}catch(Exception e){Log.e("errpr",e.getMessage());}}

在我們的MainActivity的OnCreate()方法中調用該方法,然后在手機中運行Host,就可以看到我們的調試信息.

我們先來看一下結果:

很明顯,Plugin中的函數在Host中被調用了.

下面我們看一下DexClassLoader構造函數的參數的意義:

  • 1:dexPath,指目標類所在的APK或jar文件的路徑.類裝載器將從該路徑中尋找指定的目標類,該類必須是APK或jar的全路徑.如果要包含多個路徑,路徑之間必須使用特定的分割符分隔,特定的分割符可以使用System.getProperty(“path.separtor”)獲得.
  • 2:dexOutputDir,由于dex文件被包含在APK或者Jar文件中,因此在裝載目標類之前需要先從APK或Jar文件中解壓出dex文件,該參數就是制定解壓出的dex 文件存放的路徑.在Android系統中,一個應用程序一般對應一個Linux用戶id,應用程序僅對屬于自己的數據目錄路徑有寫的權限,因此,該參數可以使用該程序的數據路徑.
  • 3:libPath,指目標類中所使用的C/C++庫存放的路徑
  • 4:最后一個參數是指該裝載器的父裝載器,一般為當前執行類的裝載器

創建了DexClassLoader對象之后,就可以調用loadClass()來裝載指定的類了.該函數返回的是一個Class對象,注意區分Class對象和目標類PluginClass對象,Class對象是ClassLoader所能識別的類,而PluginClass是程序執行后所能識別的類,此時僅僅裝載了PluginClasss的程序代碼,但是還沒有創建 PluginClass對象,因此接下來調用Class對象的newInstance()方法,該方法內部會調用PluginClass的構造函數,并返回i一個真正的PluginClass對象.

雖然生成了PluginClass對象,但是Host本地并沒有其函數,所以只能使用反射機制來調用PluginClass的方法.

關于反射機制,后面文章中會有更加詳細的使用方式.

總結

以上是生活随笔為你收集整理的DexClassLoader的使用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。