DevEnvironment 是一个 Android 环境配置切换库,运用 Java 注解、APT、反射等原理实现一键切换环境的工具库
-
App 在开发、测试、预生产、线上等阶段需要切换不同环境配置
-
同一个 App 中的不同模块,在同一阶段需要配置不同的环境
-
某些功能只能在指定环境下使用
-
需支持通过后台数据动态设置配置信息
-
环境配置在代码中写死,导致每次修改环境之后代码管理工具 ( Git、SVN ) 都会提示代码改动,一旦疏忽就提交了,这对于代码管理是不严谨的
-
使用简单、且无需重新打包即可一键切换环境
-
支持模块化配置与切换环境
-
支持通过后台数据动态设置配置信息
-
支持添加切换环境配置回调
-
使用 Java 注解编译时生成 DevEnvironment 类,内部实现
切换
保存
读取
环境的逻辑代码
比较内容 | DevEnvironment | Gradle Application Id 不同 | Gradle Application Id 相同 |
---|---|---|---|
运行时切换环境 | ✔️ | ❌ | ❌ |
切换环境回调 | ✔️ | ❌ | ❌ |
切换环境逻辑 | 自动生成 | 需要自己实现 | 需要自己实现 |
N 套环境打包数量 | 1 个 | N 个 | N 个 |
多套环境同时安装 | ✔️ | ✔️ | ❌ |
支付等 SDK 包名校验 | ✔️ | ❌ | ✔️ |
多模块环境配置 | ✔️ | ✔️ | ✔️ |
测试环境不泄露 | ✔️ | ✔️ | ✔️ |
…… | —— | —— | —— |
module | DevEnvironment | DevEnvironmentCompiler | DevEnvironmentCompilerRelease |
---|---|---|---|
version |
dependencies {
// Java
implementation 'io.github.afkt:DevEnvironment:1.1.2'
debugAnnotationProcessor 'io.github.afkt:DevEnvironmentCompiler:1.1.2'
releaseAnnotationProcessor 'io.github.afkt:DevEnvironmentCompilerRelease:1.1.2'
// 如果需要 Release 包,支持通过后台数据动态设置配置信息 则使用 debug compiler lib
// annotationProcessor 'io.github.afkt:DevEnvironmentCompiler:1.1.2'
// Kotlin
implementation 'io.github.afkt:DevEnvironment:1.1.2'
kaptDebug 'io.github.afkt:DevEnvironmentCompiler:1.1.2'
kaptRelease 'io.github.afkt:DevEnvironmentCompilerRelease:1.1.2'
// 如果需要 Release 包,支持通过后台数据动态设置配置信息 则使用 debug compiler lib
// kapt 'io.github.afkt:DevEnvironmentCompiler:1.1.2'
}
点击菜单栏中的 “Build” -> “Rebuild Project”,等待编译完成
正常会在 /build/generated/ap_generated_sources/debug/out/dev/environment
内创建 DevEnvironment.java
- 环境配置工具类 DevEnvironment.java
方法 | 注释 |
---|---|
isRelease | 是否使用 releaseAnnotationProcessor 构建 |
getModuleList | 获取全部 ModuleBean 配置列表 |
addOnEnvironmentChangeListener | 添加模块环境改变触发事件 |
removeOnEnvironmentChangeListener | 移除模块环境改变触发事件 |
clearOnEnvironmentChangeListener | 清空模块环境改变触发事件 |
reset | 重置操作 |
getIMModule | 获取 IM [ Module ] Bean |
getIMReleaseEnvironment | 获取 IM [ Module ] Release Environment Bean |
getIMEnvironment | 获取 IM [ Module ] Selected Environment Bean |
getIMEnvironmentValue | 获取 IM [ Module ] Selected Environment Value |
setIMEnvironment | 设置 IM [ Module ] Selected Environment Bean |
resetIM | 重置 IM [ Module ] Selected Environment Bean |
isIMAnnotation | 是否 IM [ Module ] Annotation Environment Bean |
// 底部五个方法中 IM 属于 Module Name 例:
@Module(alias = "IM 模块")
private class IM {
}
public final class Config {
@Module(alias = "服务器请求地址")
private class Service {
@Environment(value = "https://www.wanandroid.com/", isRelease = true, alias = "线上环境")
private String release;
@Environment(value = "https://debug.com", alias = "测试环境")
private String debug;
@Environment(value = "https://pre_release.com", alias = "预发布环境")
private String pre_release;
@Environment(value = "https://development.com", alias = "开发环境")
private String development;
}
@Module(alias = "开关")
private class Switch {
@Environment(value = "true", isRelease = true)
private String open;
@Environment(value = "false")
private String close;
}
@Module(alias = "IM 模块")
private class IM {
@Environment(value = "https://im.release.com/", isRelease = true, alias = "线上环境")
private String release;
@Environment(value = "https://im.debug.com", alias = "测试环境")
private String debug;
}
}
- @Module
被 @Module
修饰的类或接口表示一个模块,每个 @Module
有 n ( n > 0 ) 个被 @Environment
修饰的属性,表示该模块中有 n 种环境配置
- @Environment
被 @Environment
修饰的属性表示一个环境,必须指定 value 属性值,此外还有两个可选属性:isRelease 和 alias
value
:该环境配置值
isRelease
:是一个 Boolean 型的属性,默认为 false,当值为 true 时,它就是所在 @Module
的默认环境
每个
@Module
必须有且只有一个isRelease
值为 true 的@Environment
项目类结构 - 包目录
-
Module 类(@Module):模块 ( 注解标记类 )
-
Environment 类(@Environment):环境配置 ( 注解标记类 )
-
模块环境改变接口(OnEnvironmentChangeListener):模块环境发生变化时触发
每个
@Module
、@Environment
都会生成对应的 ModuleBean、EnvironmentBean 实体类
-
@Module 映射实体类(ModuleBean):@Module ( 注解标记类 ) 映射实体类
-
@Environment 映射实体类(EnvironmentBean):@Environment ( 注解标记类 ) 映射实体类
-
DevEnvironmentCompiler 属于 Debug ( 打包 / 编译 ) 注解处理器,使用该注解处理时生成的 DevEnvironment 允许设置选中的环境 (
setXXEnvironment
通过该方法设置,只有使用该注解处理才会实现该方法代码 )-
getXXModule
获取对应 Module 映射实体类 ModuleBean -
getXXReleaseEnvironment
获取对应 Module isRelease 值为 true 的 Environment 映射实体类 EnvironmentBean -
getXXEnvironment
获取对应 Module 选中的 Environment ( 默认选中 isRelease 值为 true 的@Environment
) -
getXXEnvironmentValue
获取对应 Module 选中的 Environment Value -
setXXEnvironment
设置对应 Module 选中的 Environment -
resetXX
用于删除对应 Module 选中的 Environment Config File -
isXXAnnotation
用于判断对应 Module 选中的 Environment 是否属于注解环境配置
-
-
DevEnvironmentCompilerRelease 属于 Release ( 打包 / 编译 ) 注解处理器,使用该注解处理时生成的 DevEnvironment 每个 Module 只会生成一个常量 Environment,并且无法进行修改设置
-
getXXModule
获取对应 Module 映射实体类 ModuleBean -
getXXReleaseEnvironment
获取对应 Module isRelease 值为 true 的 Environment 映射实体类 EnvironmentBean -
getXXEnvironment
内部调用getXXReleaseEnvironment
-
getXXEnvironmentValue
内部调用getXXEnvironment
获取 Value -
setXXEnvironment
内部不实现代码,直接返回 false ( 表示不支持设置 ) -
resetXX
内部不实现代码,直接返回 false -
isXXAnnotation
内部不实现代码,直接返回 true
-
DevEnvironmentCompilerRelease 编译生成的 DevEnvironment 类,全部属于 final 无法进行修改、设置,且部分方法内部不进行代码实现
而 DevEnvironmentCompiler 编译生成的 DevEnvironment 类,允许修改选中的 Environment 支持可视化切换、代码方式切换
无特殊需求一般用于 debugAnnotationProcessor DevEnvironmentCompiler
如果需要 Release 下可切换环境则使用 annotationProcessor DevEnvironmentCompiler
注:使用 DevEnvironmentCompilerRelease 注解编译生成不支持环境配置切换
- 通过代码方式设置 setXXEnvironment
// 如果准备设置环境等于当前选中的环境,则会返回 false
EnvironmentBean custom = new EnvironmentBean("自定义配置",
"https://custom.com", "动态自定义", DevEnvironment.getServiceModule());
boolean result = DevEnvironment.setServiceEnvironment(mContext, custom);
- 通过可视化界面方式切换
// 显示右上角重启按钮
boolean result = DevEnvironmentActivity.start(mContext, new RestartCallback() {
@Override
public void onRestart() {
ActivityUtils.getManager().exitApplication();
}
});
// 不显示右上角重启按钮
boolean result = DevEnvironmentActivity.start(mContext);
// 添加环境改变监听事件
DevEnvironment.addOnEnvironmentChangeListener(new OnEnvironmentChangeListener() {
/**
* 模块环境发生变化时触发
* @param module 环境发生变化的模块
* @param oldEnvironment 该模块的旧环境
* @param newEnvironment 该模块的最新环境
*/
@Override
public void onEnvironmentChanged(ModuleBean module, EnvironmentBean oldEnvironment,
EnvironmentBean newEnvironment) {
}
});
// 移除环境改变监听事件
DevEnvironment.removeOnEnvironmentChangeListener(listener);
// 移除全部环境改变监听事件
DevEnvironment.clearOnEnvironmentChangeListener();
// 有多少个 @Module 修饰,则会生成多少个 getXXModule 方法
ModuleBean serviceModule = DevEnvironment.getServiceModule();
ModuleBean switchModule = DevEnvironment.getSwitchModule();
ModuleBean imModule = DevEnvironment.getIMModule();
// getXXReleaseEnvironment 该方法返回 isRelease 值为 true 的 Environment ( 必须有且只有一个 )
// 而 getXXEnvironment 获取的为当前 Module 选中的 Environment,可通过 setXXEnvironment 进行修改
EnvironmentBean serviceReleaseEnvironment = DevEnvironment.getServiceReleaseEnvironment();
EnvironmentBean serviceEnvironment = DevEnvironment.getServiceEnvironment(mContext);
EnvironmentBean switchReleaseEnvironment = DevEnvironment.getSwitchReleaseEnvironment();
EnvironmentBean switchEnvironment = DevEnvironment.getSwitchEnvironment(mContext);
EnvironmentBean imReleaseEnvironment = DevEnvironment.getIMReleaseEnvironment();
EnvironmentBean imEnvironment = DevEnvironment.getIMEnvironment(mContext);
同 Butterknife、Greendao 等第三方库,通过编译时注解 ( APT 技术 ) 实现,具体可参考该库实现代码及 link.mk 技术链接
DevEnvironment 文件生成配置:HttpConstants
DevEnvironment 使用:DevEnvironmentLibActivity
点击菜单栏中的 “Build” -> “Rebuild Project”,等待编译完成