扒一扒 Netflix 安卓客户端使用了哪些开源库
作者:Mr_万能胶
juejin.cn/post/7246453307735392316
前言
由于前段时间看完了《不拘一格 网飞的自由与责任工作法》这本书,对 Netlifx 这家公司产生了巨大的好感。今天突然好奇,这家酷酷的硅谷公司所做的 Android 客户端,究竟使用了哪些开源库?一般来讲,外企在选择开源库的时候普遍会很谨慎,一定是对比、pk 多轮之后决定的。在此做一个整理,顺便也同步一下脑海中的主流认知,免得今后遇到类似需求的时候重复造轮子。
1. 如何查看
很简单,我的方法就是看开源协议。因为大部分开源库都会声明自己用了哪些开源库,引用者必须在 App 一个单独的页面将这些信息展示出来,因此我们查看这个页面就可以知道接了哪些第三方库,省去了反编译的麻烦。
我使用的是 8.69.0 build 12
版本的客户端,相关信息如下图所示:
2. 开源库一览
注意:下表已经删除了大部分偏底层(如 libCurl, libOpenSSL)、偏语言(如 Kotlin,MySQL),以及国内开发者耳熟能详的(如 RxJava、RxKotlin、RxKotlin)开源库。
表格按照类型排序。另外,只要官方作者没有 archive 一个库 ,我都认为它是活跃的。
静态的表格可能无法让大家按照自己喜爱的维度来查看
名称 | 地址 | 类型 | 状态 | 说明 |
---|---|---|---|---|
AutoDispose | https://uber.github.io/AutoDispose/ | RxJava 扩展 | 活跃 | 自动绑定 RxJava的流到它内部实现好的一个 scope ,来实现自动 dispose |
RxDogTag | https://github.com/uber/RxDogTag | RxJava 扩展 | 活跃 | 不想在用 RxJava 时实现 onError 可以用这个,也方便检查错误在哪。 |
AutoValue | https://github.com/google/auto/tree/main/value | Java 扩展 | 活跃 | 注解生成代码,简单理解就是做 Kotlin data class 的事 |
Checker Framework | https://checkerframework.org/ | Java 扩展 | 活跃 | 可以通过编写插件来扩展 Java 编译器的功能,比如增加一些类型检查 |
Java Poet | https://github.com/square/javapoet | Java 扩展 | 活跃 | Square 出品,通过调用 Java API 来生成 .java 文件,很多 Gradle 插件在编译时生成代码背后实现都会用到它。 |
Paper Parcel | https://github.com/grandstaish/paperparcel | Java 扩展 | 过时 | 注解生成 Parcelable 对象的CREATOR 和 writeToParcel(...) |
Bouncy Castle Crypto | https://www.bouncycastle.org/ | Java 扩展 | 活跃 | 一个用于 Java 平台的开放源码的轻量级密码术包。 |
JaroWinklerSimilarity | https://commons.apache.org/ | Java 扩展 | 活跃 | 字符串相似度比较算法 |
Moshi | https://github.com/square/moshi | Java 扩展 | 活跃 | 目前对 Kotlin 兼容最好的 Json 解析库 |
Exoplayer | https://github.com/google/ExoPlayer | Android 音视频 | 活跃 | 知名视频播放库 |
Cronet | https://developer.android.com/codelabs/cronet#0 | Android 网络请求 | 活跃 | Chrome 使用的移动端网络库。支持 HTTP、HTTP/2 以及 QUIC 协议 |
Rounded Image View | https://github.com/vinc3m1/RoundedImageView | Android 界面组件 | 过时 | 用来实现各种 radius 的圆形 ImageView |
Sticky Scroll View | https://github.com/amarjain07/StickyScrollView | Android 界面组件 | 活跃 | 滑动列表的时候固定一个 View 在顶部 |
Lottie | https://github.com/airbnb/lottie-android | Android 界面组件 | 活跃 | 知名动画库 |
FlexboxLayout | https://github.com/google/flexbox-layout | Android 界面组件 | 活跃 | Google 出品的一个在 Android 平台实现类似前端 Flex 布局的组件 |
card-stack-view | https://github.com/yuyakaido/CardStackView | Android 界面组件 | 活跃 | 滑动卡片组件,实现探探那种左滑 dis 右滑 like 的效果 |
Bugsnag | https://github.com/bugsnag/bugsnag-android | Android 架构 | 活跃 | 崩溃手机,国内类似 bugly |
Mavericks | https://github.com/airbnb/mavericks | Android 架构 | 活跃 | 之前叫 MvRx,airbnb 开源的一套著名Android App 响应式开发框架。 |
Facebook Battery | https://github.com/facebookincubator/Battery-Metrics | Android 架构 | 活跃 | Facebook 出的一款方便检测应用耗电的 SDK |
Tape by Square | https://github.com/square/tape | Android 架构 | 活跃 | 一个轻快的,事务性的,基于文件的 FIFO 的库 |
Seismic | https://github.com/square/seismic | Android 传感器 | 活跃 | Android 手机晃动检测库。没想到 Square 还出过这玩意儿。 |
rtl-viewpager | https://github.com/duolingo/rtl-viewpager | Android ViewPager 扩展 | 过时 | 扩展了 ViewPager 部分功能,现已被 ViewPager2 代替 |
groupie | https://github.com/lisawray/groupie | Android RecyclerView 扩展 | 活跃 | 方便 RecyclerView 显示复杂布局 |
Epoxy | https://github.com/airbnb/epoxy | Android RecyclerView 扩展 | 活跃 | 简化 RecyclerView 多 ViewType 场景下的开发 |
Relinker | https://github.com/KeepSafe/ReLinker | Android JNI 开发扩展 | 活跃 | 解决 API 23 以下 Android 版本可能出现的 so 库 link 不上的问题 |
接下来,我将按照这些开源库的“类型”跟大家一起过一遍。需要说明的是,这里面有些库我对它很熟悉,有些比较陌生,有些甚至让我觉得“原来已经有这样的库了”!
每个人的认知是不同的,我没见过的有可能反而是你最熟悉的,反之亦然,所以这部分主要还是偏向我自己的理解。如果你用过上面这些库,欢迎在下方评论区留言分享,而如果我的理解有误,也欢迎指出,我将不慎感激!
3. 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 大神。Epoxy 相对而言就复杂一些,不过也是为了解决 RecyclerView 构建复杂列表的。飞书文档团队之前写过一篇比较完整的介绍文章,大家可以参考
https://juejin.cn/post/7081589563134574628
,就不在此赘述了。
其它几个控件比较平常,在此略评一二:
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 布局的需求,可以考虑。
4. 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 的标配。
5. 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 替代,这一点在官方文档 github.com/google/auto/blob/main/value/README.md 里也有说明。
Paper Parcel 同样在 Kotlin First 的前提下,也已经可以使用官方的 kotlin-parcelize 来替代,简单方便。
Bouncy Castle Crypto 是一个 Java 实现的加解密库,跟 Netflix 用到的具体算法有关,这个不在此赘述了。
Checker Framework 是一个测试框架,在 Android 自动化测试中可以用于检测代码中的代码缺陷和错误,提高测试的覆盖率和可靠性。公司有自动化测试的团队,可以考虑接入这个框架。
Moshi 这个就更加不用说了,如果到现在还只知道 Gson、fastjson的 Android 开发者可以去面壁了。
6. Android 架构类
这部分我比较感兴趣的是 Mavericks 和 tape。
Mavericks 又是 Airbnb 开源的一个库,没错,大名鼎鼎 Lottie 动画框架也是他们出品的。它是一个 Android MVI 结构的开源框架,适用于需要构建复杂、高效、可维护的 Android 应用程序的场景,特别是在需要处理大量异步数据、网络请求和数据持久化的情况下。Mavericks 的核心在于它的三大件, MavericksState
,MavericksViewModel
, 和MavericksView
,再配合它独有的onEach
还有withState
几乎就可以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 官方已经有更好实现的开源库,然而他们客户端还是保留着这些过时的代码,没有做迁移,我估计要么也是“能用就不改”,要么就是“粘得太紧,实在改不动”吧。所以,难道全世界的公司,项目大了都会面临这样的问题?
-- END --
推荐阅读