Flutter For Web 已经发布半年多时间,跑在 Flutter 实践道路上的腾讯企鹅辅导团队是如何应用的?
今年 9 月,作为腾讯 Flutter 实践团队之一的我们,有幸参与了 GDD 大会上 Flutter 应用视频的录制,感受到国内众多开发者对 Flutter 的热情。两天时间,讲道理,其实没有太多的干货,但收获还是满满的。有那么点空闲的时间,也关注了一下其他的同学,大家讨论的重心还是第一天主会场的内容。我想吸引大家的一直是 Flutter 新版本 stable1.9 的重磅发布。
新版本一个重要功能就是 Flutter For Web 仓库合入 Flutter master 主仓库,意味着我们可以真正地使用一套代码、一套资源部署大前端。辅导团队经过一段时间的准备,使用 Flutter 开发的 Web 页面也即将发布,希望和大家分享下实践过程和踩坑实例,欢迎一起交流探讨。
一、发布准备
我们对辅导 App 中上课页学习简报页面进行改造,支持浏览器中打开。
- 2.0x
- 1.5x
- 1.25x
- 1.0x
- 0.5x
iOS 中打开 Flutter Web 页面
- 2.0x
- 1.5x
- 1.25x
- 1.0x
- 0.5x
浏览器中打开 Flutter Web 页面
网络 cgi 接口现网暂时没有配置,先使用假数据展示。开发过程中,我们涉及到 Flutter 页面转换、网络请求、与 Native 交互、cookie 等,最终的页面发布我们还需要在发布系统中配置。有关基础开发及发布的知识,大家可以关注互动视频大神 weiwei 的一篇分享:《如何使用 Flutter For Web 开发一个需求并上线》,文章介绍的很清楚,最终发布上线需要的产物是:
index.html:h5 访问入口;
main.dart.js:dart 代码转化成 js 后的产物;
assets:静态资源,包括图片、字体,以及我们定制的 js 文件。
二、页面改造
Flutter For Web 谷歌官方一直建议暂时不要在生产环境使用。但如果不尝试,我们永远不知道这里会藏有什么样的秘密,什么样的场景适合。对现有 Flutter 改造,增加对浏览器的支持,突破而不失稳重。
1. 增加 Web 支持
我们原先的版本使用 Flutter 1.5.4,增加 Web 支持,我们需要切换到最新的 master 分支,改造运行。
如果我们只是新建一个新的项目,只需切换到最新的 master 分支,创建一个新的项目即可。创建完成之后,根目录下会多出一个 web 文件夹,里面只有一个 web 入口文件 index.html。
2. 修改 dart:io 库
原有项目中如果直接运行 flutter run -d chrome,会发现控制器中 import 报错,原因是 dart: io 库不支持 web。io 库是 Flutter 中非常常用的库,主要是平台相关的一些 api,改造的第二步我们就需要屏蔽 dart:io 的引入。
Flutter For Web 最终运行的是在浏览器中的 js 代码,Flutter For Phone 使用,Platform 引擎与 Native 通信。js 在平台上是通过其他的系统支持(iOS 中的 JavaScriptCore) 与 Native 通信,二者是完全不同的方式,所以 dart: io 无法继续支持。
既然 dart: io 不支持 web,那我们仍然想使用原先的 Flutter 业务 UI 代码,该 如何实现(上文我们说过,我们想使用同一套代码、同一套资源整合大前端)?我们使用不同平台下支持的能力库区分。
UI 侧我们仍然使用同一套代码,逻辑侧通过 library 库分区 native 还是 web,逻辑侧对应不同的平台实现。这几天,我看到一个新的区分方法,简单而且实用:web 侧我们可以判断 0 和 0.0 是否是一个对象。
区分完不同平台,我们还需要辨别不同设备,这里我建议搭建 app 初始化的时候配置完成,后续方便实用。
3. 网络请求
原有 Flutter 项目我们通过 MJFlutter 调用 Native 的网络接口,实现数据请求。辅导 web 侧是通过 CGI 请求获得后台数据,现在 web 需要另一种方式,给大家推荐几种方式:
a. package:http/http.dart
pub 链接:https://pub.dev/packages/http#-readme-tab-
b. package:http/html.dart
c. package:dio/dio.dart
pub 链接:https://pub.dev/packages/dio#-installing-tab-
dio 这个网络库,大家之前可能用过,需要注意一点,3.0 之前的版本 Flutter For Web 不支持 (dart:io)。3.0 之后的版本,这个库经过官方大改造,现已支持 Flutter For Web 开发。
我推荐的是 dio 这个库,使用起来会比较方便,参数简单好理解。
有了基本的网路请求,配置完 CGI,接下来就是界面的展示。但是你会发现,所有的业务请求都没有回包,无法得到数据。如果作为移动端开发,没有经常接触到 http 请求,一下子发蒙,我觉得可以理解。这个是 Web 开发中经常遇到的 跨域问题。前端开发们这里可以举手了,这个问题我会。简单的处理方式就是开发过程中挂上一个代理,具体就不详细展开了。
网路问题解决,进入发布调试,上文我们介绍过 Flutter For Web 的最终产物是三个文件。如何发布,前端同学又可以举手了。有一个简单的方式:github pages(配置方法:https://pages.github.com/)。
三、JavaScript 扩展
与使用 Flutter 实现的页面不同,Flutter For Web 的页面使用 Http 请求获取后台数据。Http 请求中很重要的一点是 header 中的 cookie,这里就需要通过 dart 与 js 之间的交互,还是要称赞下 Flutter 团队的实力。
官方说明:https://dart.dev/web/js-interop
pub 地址:https://pub.dev/packages/js
新建 native_api.js 文件
dart 封装 js 方法
index 入口文件中引入 js 文件
添加完 js 支持后,dart 侧调用 getStringFromJS 方法,并打印结果。
通过 js.dart 这个库,可以实现 web 侧的主要功能。例如 cookie、localStorage。
native_api.js 中声明基本方法
dart 封装 js 方法
处理完 Web 侧的基本能力后,需要部署 dart 转成 js 后,与 native 交互的能力。我们知道,目前 app 中 native 与 web 交互的方式主要通过 jsBridge。Native 侧我们已经有了成熟的体系主动调用和接收调用 web 的能力,这部分我们可以不需要修改,减少开发工作量。在 Flutter 侧我们需要添加交互支持,也就是需要在 native_api.js 中添加与 native 交互的能力。
JavaScript 调用 Native 的方式,主要有两种:注入 API 和 拦截 URL SCHEME,你可以根据自己的业务能力,选择合适的方式。相较于 JavaScript 调用 Native,Native 调用 JavaScript 比较简单,不管是 iOS 的 UIWebView 还是 WKWebView,还是 Android 的 WebView 组件,都以子组件的形式存在于 View/Activity 中,直接调用相应的 API 即可。
例如 iOS 中 JavaScript 调用 Native,设置 webView 的 title:
四、展望
整体来说,Flutter For Web 达到成熟还有一段时间。在这段时间里,尽早布局,未免不是一件好事。Flutter For Web 现阶段的使用场景并不多,不如直接使用 Web 开发便捷、稳定。但我们可以通过 Flutter,拉近与大前端的距离,感受大前端的魅力,做一个真正的大前端开发。
腾讯企鹅辅导团队会继续实践,不管是 Flutter 实现的页面,还是 Flutter 转 Web 的页面。Flutter For Web 一个复杂的场景,我们会尝试降级及热更新能力,与 Web 同学通力合作,封装 App 和 Web 的基础 API、集成 CI 等,欢迎与我们一起交流。
技术服务于业务,业务推动技术,二者并行,提升用户体验,Flutter 道路上期待大家的反馈。
专家介绍:
涂金林,来自江苏苏州。2014 年和 2017 年分别获得东南大学本科和硕士学位。2017 年加入腾讯在线教育部,主要从事移动客户端开发。入职以来,参与腾讯企鹅辅导、腾讯课堂 iOS 和 Android 开发,腾讯企鹅辅导 iOS 负责人。目前主要担任腾讯在线教育 Flutter 项目技术负责人。
评论