Flutter 开发一个 GitHub 客户端 _ 掘金技术征文,面试android

插件

Flutter的优势是在开发UI上,但由于Flutter使用自绘引擎,并不能无缝集成原生控件(Android 原生控件及iOS UIToolkit), 而原生控件有一个比较大的优势就是可以集成系统能力,比如可以调用相机(如surfaceView)、支持浏览网页(如webview),但在flutter中,由于绘制引擎skia只支持二维图形绘制,并不能直接结合原生功能,所以当我们要到这类原生相关的控件时,我们只能通过flutter插件来调用原生控件来实现,在gitme中,主要涉及的是如何打开github文档、issue、评论里的url链接内容。

Webview

现在我们需要一个webview控件,能在应用内显示h5网页,而要实现这个,我们只能通过flutter插件!

很多人问过我flutter中有没有类似于webview这样的widget,答案是现在没有,将来极大可能也不会有,原因很简单,如果在flutter中加一个webkit和v8你觉得flutter应用的安装包有多大?

好了,现在看看有没有现成的轮子,pub中搜到的flutter_webview倒不少,但大多数都不能直接来用,原因有两个:

  1. 我们需要对webview所在路由(android中的activity, iOS中的controller)的导航头进行一些自定义,比如当页内跳转过多时给导航栏右侧加一个直接关闭当前路由的button以避免要连续多次点击返回才能退出。

  2. 我们需要webview支持一套javascript bridge协议,已备日后方便集成h5功能。

但目前没有同时满足这两点的插件,所以,我们的webview插件还是得自己来写,最终我们通过:

Android: Webview + DSBridge-Andriod

iOS:WKWebview + DSBridge-IOS

实现了自己的webview插件。

其它插件

我们还用到了fluttertoast 和 shared_preferences 插件,前者用于一些需要提示的场景来弹toast, 后者主要用于应用配置持久化。

设计模式及架构

遵循合适的设计模式,会让我们的代码逻辑清晰且易维护,一般来说不同端上都会有一套成熟的设计模式,如iOS上的mvc、android上的mvp、前端的mvvm等,那么我们的flutter代码中应该遵循怎样的设计模式?要回答这个问题,我们得先看一下flutter官方给出的编程范式(Flutter框架编程范式)以及google团队创造flutter时的灵感起源React-Native。

React-Native和flutter

RN最大的特点就是状态驱动的响应式编程,简而言之就是应用程序维护一套状态(state),并提供一个UI模板,而模板可以绑定状态,然后当状态发生改变时框架根据状态的变化重新构建UI界面。可见,而整个过程中用户不会直接操作UI控件树,构建过程(包括底层优化逻辑,几React中的diff算法)由框架完成。

在Flutter中,和RN非常相似,用户可以创建有_状态(stateful)和_无状态(stateless) 的widget。 然后在build方法中声明UI模板,当状态改变时,通过setState方法通知flutter, flutter会在下一个frame中调用用户提供的build方法来重建UI, 而底层的优化,如对比状态更新前后widget树的变化,只渲染变化部分的最小集,这些工作由flutter框架来完成,正如RN中的diff算法也是由框架完成一样。

所以很明显, Flutter是一个响应式框架,忘记mvxx这一套吧,如果你非要在flutter中套用mvxx这一套设计模式,很可能就会变成过度设计。

Dart语言范式

Dart语言最主要的特点就是结合了编译性语言与脚本语言之所长,特点很多,在实际动手之前,我比较关注它最受诟病的一点:在flutter中,对于复杂一点的UI,嵌套层次太深!

这一点确实无法反驳,过多的嵌套确实让代码看起来很难维护,尤其是web前端开发者,早就受够javaScript “回调地狱 ”(callback hell)之苦,没想到现在到了flutter还是逃不掉。但其实,问题并没有那么糟糕,flutter中的嵌套和javascript中的回调嵌套是不同的,javascript中的回调嵌套一般是异步任务的回调,需要在回调中处理之前回调的逻辑, 而flutter中的嵌套一般来说并不是回调,而是UI widget的声明结构,它不需要再回调中再处理逻辑,所以,flutter中也就是嵌套层次深一些,但不会发生处理逻辑混乱。目前比较好的建议就是对于复杂的ui,最好将各个部分拆分成单独函数。

架构

其实flutter本身就是响应式的框架,我们只需遵循响应式编程的规范就行,但在程序逻辑结构上,我们也要多考虑一下。由于gitme主要是通过网络从github获取数据,然后再渲染UI. 我们可以在逻辑上对业务代码简单分成两层:底层数据IO+上层UI渲染

数据层

关于数据请求的配置、逻辑等不要在UI层去控制,而由数据层自己完成。这也就是为什么我们队http库的要求中一定要包含“支持请求/响应拦截器”,因为只有支持拦截器,我们才能将io逻辑更好分离。

UI渲染层

UI层我们主要使用的事是material组件库,但我们并没有直接使用 ScaffoldAppBar 这些基本每个页面都要用的组件,而是在其上包装了一层,目的是程序风格发生变化时,我们只需要在包装组件中统一修改即可所有页面生效,而避免全局去替换(也许你会说可以设置主题,但是主题的精细粒度是不够的,有些需要自定义的点主题并不支持)。除此之外,我们也封装了一些通用的自定义组件,如支持上拉加载、下拉刷新的无限列表。

