随着app迭代,以及功能需求的升级,项目中的冗余代码量增多,代码各板块间的耦合加强,不利于升级以及测试,所以开始了组建化的设计。
android的组件化基于module的两种属性
application属性,module可以作为独立的app运行apply plugin: ‘com.android.application’
library属性,module不可独立运行,作为依赖库文件apply plugin: ‘com.android.library’
通过控制module的此属性可以间module在app以及依赖库之间进行切换,此属性在build.gradle文件中。
而且项目的gradle文件是可以公用的,所以可以新建一个config.gradle文件进行对module以及少量依赖进行配置。
/** * 全局统一配置文件 */ext { //true 每个业务Module可以单独开发 //false 每个业务Module以lib的方式运行 //修改之后需要Sync方可生效 isModule = false //版本号 versions = [ applicationId : "com.example.bwq.moduletest", //应用ID versionCode : 1, //版本号 versionName : "1.0.0", //版本名称 compileSdkVersion : 28, buildToolsVersion : "27.0.3", minSdkVersion : 16, targetSdkVersion : 28, androidSupportSdkVersion: "28.+", constraintLayoutVersion : "1.1.3", runnerVersion : "1.0.2", espressoVersion : "3.0.2", junitVersion : "4.12", multidexVersion : "1.0.2", butterknifeVersion : "8.8.1", arouterApiVersion : "1.4.0", arouterCompilerVersion : "1.2.1", arouterannotationVersion: "1.0.4", recyclerview : "28.+", cardview : "28.+", //三方依赖的版本控制 ] dependencies = ["appcompat_v7" : "com.android.support:appcompat-v7:${versions["androidSupportSdkVersion"]}", "constraint_layout" : "com.android.support.constraint:constraint-layout:${versions["constraintLayoutVersion"]}", "runner" : "com.android.support.test:runner:${versions["runnerVersion"]}", "espresso_core" : "com.android.support.test.espresso:espresso-core:${versions["espressoVersion"]}", "junit" : "junit:junit:${versions["junitVersion"]}", "support_annotations" : "com.android.support:support-annotations:${versions["annotationsVersion"]}", "design" : "com.android.support:design:${versions["androidSupportSdkVersion"]}", "support-v4" : "com.android.support:support-v4:${versions["androidSupportSdkVersion"]}", "cardview-v7" : "com.android.support:cardview-v7:${versions["androidSupportSdkVersion"]}", "recyclerview-v7" : "com.android.support:recyclerview-v7:${versions["androidSupportSdkVersion"]}", //方法数超过65535处理方法64K MultiDex分包方法 "multidex" : "com.android.support:multidex:${versions["multidexVersion"]}", //路由 "arouter_api" : "com.alibaba:arouter-api:${versions["arouterApiVersion"]}", "arouter_compiler" : "com.alibaba:arouter-compiler:${versions["arouterCompilerVersion"]}", "arouter_annotation" : "com.alibaba:arouter-annotation:${versions["arouterannotationVersion"]}", //黄油刀 "butterknife_compiler": "com.jakewharton:butterknife-compiler:${versions["butterknifeVersion"]}", "butterknife" : "com.jakewharton:butterknife:${versions["butterknifeVersion"]}", recyclerview : "com.android.support:recyclerview-v7:${versions["recyclerview"]}", cardview : "com.android.support:cardview-v7:${versions["cardview"]}", //三方依赖的库地址 ]}
其中isModule为控制module为组建模式还是app模式的开关
因而组建module的属性可通过开关来判断,在组建build.gradle文件开头设置为如下:
if (Boolean.valueOf(rootProject.ext.isModule)) { apply plugin: 'com.android.application'} else { apply plugin: 'com.android.library'}
在组建化中我将app分为三层,
第一层:app层
app入口,初始化页面,以及主页通过在主页viewpager中增加fragment使其成为正常app的主页。
第二层:组建层
将项目按功能划分为各个组建,如登录组建,首页组建,我的组建等,组建间通过路由的方式跳转以及传递数据。
第三层:基础层
项目基础层,公用控件,公用的方法资源文件,网络请求方法,以及依赖库的封装都在这层进行实现。
组建层以及app层的每一个module均依赖基础层,app层依赖每一个组建层以及基础层。
基础层中将在配置文件中的依赖方法,进行依赖,基础层不需要成为app独立运行,因而无需设置application以及library的开关,依赖关键字使用api:
apply plugin: 'com.android.library'apply plugin: 'com.jakewharton.butterknife'android { compileSdkVersion rootProject.ext.versions.compileSdkVersion buildToolsVersion rootProject.ext.versions.buildToolsVersion defaultConfig { minSdkVersion rootProject.ext.versions.minSdkVersion targetSdkVersion rootProject.ext.versions.targetSdkVersion versionCode rootProject.ext.versions.versionCode versionName rootProject.ext.versions.versionName testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" //MultiDex分包方法 multiDexEnabled true //Arouter路由配置 javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName()] includeCompileClasspath = true } } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }}dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') //把implementation 用api代替,它是对外部公开的, 所有其余的module就不需要增加该依赖 api rootProject.ext.dependencies["appcompat_v7"] api rootProject.ext.dependencies["constraint_layout"] api rootProject.ext.dependencies["cardview-v7"] api rootProject.ext.dependencies["recyclerview-v7"] api rootProject.ext.dependencies["support-v4"] api rootProject.ext.dependencies["design"] api rootProject.ext.dependencies["support_annotations"] //MultiDex分包方法 api rootProject.ext.dependencies["multidex"] //黄油刀 annotationProcessor rootProject.ext.dependencies["butterknife_compiler"] api rootProject.ext.dependencies["butterknife"] //Arouter路由 annotationProcessor rootProject.ext.dependencies["arouter_compiler"] api rootProject.ext.dependencies["arouter_api"] api rootProject.ext.dependencies["arouter_annotation"] api rootProject.ext.dependencies["recyclerview"] api rootProject.ext.dependencies["cardview"] }
第二层中因每个组建均需要成为独立app进行测试以及开发,因而,他的manifest文件需要两套,一套为普通library的没有app入口,一套为application的有app入口的文件。
新建module,选择phone&table module,建立标准app module,main包下新建路径manifest放置module作为app时的manifest文件
黄色框为新建文件夹以及新建文件:
manifest配置为基础app配置
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.bwq.main"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/MyAppTheme" android:name=".debug.MainApplication"> <activity android:name=".debug.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application></manifest>
红色框中的manifest文件为library时的
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.bwq.main"> <application> <activity android:name=".debug.MainActivity"/> </application></manifest>
在java中新建debug包,放置少量作为独立app时的配置,如继承自基础层的Application类,假如组建入口为fragment时展现fragment的activity,之后在当前module的builde.gradle中配置
if (Boolean.valueOf(rootProject.ext.isModule)) { apply plugin: 'com.android.application'} else { apply plugin: 'com.android.library'}apply plugin: 'com.jakewharton.butterknife'android { compileSdkVersion rootProject.ext.versions.compileSdkVersion buildToolsVersion rootProject.ext.versions.buildToolsVersion defaultConfig { if (Boolean.valueOf(rootProject.ext.isModule)) applicationId rootProject.ext.versions.applicationId minSdkVersion rootProject.ext.versions.minSdkVersion targetSdkVersion rootProject.ext.versions.targetSdkVersion versionCode rootProject.ext.versions.versionCode versionName rootProject.ext.versions.versionName testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" //MultiDex分包方法 multiDexEnabled true //Arouter路由配置 javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName()] includeCompileClasspath = true } } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets { //配置当前module作为app和作为library时的manifest文件以及作为library时所需要忽略的文件 main { if (Boolean.valueOf(rootProject.ext.isModule)) { manifest.srcFile 'src/main/manifest/AndroidManifest.xml' } else { manifest.srcFile 'src/main/AndroidManifest.xml' java { exclude '*debug/**' exclude '*manifest/**' } } } }}dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) //butterKnife implementation 'com.android.support.constraint:constraint-layout:1.1.3' annotationProcessor rootProject.ext.dependencies["butterknife_compiler"] annotationProcessor rootProject.ext.dependencies["arouter_compiler"] api project(':basis_library')}
为了方便组建间的跳转,在基础层中BaseApplication类中初始化路由,BaseApplication为所有组建以及app的Application类的基类。
/** * 初始化ARouter */ public void initARouter() { if (BuildConfig.DEBUG) { ARouter.openLog(); ARouter.openDebug(); } ARouter.init(instance); }
添加组建化后的跳转工具类
public class ARouterUtils { /** * 根据path返回Fragment * * @param path path * @return fragment */ public static BaseLazyFragment getLazyFragment(String path) { return (BaseLazyFragment) ARouter.getInstance() .build(path) .navigation(); } public static BaseFragment getFragment(String path) { return (BaseFragment) ARouter.getInstance() .build(path) .navigation(); } /** * 根据path返回Activity * * @param path path * @return Activity */ public static BaseActivity getActivity(String path) { return (BaseActivity) ARouter.getInstance() .build(path) .navigation(); } /** * 根据path返回FragmentActivity * * @param path path * @return FragmentActivity */ public static BaseFragmentActivity getFragmentActivity(String path) { return (BaseFragmentActivity) ARouter.getInstance() .build(path) .navigation(); }}
路由跳转URL地址
/** * 功能板块入口 */public interface ARouterConfig { /** * 登录页面 */ String LOGIN = "/login/LoginActivity"; /** * main */ String MAIN = "/main/MainFragment"; /** * mine */ String MINE = "/mine/MineFragment";}
app层:
builde.gradle配置:
apply plugin: 'com.android.application'apply plugin: 'com.jakewharton.butterknife'android { compileSdkVersion rootProject.ext.versions.compileSdkVersion buildToolsVersion rootProject.ext.versions.buildToolsVersion defaultConfig { applicationId rootProject.ext.versions.applicationId minSdkVersion rootProject.ext.versions.minSdkVersion targetSdkVersion rootProject.ext.versions.targetSdkVersion versionCode rootProject.ext.versions.versionCode versionName rootProject.ext.versions.versionName testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" //MultiDex分包方法 multiDexEnabled true //Arouter路由配置 javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName()] includeCompileClasspath = true } } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }}dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support.constraint:constraint-layout:1.1.3' annotationProcessor rootProject.ext.dependencies["butterknife_compiler"] annotationProcessor rootProject.ext.dependencies["arouter_compiler"] api project(':basis_library') if (!Boolean.valueOf(rootProject.ext.isModule)) { api project(':main') api project(':login') api project(':mine') }}
至此,组建化方案完成。
最后说少量注意的问题,各层的依赖关键字需要使用api,不同组建间的资源文件因为在组合后可能会有冲突,各组建间的资源文件建议以组建名开头,如login_back