在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