Flutter 学习资料及笔记总结

也许是程序员天生的鄙视链作祟,后端出身的自己一直认为前端/客户端就是一个“画皮”的事,因此一直不愿意投资时间系统地学习前端技术栈。一般都是实在不得不做前端的时候,在 github 找个功能需求差不多的代码库,修改一下上线。开发速度倒是很快,但是出来的效果总是被评价为“程序员审美”。

一直在寻找一个性价比高的方案,希望能够真正 Write once, run anywhere. 对于桌面客户端,尝试过一段时间 Electron, 但是发布安装包的体积大以及web级别的性能使得只能在有限场景下使用。移动端,当前最火的自然是 RN. 但个人是在受不了RN中屁大点的事情都搞得复杂难用,因此一直也是敬而远之。而去年12月Google发布的Flutter却让自己有了眼前一亮的感觉。

RN vs Flutter

Flutter比RN晚出生两年,而在很多概念上,其实也是借鉴的RN。无论是从社区还是成熟度来看,Flutter都还有很长一段时间要走:

但是,Flutter的设计哲学更加简单,更符合自己的品味。举个例子,Flutter中,几乎所有的UI元素都是一个 widget, 没有那些乱七八糟故弄玄虚的概念,一切都非常直白。从上表的比较可以看出,其实技术层面,Flutter其实并没有绝对的优势,在社区和成熟度上还有明显的短板,但这些都不重要。重要的是,判断一个技术是值得投资,要看未来三五年中,这个技术有没有可能成为行业标准,尤其是在大公司引领下成为事实标准。

显然,Flutter具有这样的潜力。移动开发中,在 web/H5 无法覆盖的场景,在效率和成本的驱动下,跨平台开发会是行业的趋势。最近火热的 996.icu 也算是一种从侧面透露出以后并不需要那么多的客户端开发同学。另一方面,Flutter 是Google为下一代操作系统Fusion的重要布局,且有chromium项目加持。无论从战略还是项目层面,都是天空给的足够高,翅膀长的足够硬。从这个层面看,RN简直就是一群小学生在玩过家家了(开个玩笑,不要当真)。国内方面,无论是阿里还是腾讯,都开始在Flutter上进行布局和项目技术投入。需要特别指出的是,在Flutter之前,阿里是有自研 Weex的,具体项目上,闲鱼团队已经有在实际项目中使用 Flutter.

Flutter 学习资料及笔记

Flutter 可以简单的理解为一个使用Dart语言进行开发的跨平台UI框架。因此,入门需要学习的东西主要有两块:

  1. Dart语言;
  2. Flutter 框架;

Dart 语言设计之初是为了替代 Javascript, 因此,整体上没有那么多语言bug, 会比 JS 要更加符合后端同学的语言习惯。语言入门只推荐一个官方的 A Tour of the Dart Language 学习资料。看资料的过程中,可以结合 DartPad
写一些代码片段,辅助记忆和理解。Dart 语言学习笔记:

  • 一切皆对象,默认值都是null
  • 下划线开头的变量是私有变量,跟Golang的语言设计风格类似
  • 基础类型转换,依赖 parse 和 toString 方法
  • string是 utf-16, 有点非主流
  • 函数默认值必须是 const, 规避不可重入的问题
  • Dart的所有异常都是 unchecked exception,且可以抛出任意object作为异常
  • 构造函数可以取名称,便于阅读理解,但是这点改进对于引入的复杂度并不划算

整体看,Dart 引入的一些语言特性是 python + Java 的合体。语言上中规中矩,没有什么亮点。可以看成是 javascript 的静态类型版。但是,谁让Dart搭上了Flutter这趟潜力股,而Flutter又找了Google这个大干爹呢。老实学吧,反正也就一两个小时的事。

关于Flutter本身的学习资料,其官方网站的文档一如既往地保持了 Google 级文档的水准。但是官方文档有点大而全,可能没有足够时间通读,一时半会也不容易抓住重点。我推荐几个资料你一定要仔细阅读:

学习完以上资料,附带一些课程联系,你会花大约1~2个周末的时间。学完以后,你已经初步具备开发跨平台 app 的能力了。(我个人的情况是, 两个周末学习完上面的资料,并完成一个简单的 app 开发并提交到app store审核,相信你也能做到。)

在开发app过程中,你可能会查找组件,这里推荐阿里的flutter-go.

如果需要进一步深入,可以阅读学习其他人的代码

此外,如果你关注 Flutter 在桌面端的跨平台情况,由于官方还没有发布桌面支持的正式版本。推荐你当前先watch Desktop Embedding for Fluttergo-flutter 两个项目。

总结

在Google Fusion战略和明星项目chromium加持下,以及国内巨头积极跟入的背景下,花两个周末系统学习一下Flutter个人认为是一个潜在投资性价比很高的事情。另一方面,Flutter从去年12月才发布1.0正式版,整体成熟度还不是很高,因此在实际项目中并不建议太激进的引入使用,并且Flutter在一些原生支持上海不够完善。比如,使用Flutter接收其他app分享的内容,android平台下你可以根据How do I handle incoming intents from external applications in Flutter?来解决,但是在iOS平台,当前阶段则是彻底不支持。

