查看原文
其他

扒一扒 Netflix 安卓客户端使用了哪些开源库

AndroidPub 2024-02-16

作者:Mr_万能胶
juejin.cn/post/7246453307735392316

前言

由于前段时间看完了《不拘一格 网飞的自由与责任工作法》这本书,对 Netlifx 这家公司产生了巨大的好感。今天突然好奇,这家酷酷的硅谷公司所做的 Android 客户端,究竟使用了哪些开源库?一般来讲,外企在选择开源库的时候普遍会很谨慎,一定是对比、pk 多轮之后决定的。在此做一个整理,顺便也同步一下脑海中的主流认知,免得今后遇到类似需求的时候重复造轮子。

1. 如何查看

很简单,我的方法就是看开源协议。因为大部分开源库都会声明自己用了哪些开源库,引用者必须在 App 一个单独的页面将这些信息展示出来,因此我们查看这个页面就可以知道接了哪些第三方库,省去了反编译的麻烦。

我使用的是 8.69.0 build 12 版本的客户端,相关信息如下图所示:

2. 开源库一览

注意:下表已经删除了大部分偏底层(如 libCurl, libOpenSSL)、偏语言(如 Kotlin,MySQL),以及国内开发者耳熟能详的(如 RxJavaRxKotlinRxKotlin)开源库。

表格按照类型排序。另外,只要官方作者没有 archive 一个库 ,我都认为它是活跃的。

静态的表格可能无法让大家按照自己喜爱的维度来查看

名称地址类型状态说明
AutoDisposehttps://uber.github.io/AutoDispose/RxJava 扩展活跃自动绑定 RxJava的流到它内部实现好的一个 scope ,来实现自动 dispose
RxDogTaghttps://github.com/uber/RxDogTagRxJava 扩展活跃不想在用 RxJava 时实现 onError 可以用这个,也方便检查错误在哪。
AutoValuehttps://github.com/google/auto/tree/main/valueJava 扩展活跃注解生成代码,简单理解就是做 Kotlin data class 的事
Checker Frameworkhttps://checkerframework.org/Java 扩展活跃可以通过编写插件来扩展 Java 编译器的功能,比如增加一些类型检查
Java Poethttps://github.com/square/javapoetJava 扩展活跃Square 出品,通过调用 Java API 来生成 .java 文件,很多 Gradle 插件在编译时生成代码背后实现都会用到它。
Paper Parcelhttps://github.com/grandstaish/paperparcelJava 扩展过时注解生成 Parcelable 对象的CREATOR 和 writeToParcel(...)
Bouncy Castle Cryptohttps://www.bouncycastle.org/Java 扩展活跃一个用于 Java 平台的开放源码的轻量级密码术包。
JaroWinklerSimilarityhttps://commons.apache.org/Java 扩展活跃字符串相似度比较算法
Moshihttps://github.com/square/moshiJava 扩展活跃目前对 Kotlin 兼容最好的 Json 解析库
Exoplayerhttps://github.com/google/ExoPlayerAndroid 音视频活跃知名视频播放库
Cronethttps://developer.android.com/codelabs/cronet#0Android 网络请求活跃Chrome 使用的移动端网络库。支持 HTTP、HTTP/2 以及 QUIC 协议
Rounded Image Viewhttps://github.com/vinc3m1/RoundedImageViewAndroid 界面组件过时用来实现各种 radius 的圆形 ImageView
Sticky Scroll Viewhttps://github.com/amarjain07/StickyScrollViewAndroid 界面组件活跃滑动列表的时候固定一个 View 在顶部
Lottiehttps://github.com/airbnb/lottie-androidAndroid 界面组件活跃知名动画库
FlexboxLayouthttps://github.com/google/flexbox-layoutAndroid 界面组件活跃Google 出品的一个在 Android 平台实现类似前端 Flex 布局的组件
card-stack-viewhttps://github.com/yuyakaido/CardStackViewAndroid 界面组件活跃滑动卡片组件,实现探探那种左滑 dis 右滑 like 的效果
Bugsnaghttps://github.com/bugsnag/bugsnag-androidAndroid 架构活跃崩溃手机,国内类似 bugly
Maverickshttps://github.com/airbnb/mavericksAndroid 架构活跃之前叫 MvRx,airbnb 开源的一套著名Android App 响应式开发框架。
Facebook Batteryhttps://github.com/facebookincubator/Battery-MetricsAndroid 架构活跃Facebook 出的一款方便检测应用耗电的 SDK
Tape by Squarehttps://github.com/square/tapeAndroid 架构活跃一个轻快的,事务性的,基于文件的 FIFO 的库
Seismichttps://github.com/square/seismicAndroid 传感器活跃Android 手机晃动检测库。没想到 Square 还出过这玩意儿。
rtl-viewpagerhttps://github.com/duolingo/rtl-viewpagerAndroid ViewPager 扩展过时扩展了 ViewPager 部分功能,现已被 ViewPager2 代替
groupiehttps://github.com/lisawray/groupieAndroid RecyclerView 扩展活跃方便 RecyclerView 显示复杂布局
Epoxyhttps://github.com/airbnb/epoxyAndroid RecyclerView 扩展活跃简化 RecyclerView 多 ViewType 场景下的开发
Relinkerhttps://github.com/KeepSafe/ReLinkerAndroid 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() 方法,用来把 ItemDataItemView 的关系成对注册,最后把它设给 RecyclerView 做 adapter 即可。

    groupie 从用法上看和 MultiType 应该类似,只不过它限定了每一个 ItemData 的写法,提供了 ItemBindableItem 很好地支持了后来出的 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 来实现了。

  • FlexboxLayoutConstranitLayout 出现之前的产物,由于是 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 的核心在于它的三大件,MavericksStateMavericksViewModel, 和 MavericksView,再配合它独有的 onEach 还有 withState 几乎就可以 cover 我们平时开发的大部分场景,并且能够简化代码,同时官方还提供了依赖用以方便地集成使用 ViewBinding 甚至 Hilt。

