滴滴DoKit For Flutter正式开源,还是原来的“味道”

在Flutter中,每个页面对应一个Route,通过Navigator管理Route。Navigator内部会包含一个Overlay Widget,每个Route最终都转化成一个_OverlayEntryWidget添加到Overlay上。这个地方可以把Overlay理解为Android中的FrameLayout,内部的View上下叠加。每打开一个新的Route,都相当于往FrameLayout添加一个新的子View。Navigator会存在嵌套的情况,即Route所创建的页面本身也包含一个Navigator,比如App的根Widget是MaterialApp(自带Navigator),Route页面也用MaterialApp包裹,就会形成Navigator嵌套的情况。还是以FrameLayout来理解,这也就相当于嵌套的FrameLayout。 路由信息功能会打印出当前栈顶页面所处的Route信息,如果存在Navigator嵌套的情况,也会向上遍历打印出每层Navigator的信息。具体的实现方式是,先获取当前根app根Element,可以使用WidgetsBinding.instance.renderViewElement作为根Element,再通过递归调用element的visitChildElements方法,向下遍历整棵树找到最后一个RenderObejctElement,该RenderObejctElement即为当前显示的页面上的元素。然后使用ModalRoute.of(element)方法即可获取到当前页面的路由信息。

至于嵌套的路由信息,则可以通过找到的RenderObejctElement的findAncestorStateOfType方法,反向向上递归遍历,获得所处的Navigator的NavigatorState,再调用ModalRoute.of(navigatorState.context),如果返回不为空则表示存在嵌套。

方法通道


Flutter的Method Channel调用最终都会经过ServiceBinding.instance._defaultBinaryMessenger这个对象,类型为BinaryMessenger,由于这个对象是个私有对象,无法动态进行修改。不过查看ServiceBinding的源码可以发现这个对象是通过ServiceBinding.createBinaryMessenger方法创建的,通过使用flutter的mixins,可以实现对该方法的重写。 我们知道,ServiceBinding实际也是通过mixins在WidgetsFlutterBinding.ensureInitialized方法中一起被初始化的,所以只要在WidgetsFlutterBinding这个类额外mixin一个继承于ServiceBinding并且重写了createBinaryMessenger方法的类,就能实现对ServiceBinding中createBinaryMessenger的覆盖,代码如下:

class DoKitWidgetsFlutterBinding extends WidgetsFlutterBinding

with DoKitServicesBinding {

static WidgetsBinding ensureInitialized() {

if (WidgetsBinding.instance == null) DoKitWidgetsFlutterBinding();

return WidgetsBinding.instance;

}

}

mixin DoKitServicesBinding on BindingBase, ServicesBinding {

@override

BinaryMessenger createBinaryMessenger() {

return DoKitBinaryMessenger(super.createBinaryMessenger());

}

}

接下去把runApp的入口调用改成如下,就能实现BinaryMessenger的替换 static void _runWrapperApp(DoKitApp wrapper) { DoKitWidgetsFlutterBinding.ensureInitialized() …scheduleAttachRootWidget(wrapper) …scheduleWarmUpFrame(); } 至于Method Channel具体信息的捕获,只要hook住BinaryMessenger.handlePlatformMessage和BinaryMessenger.send两个方法就行了,具体可看DoKitBinaryMessenger这个类

控件检查


和路由功能类似,通过从根element向下遍历,在遍历过程中记录和选中的View有交集的所有RendereObjectElement,并且记录用以标志当前页面的RendereObjectElement,获取它的Route信息。遍历完成后,遍历记录下来的RendereObjectElement,过滤掉Route信息和当前页面不一致的,这些Element属于被遮盖住的页面。然后通过比对RendereObjectElement和选中View的交叉区域面积占RendereObjectElement面积的比例,占比最大的为当前选中的组件。 在Debug模式下可以获取选中组件在工程中的代码位置,将WidgetInspectorService.instance.selection.current赋值为选中element的renderObject,再调用WidgetInspectorService.instance.getSelectedSummaryWidget方法,会返回一个json字符串,解析这个字符串就能获取源码文件名、行列信息等。

日志查看


日志查看功能比较简单,只要使用runZoned方法替代runApp,传入zoneSpecification,就能为日志输出设置一个代理函数,在这个代理函数内进行日志捕获,同时,还可以为onError设置一个代理函数,在这里将捕获的异常也会传入到日志当中。

帧率

使用WidgetsBinding.instance.addTimingsCallback可以统计帧率信息,在每帧渲染完成时会触发回调,包含该帧渲染的信息。

