我正在参加「掘金·启航计划」
由于前段时间看完了《不拘一格 网飞的自由与责任工作法》这本书,对 Netlifx 这家公司产生了巨大的好感。今天突然好奇,这家酷酷的硅谷公司所做的 Android 客户端,究竟使用了哪些开源库?一般来讲,外企在选择开源库的时候普遍会很谨慎,一定是对比、pk 多轮之后决定的。在此做一个整理,顺便也同步一下脑海中的主流认知,免得今后遇到类似需求的时候重复造轮子。
如何查看
很简单,我的方法就是看开源协议。因为大部分开源库都会声明自己用了哪些开源库,引用者必须在 App 一个单独的页面将这些信息展示出来,因此我们查看这个页面就可以知道接了哪些第三方库,省去了反编译的麻烦。
我使用的是 8.69.0 build 12
版本的客户端,相关信息如下图所示:
开源库一览
注意:下表已经删除了大部分偏底层(如libCurl
,libOpenSSL
)、偏语言(如 Kotlin
,MySQL
),以及国内开发者耳熟能详的(如 RxJava
、RxKotlin
、RxKotlin
)开源库。
表格按照类型排序。另外,只要官方作者没有 archive 一个库 ,我都认为它是活跃的。
静态的表格可能无法让大家按照自己喜爱的维度来查看,我也给大家准备了在线表格。
名称 | 地址 | 类型 | 状态 | 说明 |
---|---|---|---|---|
Rounded ImageView | github.com/vinc3m1/Rou… | Android 界面组件 | 过时 | 用来实现各种 radius 的圆形 ImageView |
AutoValue | github.com/google/auto… | Java 扩展 | 活跃 | 注解生成代码,简单理解就是做 Kotlin data class 的事 |
Java Poet | github.com/square/java… | Java 扩展 | 活跃 | Square 出品,通过调用 Java API 来生成 .java 文件,很多 Gradle 插件在编译时生成代码背后实现都会用到它。 |
Paper Parcel | github.com/grandstaish… | Java 扩展 | 过时 | 注解生成 Parcelable 对象的CREATOR 和 writeToParcel(...) |
AutoDispose | uber.github.io/AutoDispose… | RxJava 扩展 | 活跃 | 自动绑定 RxJava 的流到它内部实现好的一个 scope ,来实现自动 dispose |
Relinker | github.com/KeepSafe/Re… | Android JNI 开发扩展 | 活跃 | 解决 API 23 以下 Android 版本可能出现的 so 库 link 不上的问题 |
Seismic | github.com/square/seis… | Android 传感器 | 活跃 | Android 手机晃动检测库。没想到 Square 还出过这玩意儿。 |
Sticky Scroll View | github.com/amarjain07/… | Android 界面组件 | 活跃 | 滑动列表的时候固定一个 View 在顶部 |
Bouncy Castle Crypto | www.bouncycastle.org/ | Java 扩展 | 活跃 | 一个用于 Java 平台的开放源码的轻量级密码术包。 |
Lottie | github.com/airbnb/lott… | Android 界面组件 | 活跃 | 知名动画库 |
Cronet | developer.android.com/codelabs/cr… | Android 网络请求 | 活跃 | Chrome 使用的移动端网络库。支持 HTTP、HTTP/2 以及 QUIC 协议。支持 Android 和 iOS 平台 |
Exoplayer | github.com/google/ExoP… | Android 音视频 | 活跃 | 知名视频播放库 |
groupie | github.com/lisawray/gr… | Android RecyclerView 扩展 | 活跃 | 方便 RecyclerView 显示复杂布局 |
rtl-viewpager | github.com/duolingo/rt… | Android ViewPager 扩展 | 过时 | 扩展了 ViewPager 部分功能,现已被 ViewPager2 代替 |
Epoxy | github.com/airbnb/epox… | Android RecyclerView 扩展 | 活跃 | 简化 RecyclerView 多 ViewType 场景下的开发 |
FlexboxLayout | github.com/google/flex… | Android 界面组件 | 活跃 | Google 出品的一个在 Android 平台实现类似前端 Flex 布局的组件 |
RxDogTag | github.com/uber/RxDogT… | RxJava 扩展 | 活跃 | 不想在用 RxJava 时实现 onError 可以用这个,也方便检查错误在哪。 |
JaroWinklerSimilarity | commons.apache.org/proper/comm… | Java 扩展 | 活跃 | 字符串相似度比较算法 |
Mavericks | github.com/airbnb/mave… | Android 架构 | 活跃 | 之前叫 MvRx,airbnb 开源的一套著名Android App 响应式开发框架。 |
Bugsnag | github.com/bugsnag/bug… | Android 架构 | 活跃 | 崩溃手机,国内类似 bugly |
Facebook Battery | github.com/facebookinc… | Android 架构 | 活跃 | Facebook 出的一款方便检测应用耗电的 SDK |
Checker Framework | checkerframework.org/ | Java 扩展 | 活跃 | 可以通过编写插件来扩展 Java 编译器的功能,比如增加一些类型检查 |
card-stack-view | github.com/yuyakaido/C… | Android 界面组件 | 活跃 | 滑动卡片组件,实现探探那种左滑 dis 右滑 like 的效果 |
Tape by Square | github.com/square/tape | Android 架构 | 活跃 | 一个轻快的,事务性的,基于文件的FIFO的库 |
Moshi | github.com/square/mosh… | Java 扩展 | 活跃 | 目前对 Kotlin 兼容最好的 Json 解析库 |
接下来,我将按照这些开源库的“类型”跟大家一起过一遍。
需要说明的是,这里面有些库我对它很熟悉,有些比较陌生,有些甚至让我觉得“原来已经有这样的库了”!
每个人的认知是不同的,我没见过的有可能反而是你最熟悉的,反之亦然,所以这部分主要还是偏向我自己的理解。如果你用过上面这些库,欢迎在下方评论区留言分享,而如果我的理解有误,也欢迎指出,我将不慎感激!
Android 界面控件类
这部分我最感兴趣的是 groupie
和 Epoxy
这两个控件。
groupie
这个库,从用法上看有点像 Drakeet 大神早年写的 MultiType,用来解决 RecyclerView 里有很多不同 ViewType 的 item 需要显示的问题。
彼时 Google 还没有弄出 ConcatAdapter,大家面对这样的需求只能在 Adapter 里重写 getItemViewType,然后在 onBindViewHolder 里根据不同的 ViewType
调用不同的 ViewHolder
。
MultiType 的出现简化了这些步骤,它把列表的每一项称数据认为是一个 ItemData
,对应的有一个 ItemView
。它封装了一个 MultiTypeAdapter,这个 adapter
提供一个唯一接收数据的方法 setData(items: Items)
方法,Items 本质是一个 ArrayList<Object>
,里面可以 add
一个个的 ItemData
,同时提供一个 register()
方法,用来把 ItemData
和 ItemView
的关系成对注册,最后把它设给 RecyclerView
做 adapter
即可。
groupie
从用法上看和 MultiType 应该类似,只不过它限定了每一个 ItemData
的写法,提供了 Item
和 BindableItem
很好地支持了后来出的 ViewBinding。有点英雄所见略同,又有点站在巨人肩膀上了的意思。虽然没有在项目里落地过,但是 MultiType 我们至今有一个项目还在使用,在这里 shout out to Drakeet 大神。
其它的几个控件就比较平常了,在此略评一二:
Rounded Image View
这个库兴趣不大,现在主流的图片加载框架都可以在加载图片的时候去动态裁剪(Transform),在实际应用中也比写死 ImageView
要更灵活。事实上我平时很少鼓励大家去写自定义控件,因为基本上一写一个坑,我就敢说国内没有多少开发者是在写自定义控件的时候,会老老实实把旋屏、状态保存、自定义属性、无障碍、等各种情形处理好的,且不谈内存和性能方面的问题了。个人猜测 Netflix 引用这个控件估计也是历史原因,既然能用,也就懒得改了吧。
Sticky Scroll View
这个库也没什么好说的,列表滑动中固定某个头部已经有很多类似的实现了,这个控件是基于 View
嵌套和 ScrollView
的,而现在做列表大部分都是 RecyclerView
或者 CollapingToolbarLayout
了,后两者都可以比较完美实现类似的效果。
Lottie
很出名,也已经出来很久了,连 aosp 里的项目都在用,做简单的点线动画非常合适,不在此赘述了。
rtl-viewpager
是对老的 ViewPager
的扩展,现在大部分需求应该都可以结合 ViewPager2
来实现了。
FlexboxLayout
是 ConstranitLayout
出现之前的产物,由于是 Google 亲生的所以迄今还在维护。我个人觉得现阶段的 App 需求应该没有 ConstranitLayout
+ MotionLayout
做不了的吧?当然了,还是要结合具体需求,如果团队内有对前端比较熟悉的小伙伴,或者贴近 Flex 布局的需求,可以考虑。
Android 工具类
这部分我比较感兴趣的是 Seismic
和 Cronet
。
Seismic
令我感兴趣的主要还是历史原因。它居然是 11 年前就开源的一个用来检测手机晃动的库,而且还是 Sqaure 出品,如果你也是第一次知道,或者写到现在都是自己做晃动检测的,请把 “Squaure 牛逼” 打在评论区。
Cronet
这个库我倒不陌生,原因是我一直有经常看 Android Developer 官网的习惯。在 Perform network operations overview 这一章,Google 很久之前就已经把 Cronet 给列出来了,只“可惜” Retrofit 做得太好了,不管是稳定性,扩展性,还是和 Kotlin 的兼容性都近乎完美,所以基本上大家提到网络请求就是后者。但是 Cronet
也有它自己的优势,就是 QUIC,这一块估计过半数的 App 用不到,所以也不好怪大家不知道了。
其它两个库就没什么好说的了。Relinker
国内只要有 so 库并且需要下沉低版本的 App 估计都在用吧?而 Exoplayer
就更不用说了,应该是音视频播放 App 的标配。
Java、Kotlin 扩展类
这部分我比较感兴趣的是 Auto Dispose
和 JaroWinklerSimilarity
,而其它的几乎现在都有更好的替代。
AutoDispose
是由 Uber 公司开源的,没错,就是国外滴滴打车那个公司。要提它就先要看 RxDogTag
这个库,用它可以方便地管理和调试 RxJava
和 RxAndroid
中的错误和异常(话说 Uber 真的好喜欢 RxJava
的样子)。而 AutoDispose在它的基础上,可以让开发者更方便地管理 RxJava
的订阅关系,并且可以减少代码的复杂度和出错几率。
还记得大概从 2021 年开始,因为协程慢慢成熟,我确实没怎么用过 RxJava
了,但之前最开始学习的时候,确实被它的 onComplete()
onError()
搞得死去活来,印象中光这两个还不够,好像还要写一个处理 Exception
的 Consumer
,总之确实很繁琐(当然这跟我当时的认知有关,请熟悉 RxJava
的小伙伴看到这里不要打我)。这个库看起来一定程度上解决了这个问题,就像它官网写的那样 AutoDispose is an RxJava 2+ tool for automatically binding the execution of RxJava streams to a provided scope via disposal/cancellation.
,既可以偷懒,而且在数据流出错的时候还能使堆栈更加方便直观,单着两点我就觉得很值得一用了。我没有去细看源码,如果有在用的小伙伴,欢迎补充指正。
再说 JaroWinklerSimilarity
,准确说它不是单独开源的,而是 Apache Commons
里面的,但是我真的是第一次听说这个算法,它可以比较两个字符串之间的相似度,个人感觉还是很有趣的。背后的原理即
Jaro-Winkler 相似度算法,这是一个字符级别的算法,可以用于任何语言的字符串比较,也包括中文,但是需要注意的是,由于 Jaro-Winkler 算法是基于字符级别的,因此如果拿来比较两串中文的话,需要对文本进行拆字处理,效果可能没有比较英文串时那么准确。
剩下几个库就简单点评一下:
AutoValue
是 Google 出品,但主要是一个 For Java 的库,在 Kotlin First 的前提下,可以完全被 data class
替代,这一点在官方文档里也有说明。
Paper Parcel
同样在 Kotlin First 的前提下,也已经可以使用官方的 kotlin-parcelize 来替代,简单方便。
Bouncy Castle Crypto
是一个 Java 实现的加解密库,跟 Netflix 用到的具体算法有关,这个不在此赘述了。
Checker Framework
是一个测试框架,在 Android 自动化测试中可以用于检测代码中的代码缺陷和错误,提高测试的覆盖率和可靠性。公司有自动化测试的团队,可以考虑接入这个框架。
Moshi
这个就更加不用说了,如果到现在还只知道 Gson
、fastjson
的 Android 开发者可以去面壁了。
Android 架构类
这部分我比较感兴趣的是 Mavericks
和 tape
。
先说 Mavericks
,这又是 Airbnb 开源的一个库,没错,大名鼎鼎 Lottie
动画框架也是他们出品的。
Mavericks
是一个 Android MVI 结构的开源框架,适用于需要构建复杂、高效、可维护的 Android 应用程序的场景,特别是在需要处理大量异步数据、网络请求和数据持久化的情况下。Mavericks
的核心在于它的三大件,MavericksState
, MavericksViewModel
, 和 MavericksView
,再配合它独有的 onEach
还有 onEach
几乎就可以 cover 我们平时开发的大部分场景,并且能够简化代码,同时官方还提供了依赖用以方便地集成使用 ViewBinding
甚至Hilt
。
写到这里我突然想起这一个月来面试的不少同学,每次问题 App 架构,他们的回答总是,提到“数据驱动 UI 更新”就是 MVVM
,提到“逻辑界面分离”就是 MVI
。那么问题来了,如果我的应用是 MVI
架构,但是我的数据需要关心大量的状态,并且这些状态又要驱动 UI 更新呢?很少有同学能够答好这个问题。
请看回上上个自然段,恭喜你遇到了,Mavericks
就是用来解决这一问题的最好框架!
再说 Tape
, 这个相对简单,是 Square 公司开源的一个组队列相关的实现,主要包含 FileObjectQueue
、InMemoryObjectQueue
、ObjectQueue
、QueueFile
这四个实现。关于队列没什么好说的了,FIFO
而已。这个库的存在就有点像 LRU 算法
有 DiskLruCache 和 MemoryLruCache ,基于不同的介质去实现。
总结
总的来看,Netflix Android 客户端团队在开源库的选择方面,还是偏 Square、Airbnb 这样的开源大厂出品居多。而不得不承认的是这些开源库大部分都是被广泛使用,经得起考验的,不至于出一些稀奇古怪的问题,更不至于一段时间之后没人维护。
另外,相信大家也感受到了,他们团队相对而言还是比较快速跟进主流 Android 开发技术的,不管是语言层面还是架构层面,对 MAD 还是很努力地践行的。
而“自研”方面,与国内氛围不同,没有 KPI,没有面向晋级编程,既然能站在巨人的肩膀上,也就不必去重复造轮子,相信大家也看出了 Netflix 其实并没有自己写什么框架在里面。不过考虑到 Netflix 观看时候的良好体验,我怀疑音视频那块估计有?可惜这不是我的擅长方向,如果有研究的小伙伴欢迎评论区补充。
最后还可以看出一点,大公司病同样也存在于他们团队。整个 Netflix Android 客户端存在很多已经过时、不再维护,或者 Google 官方已经有更好实现的开源库,然而他们客户端还是保留着这些过时的代码,没有做迁移,我估计要么也是“能用就不改”,要么就是“粘得太紧,实在改不动”吧。所以,难道全世界的公司,项目大了都会面临这样的问题?
以上。