Android组件化初探

Android组件化初探

1. 现状

随着业务增加,代码量急剧增加,大大延长了编译时间,短则3min,长则7、8min;很多同学为节省开发时间,自己新建新的app,完成开发后,再合并到project中;组件化的目的就是为了解耦,将业务模块独立出来,自成一个apk,这样开发期间能提高效率

2. 原理

编译期间动态设置自己业务Module属性(app/library)
在开发期间,只需要编译自己的业务模块代码,并将自己业务模块Module设置app;这样能很大程度上提高编译速度,提高开发效率;在发版期间将自己业务Module设置为libray模式即可

3. 需要解决的问题

  1. 需要在编译期间动态设置自己业务模块属性(app/library)
  2. 开发模式应该存在一个DebugActivity 以作为app启动页;发布模式应该将其忽略不参与打包
  3. 为保证资源不与其他模块存在冲突,应限定自己module所有资源带有指定前缀
  4. 业务模块可能会存在依赖其他业务模块功能,如何实现?
  5. debug模式和发布模式下清单文件应该单独区分
  6. 业务module在运行期间可能会对debug/发布模式做不同操作处理,java代码层如何区分?
  7. 当自己业务模块代码增加时,如何提高开发效率?

4. 实现

4.1 编辑根目录gradle.properties文件

为了能够区分开发模式和发布模式,我们可以在项目根目录gradle.properties文件中添加一个属于自己业务模块变量,以区分是开发模式还是发布模式(下面以module1为样例进行说明)

    #标识MODULE1以app方式启动,发布时可改为false
    MODULE1_IS_APP = true

4.2 编辑settings.gradle文件

让gradle动态指定需要参与编译的module

if(MODULE1_IS_APP.toBoolean()){
    include ':module1', ':framework', ':baseresource'
}else{
    include ':app', ':module1', ':framework', ':baseresource'
}

4.3 编辑moudle1工程中build.gradle文件

为能在编译期间动态设置通通花module是以app还是library需要添加如下代码:

//解决问题1
if (MODULE1_IS_APP.toBoolean()) {
    apply plugin: 'com.android.application'
    //解决问题7,关于如何集成freeline
    //参见(http://blog.csdn.net/dbs1215/article/details/64166592)此处不再阐述请参考
    //apply plugin: 'com.antfortune.freeline'
} else {
    apply plugin: 'com.android.library'
}

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"

        if (MODULE1_IS_APP.toBoolean()) {
            multiDexEnabled true
        }

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    buildTypes.each {
        //解决问题6 代码中可以通过BuildConfig.MODULE1_IS_APP获取
        it.buildConfigField "boolean", "MODULE1_IS_APP", MODULE1_IS_APP
    }

    //解决问题3 (只能做到布局文件,字符串等资源前缀,java类,图片需要自己处理)
    resourcePrefix "module1_"

    sourceSets {
        main {
            //解决2、5问题
            if (MODULE1_IS_APP.toBoolean()) {
                //如果是app启动,使用该清单文件
                manifest.srcFile 'src/main/xml/app/AndroidManifest.xml'

            } else {
                manifest.srcFile 'src/main/xml/library/AndroidManifest.xml'

                java{
                    //debug包不参与打包
                    exclude '**/debug/**'
                }
            }
        }
    }

    configurations {
        all*.exclude group: 'com.android.support', module: 'support-v4'
        all*.exclude group: 'com.android.support', module: 'support-annotations'
    }
}

dependencies {
    //业务module需要依赖的相关库
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile project(':framework')
    compile project(':baseresource')
}

4.4 问题4如何解决?

可以通过依赖注入来实现

  1. 首先可以声明一个接口IDependService
    添加Module1需要依赖其他Module的方法

  2. 在依赖方Module某个路径下实现该接口

  3. 在Module1添加一个类Module1SDK(单例)对象初始化时通过反射实现依赖注入

具体如何实现可以参见末尾代码链接

依然存在的问题

  1. 当自己的业务module1联调依赖于其他业务module功能时,需要以app为主工程启动,耗费时间,暂时没找到别的有效办法
  2. 当自己的业务module1依赖于公共组件/基础模块,但未下沉,无法引用,尴尬。。。。只能通过copy(简单点)/下沉(改动较大)方式来做

思考

  • 如何定义并剥离Module
  • 组件与组件间通讯(Router)

示例工程链接

猜你喜欢

转载自blog.csdn.net/dbs1215/article/details/77932195
今日推荐