Android上一个简单的Feature Flag实现
起因是看了Jeroen Mols大佬的Feature Flags系列,深受启发。在看了代码后,萌生了写一个适合自己的Feature Flag框架。现在整出来了,但发现使用场景有点局限😂,所以把代码丢在这里以备不时之需。
我个人的需求没原文中那么复杂,只需要一个可以在代码里手动调整的开关,一个可以在运行时进行修改的面板,同时要让R8把未使用的所有代码剔除。
首先是可以在代码里手动调整的开关,用buildConfigField
:
1 | android { |
"Boolean.parseBoolean(\"true\")"
确保IDE不会警告,就像BuildConfig.DEBUG
一样。
整个框架,抄了就走:
1 | enum class Feature( |
使用:
1 | FeatureFlagManager.init(this) |
运作原理:
isFeatureEnabled
1
2
3
4
5
6
7
8
9/**
* If we pass a value directly, this method won't get removed by R8.
* Passing a lambda does the job.
* I learn this at https://youtu.be/MYQWtNG2so8?t=362
*/
fun isFeatureEnabled(f: () -> Feature): Boolean {
if (!BuildConfig.FEATURE_FLAG) return false
return f.invoke().enabled
}顾名思义,传Lambda而不是直接传Feature确保R8可以在这段代码没被使用时移除掉它,不然Feature会留在最终的APK里。
担心性能问题?
- 我没做Benchkmark,所以不考虑优化。
- 我寻思以大部分应用的水平,这个Lambda根本不在瓶颈上。
- 请信任智能的R8,人家比咱上心,也比咱厉害,也许人家已经搞定了。
- Romain Guy大佬怎么做,我就怎么做!
setAdapter
之所以使用
AlertDialog
的setAdapter
而不是自定义View
,是因为这样可以让列表滚动时在顶端和底端有一个分割线,我挺喜欢这个设计,但缺点就是要处理ListView
😢ListView
的每个条目的命名R.layout.list_item_feature_flag
我之前用的是
R.layout.item_feature_flag
,但发现R8在把整个Feature
移除后死活不把这个文件处理掉,查看resources.txt
并研究后才发现,所有以item
开头的资源,都不会被处理(当然还有其它各种开头,具体在这里)。修改为list
开头后就好了,虽然文件还在,但里面的内容已经没了。另一种方法是根据官方文档底部的方法来确保这些文件被移除。我懒,所以没试这种方法。
getView
绑定ListItemWithLayout
就是一个CompoundButton
配一个TextView
,不稀奇。包括其他的一些方法,都是简单包装了一下,顾名思义。ProcessPhoenix.triggerRebirth(context)
我这里用ProcessPhoenix来强制重启,但它有点Bug,需要你在启动的
Activity
加一个category:<category android:name="android.intent.category.DEFAULT" />
。我也找了一下
chromium
是怎么重启的,发现人家使用JNI重启进程,我寻思有没有谁来打包成一个库呀?