编码

在想清楚上述问题后,我们对我们APP整体也就有了一个轮廓。接下来就是去逐一解决这些技术点即可。

UI布局

布局主要涉及Flutter中widget的使用,这一步可以结合google官方 Gallery 中的示例先摸索,等自己动手写上几个页面后,布局就会轻松很多,flutter组件非常多,但常用的也很固定。flutter sdk中的注释很详细,示例都在注释里(Flutter文档就是通过注释生成的), 在IDE中可以非常方便的跳转查看源码。总之,了解Flutter widget的第一资料就是源码。

Markdown支持

dart官方有一个markdown包,它可以将markdown文本解析成html。但是我们需要的是将markdown文本直接转化成flutter widget树,所以这个包是不能直接用的,但是,如果我们要自己实现一个markdown到flutter的解析器,也并非易事。于是,我们想到了markdown包,看能否把它将markdown语法转化为html这一步替换为从markdown到flutter的widget,顺着这个思路,我们实现了最终的markdown解析器,并且工作良好。但是有一个问题就是:markdown包只支持纯粹markdown语法解析,如果在markdown文本中嵌入html代码,html代码是不支持的,所以现在我们的markdown解析器只支持markdown语法,对内嵌html代码不支持。这个我们希望markdown包作者能在后续版本中支持内嵌html语法,或者等我这边腾出手再去给它提pr。

Emoji支持

Emoji支持是在markdown解析过程中完成的,将对应的emoji标记符先转换成markdown语法,然后再解析markdown。

Mock与缓存

由于gitme中使用的网络库是dio, 而dio的开发与迭代基本与gitme是同时的,我们也花了不少的时间在dio库的迭代上。

Mock

在开发测试时,我们测试数据放在了一个git项目中,让后push到github,App访问git数据时就从github上的测试项目拉取,但是有一个问题就是每次打开页面时都要等待几秒,直到数据获取完成,这极大的影响了我们的开发效率。为了解决这个问题,我们在dio请求拦截器中做了一层mock: 如果请求的是测试项目的数据,我们直接将本地工程对应的数据返回。这样一来有两个好处:

  1. 需要添加、改动测试数据时无需push到github远程仓库,本地该了就立即生效。

  2. 节省了网络请求时间。

缓存

由于github在墙外,国内访问有时可能会在速度和稳定性上存在一些问题,为了提高用户体验,我们需要一个合理的缓存策略。一般来说,http协议有一套完整的策略,需要服务器与客户端配合(通过header来传递缓存策略信息),但是我们调用的是github的接口,所以服务器对于我们来说是不可控的,所以我们不能使用http协议本身的缓存策略,这确实比较遗憾,但是现在我们又有了一种新的思路,这还是多亏dio支持拦截器,这让我们也可以在请求前/后来定制我们的缓存策略,值得一提的是,1.0中还没有加入缓存功能,这在我们后续版本迭代时会被支持。

链接拦截

如果在markdown中点击url链接时,会进行统一的预处理,比如:检查如果是github链接的话,将其转换为App内路由,这样就可以在APP内打开,避免跳到网页中去,如果是邮箱地址,则调用系统邮箱APP打开。

全局事件总线

gitme中有些场景需要全局状态共享,这和react中的redux或vue中的vux很相似,不过gitme中需要共享的状态并不多,所以我们采用了事件总线的方式来同步状态。

插件

正如上文所说,我们需要实现一个支持一种javascript bridge协议的webview插件,这个需要会原生开发,本身难度不大,就是gitme中实现了状态栏自动变色功能,会根据背景颜色自动调整前景文字、图标颜色,这使得我们的webview插件样式比较智能,并且非常容易自定义主题。同时也实现了几个API,以供javascript调用。

我们实现的另一个插件是版本更新插件,在其中我们也集成了mta统计sdk.

修轮子

在gitme中引入了一些第三方包,而其中近乎一半的第三方包无法直接使用,对于这些包,我们的做法是fork其源码,然后修复、定制,然后在gitme中依赖我们fork的repo(flutter支持直接依赖git项目)。在开发gitme的过程中,我们深深的体会到了生态的重要性。

总结

在1.0开发完成后,首先根据之前设定的目标,check一下完成度, 然后在谈谈开发过程中躺过的坑。

目标完成度

1.0的目标基本都已完成,但仍有几个已知问题:

  1. 不支持markdown中嵌套的html代码。
  2. SVG暂不支持;原因是flutter目前不支持svg,而第三方的包质量太差,所以初始版本暂不支持。
  3. 代码染色能力不足。

对于第一个问题,上文已经谈过了,待日后优化。而代码染色问题比较棘手,这主要是因为编程语言种类繁多,而靠谱的染色方式都是需要通过将代码转化为抽象语法树(AST,Abstract Syntax Tree),然后再进行关键字、方法名、类名等提取,然后应用不同样式渲染。如果是在web端,直接引入highlight.js,但dart中目前并没有这样的库,为此我们自己实现了一个简单的分析器,我们主要测试了Dart、Javascript、Java、php四种语言的成功率,gitme 1.0.0 结果如下:

语言成功率
Dart> 95%
Javascript> 90%
Java> 90%
php50%

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

总结

最后对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

相信它会给大家带来很多收获:

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
职业方向,才能在工作和能力提升中甩开同龄人。

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-BeplSbw9-1712632897027)]

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值