Android 使用动态加载框架DL进行插件化开发

标签: android 动态加载 框架 | 发表时间:2014-10-20 08:06 | 作者:t12x3456
出处:http://blog.csdn.net

如有转载,请声明出处: 时之沙:  http://blog.csdn.net/t12x3456    (来自时之沙的csdn博客)

概述:

        随着应用的不断迭代,应用的体积不断增大,项目越来越臃肿,冗余增加.项目新功能的添加,无法确定与用户匹配性,发生严重异常往往牵一发而动全身,只能紧急发布补丁版本,强制用户进行更新.结果频繁的更新,反而容易降低用户使用黏性.或者是公司业务的不断发展,同系的应用越来越多,传统方式需要通过用户量最大的主项目进行引导下载并安装.

       怎么办?参考浏览器-插件开发模式:

         一. 来可以将自己的应用分拆,某些功能可以在插件中实现,用到时再进行下载,而且不用安装.  如果有新功能的添加,不需要更新应用,只要预留插件管理,我们就可以通过添加插件的方式,动态更新自己的应用,该功能需要改进或扩展,更新插件即可,无需频繁安装或卸载(容易造成用户反感).

        二. 对应同系应用,正常的引流方式只能引导用户进行新应用的下载和安装,如果使用插件化开发,则无需安装应用,关闭插件功能也十分方便,省去应用安装和卸载的过程,可以实现无缝引流.

    这里要向大家推荐一个开源的动态加载框架 DL, 该项目由 singwhatiwanna发起,目前一共有三个人开发,我有幸成为了其中的contributor.

     如果你对DL动态加载框架还不熟悉,建议先看一下这篇文章:

    APK动态加载框架DL解析 http://blog.csdn.net/singwhatiwanna/article/details/39937639

如果你看过之后还会不太清晰,请看下DL插件化框架的全景图,如下


这里我主要向大家介绍一下利用DL框架进行开发的具体步骤:

1. 首先我们需要从github上获取项目代码:

   https://github.com/singwhatiwanna/dynamic-load-apk

   这里我们可以看到下载后的目录如下

 

 

        lib目录就是我们的公共插件库

        sample目录是对应的demo,  具体的工程可以参照上面的DL全景图中的三种模式:

        由于一般项目中,代码管理和开发团队相对独立,  一般插件工程的团队是很难接触主项目团队的代码.因此,这里主要以第一种,也是我们最为推荐的方式进行, 采用插件不依赖宿主的方式进行开发. 不需要两个团队过多的交互,开发效率相对较高.


2 导入lib工程,如下所示:


 


可以看到bin目录下的dl-lib.jar, 如果我们需要对lib工程进行修改,重新build获取对应的dl-lib.jar即可


3. 插件工程的开发, 导入demo中的main-plugin工程

  

    首先还是要强调插件开发的注意事项,以免出现不必要的错误

    插件也需要引用DL的jar包,但是不能放入到插件工程的libs目录下面,换句话说,就是插件编译的时候依赖jar包但是打包成apk的时候不要把jar包打进去,这是因为,dl-lib.jar已经在宿主工程中存在了,如果插件中也有这个jar包,就会发生类链接错误,原因很简单,内存中有两份一样的类,重复了。至于support-v4也是同样的道理。对于eclipse很简单,只需要在插件工程中创建一个目录,比如external-jars,然后把dl-lib.jar和support-v4.jar放进去,同时在.classpath中追加如下两句即可: 

<classpathentry kind="lib" path="external-jars/dl-lib.jar"/>
<classpathentry kind="lib" path="external-jars/android-support-v4.jar"/>
   然后是插件开发中的具体步骤

 (1) 如果原有的为Activity,这里需要改为继承DLBasePluginActivity,如果原来为FragmentActivity,那么需要继承DLBasePluginFragmentActivity, for example:

  

