在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