本文来自作者 Zm 在 GitChat 上分享「 如何更加安全、高效地利用开源项目」,「阅读原文」了解更多知识。
「文末高能」
编辑 | 黄飞鸿
前言
在平时的开发过程中,难免会遇到这样那样的难题,或者一些繁琐且不想纯手工完成的功能,对于这些问题,解决的姿势有很多种,可以通过同事间的交流、上网查资料、去官网找文档等,随着开源的推动和完善,寻找合适的开源项目支持,绝对是一个很好的方法。
如今市面上的开源项目鱼龙混杂,并且有一些项目早已停止更新维护,跑 demo 的时候,怎么用怎么正确,一放入项目,却发现哪哪都不合适。
比如低版本下才可以运行,高版本删去一些方法,再或者与一些新技术的包冲突等,在众多开源项目中,我们应该以何种姿势去选择最佳方案?且听我慢慢道来。
PS:目前我主要是做手机客户端开发,以下的例子会举一些日常开发的例子。
正确理解、确定需求
我喜欢苹果,可是你给了我一车香蕉,然后你说你被自己感动了,问我为什么不感动。
我无言以对,然后你告诉全世界,你花光了所有的钱给我买了一车香蕉,可是我却没有一点点感动,我一定是一个铁石心肠的人!我的人品确定是有问题的!我只是喜欢苹果而已啊。
对于这样的问题,在我们的开发过程中也经常遇到,产品经理只是想要一个苹果,而我们却给他送来了一大包香蕉,后来发现哪哪不合适,又去和产品经理确定需求,才发现自己想的是错的。
相信这样的例子,在每个人身边都有过,因为没有及时沟通,造成后期维护成本大大提高,如果发现的早还好,在面临上线出现这样的问题,这一定是晴天大霹雳。
正确理解、确定需求,对开发中选取第三方开源或者原生都是有很大帮助,可以大大降低后期维护成本。
前段时间公司要接入摄像头来完成视频直播功能,采用 m3u8 格式实现,后期也不会有其它格式接入,从开发者文档中看到,Android 原生控件仅支持 MP4 格式,对于其它格式的兼容,还存在很大问题,也就是说没法完美兼容 m3u8。
此时,我们仅需要找到 m3u8 格式支持的方案就好,在搜索的征途中,我们大大地缩小的范围。
兼容性
做客户端开发,对于兼容性的话题,总是有千言万语,从最初写布局到后来的集成,再到后来系统的升级,无时无刻不在与兼容性打交道,尤其是在 swift 刚诞生的那一两年,每个大版本都会大改 api,这就有点扯淡了,搞的开发者心力交瘁,企业也不敢轻易尝试使用。
对于布局的适配的兼容性,今天不做讨论,接着上面视频对接的话题继续撸下去,经过一番对比,我把目标锁定在了 Google 的 ExoPlayer 和 bilibili 的 ijkplayer,这两个都是开源项目,都可以在 github 找到源码,地址如下,点击可跳转:
ijkplayer的github地址:https://github.com/Bilibili/ijkplayer
ExoPlayer的github地址:https://github.com/google/ExoPlayer
我最初的选择方案更是倾向于 ijkplayer,对国内开源项目本来就有一种特别的情感,国货当自强,和朋友讨论的时候,几个朋友也是推荐我 ijkplayer,这其中也有B站的哥们。
但他没参与到这个开源项目中,在最初跑 demo 的时候,确实可以完美播放 m3u8,当我把他放到我们项目中去的时候,发现报错了,再次检查下导入的包,如下:
dependencies {
# required, enough for most devices.
compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.3'
compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.3'
# Other ABIs: optional
compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.3'
compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.3'
compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.3'
compile 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.3'
# ExoPlayer as IMediaPlayer: optional, experimental
compile 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.3'
}
发现导入的包没问题,打开源码看了下,是包的内部有冲突了,如下:
defaultConfig {
minSdkVersion 21
targetSdkVersion rootProject.ext.targetSdkVersion
}
最低支持21的版本,和项目有冲突,解决方案有三种,不导入64位的包,或者自己修改源码后重新编译,最后一种不现实,就是改公司项目的最低版本,我们目前还是有一部分 Android 4.3 的用户。
一定会有更好的方案,嗯,一定会有的,抱着试试看的态度,无意间发现了ExoPlayer。
通过一番查阅资料,在ExoPlayer的开发者文档中可看到
ExoPlayer’s standard audio and video components rely on Android’s MediaCodec API, which was released in Android 4.1 (API level 16).
Hence they do not work on earlier versions of Android. Widevine common encryption is available on Android 4.4 (API level 19) and higher.
最低支持的版本是 Android 4.1,公司目前项目,最低支持是 Android 4.2,挺符合我们的口味。
总结:兼容性一直是一个很繁琐的问题,版本更新太快,技术不断更新换代,一些不安全或者没必要的方法,不断的从 API 中删去,接着迎来了一些新加入的 API,合理的考察和调研,可以省去很多弯路。
健全性
对于健全性,主要体现在文档的健全性和资料的健全性,如果是一个全新的技术,官方没有提供健全的 API,市面上还没有一些集成文档,这类的开源项目,最好别介入到项目中,作为第一个尝试吃蜘蛛的人,可以吃到的是一嘴的苦水。
最初我在测试 ijkplayer 的时候,首先,简单浏览了下内容,知道了个大概采用什么技术,接着就去找文档,天哪,我只看到了集成时候需要导入的包和编译采用的环境、工具,还有,就是我只找到了 sample。
这就尴尬了,这么大而优秀的项目,居然没有官方文档,瞬间好感下降到了负一层,去网上搜了下资料,资料还是很健全的,有很多优秀的开发者在集成后,把一些必要的注释就加上去了,看起来一目了然。
后来在调研Google的ExoPlayer的时候,发现有了质的差距,如下:
ExoPlayer 源码地址:
https://github.com/google/ExoPlayer
ExoPlayer api地址:
http://google.github.io/ExoPlayer/doc/reference/
ExoPlayer 开发者指南:
https://google.github.io/ExoPlayer/guide.html
这真的太棒了,集成的时候,可以解决少走很多弯路,遇到问题,也有了一些解决方案,扩展的时候,也为自己增加了几分信心。
想起了中学时候学校的一句标语:「细节决定成败,态度决定高度」。在平时使用或者学习第三方开源项目的时候,实现功能并不是第一要素,更应该关注 API 和资料的健全性。
这点,我一直很欣赏 Google 和 square,Google 先不提,在学习 square 的 retrofit 的时候,API还是给了我很大的帮助,里面写的确实挺详细,一目了然,每个注解都有详细的说明,让学习者感到更加亲切。
实现原理
对于实现原理,一些初、中级开发者并不关注这个话题,总觉得自己看不懂源码,看不懂那些所谓的高深技术,这个就是一个错误的态度,源码看不懂也很正常,诸如 ijkplayer 通过封装、修改和扩展 FFmpeg 去实现。
FFmpeg,这个确实比较高深,虽然学过一段时间 C 语言,搞过一段时间FFmpeg,但对于内部一些代码,看的同样很吃力,但文档总可以看得懂的,再或者网上那么多资料。
总可以了解个大概,至少可以知道 ijkplayer 支持的格式、采用的技术、解码的方式、需要的包…
之前一个前辈给我的忠告,如果一项技术,一个团队没人很熟悉,没人阅读和了解过源码,最好不要使用,一旦使用了,以后很可能会带来一大堆繁琐的问题。
确实是这样子的,就像三年多前在一家外包公司的时候,那时候市面上还没有太多关于即时聊天的文档,当时的第三方也没那么多选择,公司决定使用 xmpp + openfire 去实现。
而那时候我们团队没人接触过这一块内容,项目在爬行中推动,一个加好友的功能,把一个同事搞了好几天(这不否认那位同事的能力和粗心,因为英语的问题,没去看官方文档,同时也没过多的做调研)。
我很欣赏曹操,很欣赏他的疑人不用,用人不疑。如果曹操是一个程序员,一定是一位很优秀的代码家,以曹操的性格,一定会把一门技术吃透,然后再学以致用,举一反三,尽可能把一门技术发挥到极致。
性能
不管采用什么样的开源项目,性能绝对是一个很重要的参考,就算这个项目写得再好,功能齐全,一旦性能有问题,这将是致命一击,就像一个失去双手的运动员,长、短跑都是第一,此时让他去参加乒乓球比赛,再牛逼的教练也是一脸懵逼。
回到刚才的话题,再 ExoPlayer 和 ijkplayer 中的选择,一大部分原因是因为性能方面的问题,性能问题,直接把矛头指向了硬解码和软解码的区别。
硬解码:就是调用 GPU 的专门模块进行解码,由显卡核心 GPU 来对视频进行解码工作。
软解码:通过软件让 CPU 来对视频进行解码处理。
相信对于软解码和硬解码,大部分人都不陌生,这里不做多与赘述。
一图胜千言,做了一下对比:
上面对比中一个是功耗一个是总功耗,这个也很容易理解,GPU的电路更复杂,并行运算能力要远远高于CPU,于是耗电量就更高,GPU功耗大,但运行速度提升更多,功耗 = 功率 * 时间,所以就算功率乘个4,但是时间除以个10,总耗能还是降低。
对于硬解码和软解码的选择,这个真心说不上哪个更好,根据项目的需要,现在几乎所有的设备都支持硬解码和软解码,仅支持一种的 Android 移动设备已经属于古董级的,我是没见到过,之前更多的人愿意选择软解码,更大的原因是因为硬件解码支持的格式较少,而软解码对于格式是不受限制的。
现在随着硬件的不断提高,解码技术的不断成熟和完善,我是更倾向硬解码,但硬件提升的同时,CPU 也在不断的优化和提高,现在也不需要像之前那样尽可能节省 CPU。
现在处于性能过剩的时代,CPU 已经很难处于负荷状态,选择软解码或者硬解码都是没有谁对谁错,刚刚图上已经贴出和标记两者的优点,根据项目需要选择。
当时选择硬解码的 ExoPlayer,是因为只需要播放 m3u8 格式的视频,画面上没有那么高的追求,对于这样的需求,硬解码更符合公司的口味和用户的体验,至少可以节省更多的电量。
功能与扩展
对于产品经常改需求,这是常有的事,我们更多的时间不应该是放在和产品经理撕逼,而是如何更好的应对这个问题。
刚学软件开发的时候,书上就提到,好的程序员,会更好的考虑代码的可维护性、可重用性、可扩展性和灵活性。
再接入一个第三方之前,熟悉它的功能是在所难免的事,就是因为某个和某几个功能吸引才导致我们采用这个第三方,为了方便以后扩展,还是应该多读几遍开发者文档,尽可能多的了解和熟悉内部结构,在开发者文档,一般都会有详细的说明。
对于扩展性,这个就离不开文档和源码了,总不能自己莫名其妙的写代码,这不现实,我觉得每个合格的程序员都应该养成阅读源码的好习惯,这对自身的提高和功能的扩展都有很大的帮助。
集成性
对于集成性,我第一反应就是想到了微信和支付宝支付,这简直就是天壤之别,两年前的时候,我和一个同事分别接入支付宝和微信支付,我接入支付宝,加上阅读文档和跑 demo,不到一个小时就跑通了。
而他接入微信支付的时候,接了一天还没搞定,然后和我说微信支付的各种坑,当时也是半信半疑,就算坑了点,也不至于需要一天多吧,就这么点内容。
后来有一次接了个私活,也是需要接入支付宝和微信支付,支付宝的文档很全很详细,微信的文档乱七八糟,更恶心的是回调的类还必须是一个固定包下面的固定类名,严重破坏了项目的包结构,深深的鄙视。
对于开放的 SDK,我觉得应该给接入者提供更加全面的文档,站在别的位置考虑下问题。
总结
如何更加安全、高效地利用第三方开源项目,为了提高以后代码的可维护性和可扩展性,我们应该更多的去调研和阅读开发者文档,磨刀不误砍柴工,一个好的开发者,应该把更多的时间放在思考和调研,而不是速度完成需求,然后把更多的时间放在改 bug。
彩蛋
让真正的前端牛人带你采坑
公众号内回复「大漠穷秋」
快速上手 Angular
「阅读原文」了解更多知识