天天看點

Android動态加載JAR包的實作方法

        有時候我們需要使用動态更新技術,簡單來說就是:當我們把開發jar包發送給使用者後,如果後期更新了部分代碼,這時讓使用者的jar包自動更新,而不是使用者主動手動地去更新的技術就是動态更新。這個需要使用的技術之一就是Android動态加載JAR包。

       主要的過程分為兩步,一個是将需要導出的java檔案導出位jar包,java檔案代碼如下所示:

package adapter;

public class RoutePlanManager {
    
    private String name = "RoutePlanManager";
    public static String get() {
        return "hello world";
    }
}
           

        導出為Hello.jar,這時我們需要使用Android SDK提供的工具(在platform-tools目錄下),有些版本的沒有,可以網上下載下傳。利用dx工具,将java的jar包轉為Android虛拟機可以認識的位元組碼。具體來說,就是執行如下的指令:

dx --dex --output=dex.jar Hello.jar
           

其中,Hello.jar是我們的源jar包,dex.jar是我們用dx工具處理後的jar包,是Android虛拟機可以識别的jar檔案,接下來就可以進行第二步操作了。

這裡,我們需要使用DexClassLoader類實作Jar的動态加載,該類構造方法的官方文檔如下所示:

public DexClassLoader (String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent)

Added in API level 3
Creates a DexClassLoader that finds interpreted and native code. Interpreted classes are found in a set of DEX files contained in Jar or APK files.

The path lists are separated using the character specified by the path.separator system property, which defaults to :.

Parameters
dexPath	the list of jar/apk files containing classes and resources, delimited by File.pathSeparator, which defaults to ":" on Android
optimizedDirectory	directory where optimized dex files should be written; must not be null
libraryPath	the list of directories containing native libraries, delimited by File.pathSeparator; may be null
parent	the parent class loader
           

該接口具有四個參數,第一個是dex.jar包的路徑,第二個可以認為是挂載路徑,就是優化後的dex檔案的存放路徑,對權限有要求,是以需要通過上下文擷取路徑,第三個參數設定為null,第四個代表父親類加載器。

        我們在Android中實作動态加載的代碼如下所示:

String sdcard = Environment.getExternalStorageDirectory().getAbsolutePath();
           String jarPath = sdcard + "/Jar/dex.jar";
           String tmpPath = getApplicationContext().getDir("Jar", 0).getAbsolutePath();
            DexClassLoader cl = new DexClassLoader(jarPath, tmpPath
                    , null, this.getClass().getClassLoader());
            Class<?> libProviderCls = null;
            try {
                  libProviderCls = cl.loadClass("adapter.RoutePlanManager");
                  Constructor<?> localConstructor = libProviderCls.getConstructor(new Class[] {});
                  Object obj = localConstructor.newInstance(new Object[] {});
                  Method mMethodWrite = libProviderCls.getDeclaredMethod("get");
                  mMethodWrite.setAccessible(true);
                  String str = (String) mMethodWrite.invoke(obj);
                  Toast.makeText(LoadJarActivity.this, str, Toast.LENGTH_LONG).show();
            } catch (Exception e) {
                e.printStackTrace();
            }
           

當加載了Jar包之後,我們需要執行Jar包中的方法,這個時候我們需要使用Java的反射來處理。以上就是實作動态加載的方式。