写到这里我突然想起这一个月来面试的不少同学,每次问题 App 架构,他们的回答总是,提到“数据驱动 UI 更新”就是 MVVM,提到“逻辑界面分离”就是 MVI。那么问题来了,如果我的应用是 MVI架构,但是我的数据需要关心大量的状态,并且这些状态又要驱动 UI 更新呢?很少有同学能够答好这个问题。恭喜你,Mavericks 就是用来解决这一问题的最好框架!

  • Tape, 这个相对简单,是 Square 公司开源的一个组队列相关的实现,主要包含 FileObjectQueueInMemoryObjectQueueObjectQueueQueueFile 这四个实现。关于队列没什么好说的了,FIFO 而已。这个库的存在就有点像 LRU 算法有 DiskLruCacheMemoryLruCache ,基于不同的介质去实现。

总结

总的来看,Netflix Android 客户端团队在开源库的选择方面,还是偏 Square、Airbnb 这样的开源大厂出品居多。而不得不承认的是这些开源库大部分都是被广泛使用,经得起考验的,不至于出一些稀奇古怪的问题,更不至于一段时间之后没人维护。

另外,相信大家也感受到了,他们团队相对而言还是比较快速跟进主流 Android 开发技术的,不管是语言层面还是架构层面,对 MAD 还是很努力地践行的。

而“自研”方面,与国内氛围不同,没有 KPI,没有面向晋级编程,既然能站在巨人的肩膀上,也 就不必去重复造轮子,相信大家也看出了 Netflix 其实并没有自己写什么框架在里面。不过考虑到 Netflix 观看时候的良好体验,我怀疑音视频那块估计有?可惜这不是我的擅长方向,如果有研究的小伙伴欢迎评论区补充。

最后还可以看出一点,大公司病同样也存在于他们团队。整个 Netflix Android 客户端存在很多已经过时、不再维护,或者 Google 官方已经有更好实现的开源库,然而他们客户端还是保留着这些过时的代码,没有做迁移,我估计要么也是“能用就不改”,要么就是“粘得太紧,实在改不动”吧。所以,难道全世界的公司,项目大了都会面临这样的问题?


-- END --


推荐阅读


继续滑动看下一个

扒一扒 Netflix 安卓客户端使用了哪些开源库

向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存