Android 模块化开发

大兔子大兔子 提交于 2020-01-23 14:01:43

概述

单独开发每个模块,用集成的方式把他们组合起来,拼出一个app。如通用的模块,自动更新的模块,反馈模块,推送模块都可以单独以模块来开发,最后进行集成。我们可以通过一个壳来包含很多个模块。

好处

可以单独升级模块。耦合度低。同时,也很好地解决了“牵一发而动全身”的问题。方便分工。与其他团队合作时,如外包的团队,可以很好的地将核心代码与外包部分隔离开,不用和他们分享核心代码,让他们去做独立的功能,做好直接调用就行。方便以后重构代码,不用担心会改到核心代码。

架构分层

在这里插入图片描述

  • 顶层
    将所有的业务模块聚合在一起,加上配置,形成主应用。一个模块化做得好的应用,主应用都会比较简单且稳定。
  • 中间层
    模块按照功能划分。比如app可以划分为更新、登录、分享、播放等模块。采用aar作为模块的最小单位,之所以选择aar是因为jar不能带资源只能带java代码,library太容易被修改。aar的好处是能带资源并且是编译好的,不能被修改。保证了模块的版本不会在被别人调用的时候随意修改,如果想修改就要联系做aar的人,让他去升级aar的版本。
    在android studio里,用maven打包aar。aar其实就是依赖。
  • 底层:包含基础库和底层库
    (1)基础库:包含所有模块需要的依赖库,以及一些工具类,比如封装了的常用网络请求,封装图片处理fresco,数据库相关等,还包含所有模块需要的依赖库;
    (2)底层库:主要是使用C/C++开发的跨平台的引擎或者库,以so的形式存在。

Android Studio 项目结构

在这里插入图片描述

  • MyApplication 整个项目目录
  • MyApplication/build.gradle是整个项目的gradle构建脚本
  • MyApplication/gradle.properties是整个项目的gradle设置
  • MyApplication/MyApplication.iml是整个项目的配置文件
  • MyApplication/settings.gradle是定义整个项目包含哪些模块
  • app项目中app模块目录
  • app/build/是app模块build编译输出的目录
  • app/app.iml是app模块的配置文件
  • app/.gitignore是app模块的版本管理忽略文件
  • app/build.gradle是app模块的gradle构建脚本
  • app/proguard-rules.pro是app模块的混淆文件
  • External Libraries 项目依赖的Lib,编译时自动下载的

Android Studio 新建的项目自身就是一个模块化项目。因为MyApplication 是整个项目,而app是一个模块。可以在后续自行增加更多的功能模块。

在Android Studio进行模块化开发

1.创建 Module 模块
有两种方式。
方式一:针对已存在的模块,只需要将模块复制到项目的根目录(如上面的MyApplication目录)下即可。这种方式需要在根目录下的setting.gradle文件中设置一下,格式:

include ':projectName'

方式二:直接在project下新建一个Module。操作步骤:

File --> New --> New Module --> Android Library (建议选择这个) --> Finish

这种方式会自动在根目录下的setting.gradle文件中设置。

如:
在这里插入图片描述

在主模块app模块的build.gradle中设置:

dependencies {
...
    implementation project(path: ':modulea')
}

模块中 application 和 library 状态切换配置

组件化插件化是两个不同的概念。插件化作用在“运行时”,而组件化作用在“编译时”。插件化是基于多APK,而组件化本质上只有一个APK。
(1)用一个属性来控制gradle构建插件的切换。 如果我们创建的Module是要作为一个库library来给别的模块使用,那么就应该使用com.android.library这个gradle插件来构建。如果我们Module是一个应用,而不是插件,那么就要使用com.android.application这个gradle插件来构建。我们可以在gradle.properties文件(在根目录下)来配置一些属性,然后在各个Module的build.gradle的构建脚本里就可以根据这属性来判断要使用哪个插件,如:
gradle.properties

# false表示是集成化开发模式,true表示是组件化开发模式
isModule = false

isModule = false:表示这个模块是一个Module(插件);
isModule = true:表示这个模块是一个app(组件);

(2)在模块的build.gradle文件中使用isModule属性。

在modulea模块的build.gradle中使用isModule来判断要使用哪个构建脚本插件:

if(isModule.toBoolean()){
    apply plugin: 'com.android.application'
}else{
    apply plugin: 'com.android.library'
}
android {
...
    defaultConfig {
		...
        // library下删除applicationId
        // 如果是组件就要给一个applicationId
        if(isModule.toBoolean()){
            applicationId "com.wong.modulea"
        }
    }
...
}

(3)提供两套 AndroidManifest.xml并进行动态切换


android {
    ...
    sourceSets {
        main{
            // 应用
            if(isModule.toBoolean()){
                manifest.srcFile 'src/main/buildApp/AndroidManifest.xml'
            }else{// 插件
                manifest.srcFile 'src/main/buildModule/AndroidManifest.xml'
            }
        }
    }
}

(组件)src/main/buildApp/AndroidManifest.xml的内容可能如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.wong.modulea" >
    <application>
        <activity android:name=".WarehouseActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

(插件)src/main/buildModule/AndroidManifest.xml的内容可能如下:
buildModule 的 AndroidManifest.xml, activity 等在这里可以正常注册。这里注册后主程序就可以不用写了。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.wong.modulea">

    <application>
        <activity android:name=".WarehouseActivity"></activity>
    </application>

</manifest>

(4)在app模块的build.gradle配置如下:

dependencies {
    ...
    if(!isModule.toBoolean()){
        implementation project(path: ':modulea')
    }
}

这样就完成了。

Android 模块化开发过程中可能遇到的问题

1.资源名冲突
默认情况, library 的所有的 resource 为 public , 在模块化开发过程中很容易遇到资源冲突问题。两种解决方法:
(1)保护某些 resources 不被外部访问,通过创建res/values/public.xml来完成,至少添加一行,就会被视为 private。

<resources>
    <public name="mylib_app_name" type="string"/>
</resources>

(2)在 library 的 build.gradle 中添加 resourcePrefix , 则所有的资源须以此 prefix 开头,否则报错。注意,图片资源虽然不提示报错误,但是也需要修改名字。

android {
    ...
    buildTypes {
    ...
    }
    resourcePrefix 'my_prefix_'
}

2.依赖重复
解决方法:将所有的依赖都写在library层的module里,将所有的依赖统一一个入口给顶层的app用。

最后送上demo

谢谢阅读

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!