public class MainActivity extends DLBasePluginActivity 
TestFragmentActivity extends DLBasePluginFragmentActivity

 (2) 如果需要插件独立安装运行, 只要将jar放到libs下面即可,若支持动态加载,仍需按上述注意事项加入 exteral-jars中

 (3)插件所需要权限需要在宿主工程中声明

       如果是实际开发,一般为从服务器获取插件,这里我们方便自己调试演示,将运行生成对应的插件apk,放入sd卡上的DynamicLoadHost目录中


4. 宿主工程中将上述生成的dl-lib.jar加入libs即可,如下所示为demo中提供的宿主工程

  

  

    在宿主工程中,首先我们需要获取要调用的插件apk对应的MainActivity,DL的demo中插件路径为 sd卡上的DynamicLoadHost目录,没有的话需要创建,或者根据自己需求进行修改.


        String pluginFolder = Environment.getExternalStorageDirectory() + "/DynamicLoadHost";
        File file = new File(pluginFolder);
        File[] plugins = file.listFiles();
        if (plugins == null || plugins.length == 0) {
            mNoPluginTextView.setVisibility(View.VISIBLE);
            return;
        }

        for (File plugin : plugins) {
            PluginItem item = new PluginItem();
            item.pluginPath = plugin.getAbsolutePath();
            item.packageInfo = DLUtils.getPackageInfo(this, item.pluginPath);
            if (item.packageInfo.activities != null && item.packageInfo.activities.length > 0) {
                item.launcherActivityName = item.packageInfo.activities[0].name;
            }
            mPluginItems.add(item);
        }

