在开发Android App的过程当中,可能希望实现插件式软件架构,将一部分代码以另外一个APK的形式单独发布,而在主程序中加载并执行这个APK中的代码。 实现这个任务的一般方法是:// 加载类clsContext pluginContext = mainContext.createPackageContext(PLUGIN_PKG, Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);ClassLoader loader = pluginContext.getClassLoader();Class> cls = loader.loadClass(CLASS_NAME);// 通过反射技术,调用cls中的方法,下面是一个示例,实际代码因情况而定Object obj = cls.newInstance();Method method = cls.getDeclaredMethod("someMethod");method.invoke(obj); 但是,这个方法在Android 4.1及之后的系统中存在一些问题:对于收费应用,Google Play会将其安装在一个加密目录之下(具体就是/data/app-asec),而不是一个普通目录之下(具体就是/data/app);安装在加密目录中的应用,我们是无法使用上述方法来加载并执行代码的;而实际情况是,我们经常就是依靠插件应用来收费的。 解决上述问题的一个方案是:将插件的二进制代码拷贝到SD卡中,主程序从SD卡中加载并执行其代码。 实现这个任务的具体方法是:Class> cls = null;try { // 尝试第一种方法 cls = loadClass1(mainContext, pkg, entryCls);} catch (Exception e) { // 尝试第二种方法 cls = loadClass2(mainContext, pkg, entryCls);}// 示例代码Object obj = cls.newInstance();Method method = cls.getDeclaredMethod("someMethod");method.invoke(obj);// 第一种加载方法private Class> loadClass1(Context mainContext, String pkg, String entryCls) throws Exception { Context pluginContext = mainContext.createPackageContext(pkg, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); ClassLoader loader = pluginContext.getClassLoader(); return loader.loadClass(entryCls); }//