内存

同VM信息,使用VMService可以获取到内存详细使用信息。

网络请求


Flutter自带的网络请求通过HttpClient类发送,只要hook住HttpClient的创建就可以hook整个网络请求的过程。查看HttpClient的构造函数可以发现,如果存在HttpOverrides,就会使用HttpOverrids来创建HttpClient

factory HttpClient({SecurityContext? context}) {

HttpOverrides? overrides = HttpOverrides.current;

if (overrides == null) {

return new _HttpClient(context);

}

return overrides.createHttpClient(context);

}

所以这里重写了一个HttpOverrids

class DoKitHttpOverrides extends HttpOverrides {

final HttpOverrides origin;

DoKitHttpOverrides(this.origin);

@override

HttpClient createHttpClient(SecurityContext context) {

if (origin != null) {

return DoKitHttpClient(origin.createHttpClient(context));

}

// 置空,防止递归调用,使得_HttpClient可以被初始化

HttpOverrides.global = null;

HttpClient client = DoKitHttpClient(new HttpClient(context: context));

// 创建完成后继续置回DoKitHttpOverrides

HttpOverrides.global = this;

return client;

}

}

替换HttpOverrides

HttpOverrides origin = HttpOverrides.current;

HttpOverrides.global = new DoKitHttpOverrides(origin);

hook住HttpClient方法后,对于请求和返回结果的hook过程就和Android中的HttpUrlConnection类似了,具体可以看DoKitHttpClient、DoKitHttpClientRequest、DoKitHttpClientResponse三个类。

版本API兼容


Flutter版本更新还是比较快的,每一个大版本更新都会带来一些API的变更,目前DoKit的方案需要重写一些framework层的类,在兼容多版本时就会有一些问题。以上面的BinaryMessager为例,1.17版本只有四个方法,用来hook的DoKitBinaryMessager是这么写的

class DoKitBinaryMessenger extends BinaryMessenger {

final MethodCodec codec = const StandardMethodCodec();

final BinaryMessenger origin;

DoKitBinaryMessenger(this.origin);

@override

Future handlePlatformMessage(String channel, ByteData data, callback) {

ChannelInfo info = saveMessage(channel, data, false);

PlatformMessageResponseCallback wrapper = (ByteData data) {

resolveResult(info, data);

callback(data);

};

return origin.handlePlatformMessage(channel, data, wrapper);

}

@override

Future send(String channel, ByteData message) async {

ChannelInfo info = saveMessage(channel, message, true);

ByteData result = await origin.send(channel, message);

resolveResult(info, result);

return result;

}

@override

void setMessageHandler(

String channel, Future Function(ByteData message) handler) {

origin.setMessageHandler(channel, handler);

}

@override

void setMockMessageHandler(

String channel, Future Function(ByteData message) handler) {

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

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

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

img

img

img

img

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

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

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

感觉现在好多人都在说什么安卓快凉了,工作越来越难找了。又是说什么程序员中年危机啥的,为啥我这年近30的老农根本没有这种感觉,反倒觉得那些贩卖焦虑的都是瞎j8扯谈。当然,职业危机意识确实是要有的,但根本没到那种草木皆兵的地步好吗?

Android凉了都是弱者的借口和说辞。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

所以,最后这里放上我耗时两个月,将自己8年Android开发的知识笔记整理成的Android开发者必知必会系统学习资料笔记,上述知识点在笔记中都有详细的解读,里面还包含了腾讯、字节跳动、阿里、百度2019-2021面试真题解析,并且把每个技术点整理成了视频和PDF(知识脉络 + 诸多细节)。

以上全套学习笔记面试宝典,吃透一半保你可以吊打面试官,只有自己真正强大了,有核心竞争力,你才有拒绝offer的权力,所以,奋斗吧!骚年们!千里之行,始于足下。种下一颗树最好的时间是十年前,其次,就是现在。

最后,赠与大家一句诗,共勉!

不驰于空想,不骛于虚声。不忘初心,方得始终。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 诸多细节)。

[外链图片转存中…(img-cGbQAFVg-1713682047552)]

以上全套学习笔记面试宝典,吃透一半保你可以吊打面试官,只有自己真正强大了,有核心竞争力,你才有拒绝offer的权力,所以,奋斗吧!骚年们!千里之行,始于足下。种下一颗树最好的时间是十年前,其次,就是现在。

最后,赠与大家一句诗,共勉!

不驰于空想,不骛于虚声。不忘初心,方得始终。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 18
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值