开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
前言
有时候我们在维护的一套代码时,可能会遇到在这个代码的基础上,修改部分功能再出一个新应用的需求。
新应用和老应用可能存在的差异点有:
- 包名、应用名、签名、版本号、配置参数等
- 各种资源(图片、颜色、字体、文案等)
- 功能逻辑差异
尽管我们可以复制代码创建新工程,或者切一个新分支,但如果作为长期使用的方案,它们都不太合适的地方。那么就有了本文————通过渠道包的方式,实现一套代码包含所有差异化处理。
gradle配置
配置渠道包
- 创建package
如下图所示,在主module的src下创建相应的package,作为不同的渠道,apple和banana是渠道名称,相当于两个应用各自的路径,互相独立,apple不能访问banana的内容,除此之外的内容则是公用的。
- 配置
productFlavors
打开主module的build.gradle,在android下添加如下代码:
productFlavors {
flavorDimensions "name"
apple {
dimension "name"
applicationId "com.mobile.apple"
versionCode 10000
versionName "1.0.0"
}
banana {
dimension "name"
applicationId "com.mobile.banana"
versionCode 20000
versionName "2.0.0"
}
}
同步代码,点击工程左侧的Build Variants,如果出现这些渠道参数,就表示创建成功了。之后我们想要打哪个包,就在这里选中对应的包参数即可
包名、版本号、配置参数,都可以在这里修改。
- 注意点
在gradle配置的
defaultConfig中,既存在和渠道apple中重复的配置属性(如applicationId,versionCode等),也存在不同的配置属性(如minSdk等),最终,重复的属性会被渠道包中的值覆盖,不同的则会全部保留。
资源
资源文件和gradle配置属性一样,渠道包中的图片、文案、清单文件、assets等,都可以覆盖公共路径下的同名内容,不同的内容则会被保留。
如图,main模块的ic_launcher.webp和AndroidManifest.xml被apple模块的覆盖替换,而它的ic_launcher_round.webp得以保留。
替换字符串,如下图所示
每个渠道包只要在各自的路径下修改、替换相应的内容,即可实现名称、logo等差异
逻辑差异
通过渠道包+抽象类/接口的方式,可以较为优雅的控制某些功能和逻辑。话不多说,以抽象类为例,上代码:
//1.主module中创建,定义那些存在差异化处理逻辑的方法
//抽象类
abstract class OnFlavorsFunctionDiff {
abstract fun getColor(): String
abstract fun getShape()
fun isFood(): Boolean = true
}
//或接口
interface OnFlavorsFunctionDiff {
fun getColor(): String
fun getShape()
}
//抽象类或接口任选其一都可以实现,不过个人认为抽象类相对接口更加灵活
//2.主module,设置和保存diff的静态工具类
object FlavorsFunctionDiff {
private var mDiff: OnFlavorsFunctionDiff? = null
fun setDiff(diff: OnFlavorsFunctionDiff) {
mDiff = diff
}
fun getDiff(): OnFlavorsFunctionDiff {
if (mDiff == null){
throw RuntimeException("must init diff first")
} else {
return mDiff!!
}
}
}
//3.在Application中设置Diff,而此处的CustomFunctionDiff就是子类或者实现接口方法的类
class App: Application() {
override fun onCreate() {
super.onCreate()
FlavorsFunctionDiff.setDiff(CustomFunctionDiff())
}
}
//4.在各个渠道包路径下,继承或依赖OnFlavorsFunctionDiff,创建自定义的实现类,重载重写实现这些方法
class CustomFunctionDiff : OnFlavorsFunctionDiff {
override fun getColor(): String {
return "red"
}
override fun getShape() {
Log.i("Diff", "shape is round")
}
}
//5.最后在代码里根据这个,来决定走不同的逻辑
FlavorsFunctionDiff.getDiff().xxx
感谢阅读,欢迎交流指正~