接着是调起响应的apk,这时需要使用dl-lib.jar:

  (1)通过Class.forName的方式获取我们需要调用的插件apk中MainActivity的class对象

  (2) 就上面提到的,我们需要判断该对象继承自DLProxActivity还是DLProxFragmentActivity,得到对应的代理class对象

  (3)使用对应的代理class对象调起插件apk

 PluginItem item = mPluginItems.get(position);
        Class<?> proxyCls = null;

        try {
            Class<?> cls = Class.forName(item.launcherActivityName, false,
                    DLClassLoader.getClassLoader(item.pluginPath, getApplicationContext(), getClassLoader()));
            if (cls.asSubclass(DLBasePluginActivity.class) != null) {
                proxyCls = DLProxyActivity.class;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            Toast.makeText(this,
                    "load plugin apk failed, load class " + item.launcherActivityName + " failed.",
                    Toast.LENGTH_SHORT).show();
        } catch (ClassCastException e) {
            // ignored
        } finally {
            if (proxyCls == null) {
                proxyCls = DLProxyFragmentActivity.class;
            }
            Intent intent = new Intent(this, proxyCls);
            intent.putExtra(DLConstants.EXTRA_DEX_PATH,
                    mPluginItems.get(position).pluginPath);
            startActivity(intent);
        }

       最后运行宿主工程 main-host,就可以看到最终的效果:

    



       相信大家经过如上步骤,可以对DL动态加载框架进行开发有了一定了解.目前DL框架仍在不断扩展中,欢迎对我们的项目进行star,fork,或者提出宝贵的建议.,如有问题请及时反馈,我们会在后续版本中进行修复或者改进.


作者:t12x3456 发表于2014-10-20 0:06:28 原文链接
阅读:125 评论:1 查看评论

相关 [android 动态加载 框架] 推荐:

Android 使用动态加载框架DL进行插件化开发

- - CSDN博客移动开发推荐文章
如有转载,请声明出处: 时之沙:  http://blog.csdn.net/t12x3456    (来自时之沙的csdn博客).         随着应用的不断迭代,应用的体积不断增大,项目越来越臃肿,冗余增加.项目新功能的添加,无法确定与用户匹配性,发生严重异常往往牵一发而动全身,只能紧急发布补丁版本,强制用户进行更新.结果频繁的更新,反而容易降低用户使用黏性.或者是公司业务的不断发展,同系的应用越来越多,传统方式需要通过用户量最大的主项目进行引导下载并安装..

美团Android DEX自动拆包及动态加载简介

- - 美团技术团队
作为一个android开发者,在开发应用时,随着业务规模发展到一定程度,不断地加入新功能、添加新的类库,代码在急剧的膨胀,相应的apk包的大小也急剧增加, 那么终有一天,你会不幸遇到这个错误:. 生成的apk在android 2.3或之前的机器上无法安装,提示INSTALL_FAILED_DEXOPT.

Android 动态加载技术三个关键问题详解

- - 移动开发 - ITeye博客
关注微信号:javalearns   随时随地学Java. 动态加载技术(也叫插件化技术)在技术驱动型的公司中扮演着相当重要的角色,当项目越来越庞大的时候,需要通过插件化来减轻应用的内存和CPU占用,还可以实现热插拔,即在不发布新版本的情况下更新某些模块. 动态加载是一项很复杂的技术,这里主要介绍动态加载技术中的三个基础性问题,至于完整的动态加载技术的实现请参考笔者发起的开源插件化框架DL:.

Android插件化(一):使用改进的MultiDex动态加载assets中的apk

- - CSDN博客推荐文章
Android插件化(一):使用改进的MultiDex动态加载assets中的apk. 为了解决65535方法数超标的问题,Google推荐使用MultiDex来加载classes2.dex,classes3.dex等等,其基本思想就是在运行时动态修改ClassLoader,以达到动态加载类的目的.

android应用框架

- - CSDN博客移动开发推荐文章
原文地址:http://developer.android.com/guide/components/fundamentals.html. android应用程序一旦装进设备,每个程序会在它自己安全的沙盒里运行. 1.android操作系统是一个多用户linux系统,每一个应用程序是一个用户. 2.默认情况下,系统会为每个app分配唯一的linux用户id(这个id只会被系统使用,并且只会被这个app知道),系统为每个app的所有文件都设置了权限,只有被分配了这个app用户ID的程序可以访问它.

动态加载HQL

- senyo - BlogJava-首页技术区
Java代码如下:(ReloadableDynamicHibernate.java). 135         private Map qlMap;                //查询的映射. 这样就实现了每次修改SQL or HQL语句后不用重启服务器,立刻看到结果,加快了开发速度.

java动态加载

- - Java - 编程语言 - ITeye博客
第一部分:Java虚拟机启动时,关于类加载方面的一些动作. 当使用java ProgramName.class运行程序时,Java找到JRE,接着找到jvm.dll,把该动态库载入内存,这就是JVM. 然后加载其它动态库, 并激活JVM. JVM激活之后会进行一些初始化工作,之后生成BootstrapLoader,该Class Loader是由C++写的.

一些android开源框架

- - CSDN博客推荐文章
在目前软件开发行业中,流行着这么一句话“天下武功,唯快不破”. 而“快”,就不能让我们重复去制造论坛,不能去重新发明轮子. 目前开源界中已经有很多成熟的,得到了大量商用的开源软件和框架,我们就可以借鉴这有优秀的资源,才能在这个节奏速度的社会中博得一丝生存的机会. 我收集整理了一些优秀的android开源框架,希望能对android软件开发的朋友一点的帮助.

Android 程序框架设计

- - 互联网的那点事
每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心. 通过这种方式,你可以无数次地使用那些已有的解决方案,无需在重复相同的工作. 设计模式是在某种特别的情况下,针对某种问题的某种典型、通用的解决方法. 我们是需要适当了解并学习一些设计模式,在程序开发过程中,总是会涉及到一些框架设计,模块设计之类的东西,如果能很好理解并运行设计模式,你所设计的模块或框架将会要稳定得多,因为这些设计模式它们都是通用的解决方案,是经过实践经验了的.

Android Otto框架浅析

- - CSDN博客移动开发推荐文章
今天要介绍的是一个Android中使用得比较多的android 事件总线 EventBus模式的一个框架Otto. Otto 官网: http://square.github.io/otto/. 一、Android Studio中配置Otto (Eclipse中直接下载jar包导入). 跟之前介绍的其他的框架一样,它只需要简单地在build.gradle中配置下面一行红色字体即可.