ClassLoader使用經驗(一)

  在Android開發中,有時,會須要在應用中額外下載一些其餘的插件,進行額外的功能。好比QQ的皮膚,掌閱的語音包,須要在使用過程當中下載額外的apk,可是額外的apk無需安裝咱們便可使用裏面的資源和方法。這樣的功能就是用ClassLoader實現的。在此記錄一些ClassLoader的使用方法與經驗用以備忘。android

  這裏要實現的例子很簡單。我在一個額外的工程B中實現一個Toast的方法,而後用工程A中的類去調用這個方法。app

  首先來看看工程B:this

  工程B中我先實現了一個簡單的類spa

public class ToastClass {

    public void alertMessage(Context context , String str){
        Toast.makeText(context , str , Toast.LENGTH_SHORT ).show();
    }

}

 

  等會在工程A中傳入上下文和要顯示的內容便可彈出一個toast窗。插件

  可是,並非任何apk中的內咱們都能隨意調用,咱們首先要作一個協定。協定的方式是action,咱們在AndroidManifest中的MainActivity的Intent-Filter中加入如下一行code

<action android:name="com.dream.fishbonelsy.blurtestdemo"/>

  這樣,工程A就以此爲憑據調用工程B中的類和方法。blog

  下面在工程A中,使用ClassLoader來獲取這個apk資源

  

        // 獲取APK
        Intent intent = new Intent("com.dream.fishbonelsy.blurtestdemo" , null);
        // 獲取包管理器
        PackageManager packageManager = context.getPackageManager();
        List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, 0);
        // 得到指定的activity的信息
        ActivityInfo activityInfo = resolveInfos.get(0).activityInfo;
        // 得到包名
        String packageName = activityInfo.packageName;
        // 得到apk目錄
        String apkPath = activityInfo.applicationInfo.sourceDir;
        //dex解壓後的目錄,注意,這個用宿主程序的目錄,android中只容許程序讀取寫本身
        //目錄下的文件
        String dexOutputDir = context.getApplicationInfo().dataDir;
        //native代碼的目錄
        String libPath = activityInfo.applicationInfo.nativeLibraryDir;
        //建立類加載器,把dex加載到虛擬機中
        DexClassLoader calssLoader = new DexClassLoader(apkPath, dexOutputDir, libPath,
                this.getClass().getClassLoader());

 

  這裏經過包管理器和工程B的action得到一系列須要的信息:apk目錄,文件目錄,native代碼錄目,包名。開發

  獲取了包名以後,若是咱們知道類名和方法名就能夠直接調用了。get

  

//利用反射調用插件包內的類的方法

        try {
            Class<?> clazz = calssLoader.loadClass(packageName+".ToastClass");

            Object obj = clazz.newInstance();
            Class[] param = new Class[2];
            param[0] = Context.class;
            param[1] = String.class;
            Method method = clazz.getMethod("alertMessage", param);
            method.invoke(obj,context , "hello android");

            Log.i("Host", "return result is " );

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

  經過反射,咱們便可調用工程B中的方法。

 

Done

相關文章
相關標籤/搜索