四五年前iOS客户端开发炙手可热的机会已经一去不复返了,Flutter也许是下一个机会。

获取 Instagram 用户所有图片手记

我是一个 Instagram 重度用户,关注了很多有意思的 po 主,因此经常需要将这些 po 主的所有图片打包下载。(国外非常注重版权,下载图片只能个人使用,商业用途请严格遵循版权保护流程。)

ig 的账户分为公开账户和私有账户。这里只讨论公开账户的图片的获取方式。

我们知道在 ig 用户的 profile 业务可以看到用户发布的所有图片,例如:https://www.instagram.com/instagram/,即格式为:

很久以前,我们通过 https://www.instagram.com/{username}/?__a=1 的方式可以获取该用户的所有图片。但是这个方法被大家玩烂了,ig做了一些限制,先是下线了这个私有接口,后来又恢复了这个接口,但是需要用户处于登录状态。考虑到这个接口被下线过,继续使用该接口不确定性较大,且让帐户处于登录状态去调用这种私有接口被封号的概率是很大的。于是,尝试使用其他方式。

前端无秘密,ig 的接口其实还是比较奔放的。在用户 profile 页面转了一圈,发现其使用了一个通用的 graphql 接口来获取用户图片:

那么接下来的事情简单了,确定其请求的参数就可以模型请求获取用户图片了。

query_hash 参数

query_hash 在接口中的作用类似于让服务器知道客户端的版本,这个参数被 hard-coding 在前端的一个 js 文件中。在我的网络环境下,该 js 文件是 b55cb2cfaa46.js,值为 f2405b236d85e8296cf30347c9f08c2a.

该参数获取非常容易,唯一不太确定的是其更新的频率。从实际使用情况来看,这个值已经一个多月没有更新过了。因此,一周自动检测更新一次应该是没有问题的。

query 参数中的 variables 都是业务参数,看一眼就明白。但是,实际测试你会发现,所有的query参数都正确的情况下,服务器依然会返回 403. 二分排除了一下,发现是 header 中的 x-instagram-gis 是一个请求签名验证参数。只有该参数通过了验证,才能获得预期的返回。

x-instagram-gis 参数

签名的生成算法是:signature = md5({rhxGis}:{queryVariables}). 对应 js 实现:

rhxGis 参数可以通过用户页面的全局变量 window._sharedData 获取到:

queryVariables 对应上诉 variables 参数。

至此,关键参数获取方式都已搞定。可以开心的在 ig 上逛图啦。

扩展阅读

How to perform unauthenticated Instagram web scraping in response to recent private API changes?

Go 1.12 TLS 1.3 简单测试

《TLS 1.3 当前(2018.10)支持与部署之现状》中,我们提到 Go 将在 1.12 中支持 TLS 1.3. 作为一个 Gopher, 终于在前几天盼来了 golang 1.12 的发布。

但是从 release 日志看,本次对选择性的部分支持 TLS 1.3, 且默认处于关闭状态:

Go 1.12 adds opt-in support for TLS 1.3 in the crypto/tls package as specified by RFC 8446. It can be enabled by adding the value tls13=1 to the GODEBUG environment variable. It will be enabled by default in Go 1.13.

如果要开启 TLS 1.3, 需要设置环境变量:GODEBUG=tls13=1.

本次发布的 TLS 1.3 的 cipher suite 无法配置,也不支持 0-RTT 模式:

TLS 1.3 cipher suites are not configurable. All supported cipher suites are safe, and if PreferServerCipherSuites is set in Config the preference order is based on the available hardware.

Early data (also called “0-RTT mode”) is not currently supported as a client or server.

要知道,没有 0-RTT 的 TLS 1.3 是没有灵魂的,对本次版本的失望那是肯定的。但是依然在第一时间升级了 Go 版本,简单测试了一下国内网络环境下 TLS 1.3 与 1.2 的握手延迟。如果对 TLS 1.3 握手延迟还不太熟悉,可以参见拙文《TLS1.3/QUIC 是怎样做到 0-RTT 的》 以及 TLS 1.3 Handshake Protocol.

测试代码

需要说明的是,这个测试是不严谨,里面没有考虑 cipher suite 以及 early data 的差异。测试结果定性意义大于定量意义。

测试结果

测试使用的目标服务器地址是 blog.cloudflare.com:443, 我的网络环境下,ping 延迟为 226 ms (1-RTT).

从结果看,有如下结论:

  1. TLS 1.3 平均比 TLS 1.2 建立连接的延迟低约 1-RTT, 跟理论分析是吻合的。但是,
  2. 从 max 项可以看出,部分时候国内到目标服务器网络不稳定带来的波动比 TLS 本身协议优化的 RTT 大的多。因此,稳定高延迟的网络链路有时候比低延迟高抖动的网络更有实际意义。
  3. TLS 建立在 TCP 基础上,TCP 的握手延迟在 TLS 层面是优化不掉的,或者说不是 TLS 的管辖范围,因此,在允许的情况下,尽量复用连接。