UME: ShowCode及WidgetInspectorService

1,169 阅读3分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

ShowCode

今天我们来看下代码展示功能是如何实现的

当我们点击功能列表的ShowCode时就会弹出当前路径下的页面(home_page)代码

Simulator Screen Shot - iPhone 13 Pro - 2021-11-04 at 11.34.56.png

该功能的UI显示相关代码在show_code.dart中,数据获取主要分为两个部分,第一部分获取到当前页面,第二部分获取页面代码

获取当前页面

在page_info_helper.dart中的_jsonInfo通过renderObject获取widgetID,然后通过WidgetInspectorServicegetSelectedSummaryWidget方法传入widgetID获取info数据

Map? get _jsonInfo {
  if (renderObject == null) return null;
  final widgetId = WidgetInspectorService.instance
      // ignore: invalid_use_of_protected_member
      .toId(renderObject!.toDiagnosticsNode(), '');
  if (widgetId == null) return null;

  String infoStr =
      WidgetInspectorService.instance.getSelectedSummaryWidget(widgetId, '');
  return json.decode(infoStr);
}

jsonInfocreationLocation中包含file

"creationLocation":**{\
        "file":"file:///Users/xxx/flutter_ume-master/example/lib/home_page.dart",\
        "line":20,\
        "column":12,\
        "name":"Scaffold"\
    }

然后简单做个处理组合一下,就变成了上面显示的package:example/home_page.dart

页面代码获取

首先拿到当前isloate所有脚本,通过遍历匹配uri是否包含当前文件名,如果包含则返回脚本的id

Future<String?> getScriptIdWithFileName(String fileName) async {
  ScriptList scriptList = await serviceWrapper.getScripts();
  final scripts = scriptList.scripts!;

  for (final script in scripts) {
    if (script.uri!.contains(fileName)) return script.id;
  }

  return null;
}

然后通过脚本的id拿到脚本对象,脚本对象中有一个source就是我们需要的页面代码

WX20211104-172600.png

最后就是一个富文本显示了, 文字高亮的话,就是写了一个DartSyntaxHighlighter并对一些关键词进行了高亮处理

WidgetInspectorService

官方介绍:api.flutter.dev/flutter/wid…

用于与WidgetInspector交互的服务,简单介绍一下几个method

forceRebuild 重建整棵树

这个方法是热重载时使用的, 但官方不推荐使用这种方式进行热重载

initServiceExtensions 注册服务的扩展

添加一些扩展方法用于调试,传入一个RegisterServiceExtensionCallback对象

typedef RegisterServiceExtensionCallback = void Function({ 
    required String name,
    required ServiceExtensionCallback callback}
);

toObject 转成对象

通过传入一个id返回一个dart对象

toObjectForSourceLocation

该方法跟上一个方法类似, 内部实现也是调用了toObject, 如果Object是Element类型的话则取Object.widget返回

@protected Object? toObjectForSourceLocation(String id, [ String? groupName ]) { 
    final Object? object = toObject(id);
    if (object is Element) {
        return object.widget;
    } 
    return object; 
    }

setSelectionById 设置选中对象

传入一个id如果改id有效则将该对象设置为选中对象

devToolsInspectorUri

获取VM Service 与 DevTools inspector uri

getParentChain 获取全部父节点

获取树的根部节点到ID所在节点的element或RenderObject

getProperties 获取node

通过diagnosticsNodeId获取diagnosticsNode的json对象

getChildren 获取子节点

通过diagnosticsNodeId获取子节点的json对象

getChildrenSummaryTree 获取自建子节点

通过diagnosticsNodeId获取子节点的json对象, 只引用包括由用户代码直接创建的子对象

getChildrenDetailsSubtree 获取所有子树节点

不经过任何筛选的全部子节点

getRootWidget 获取根节点

获取根节点元素

getRootWidgetSummaryTree

只显示摘要节点

getRootRenderObject

返回RenderObject

getDetailsSubtree

获取有当前节点为根节点的树, 可以传入subtreeDepth参数,控制返回级别

getSelectedRenderObject

返回当前选中节点

getSelectedWidget

返回当前选中Widget

screenshot 屏幕截图

获取当前屏幕截图,可以控制截图范围

好了今天的源码查看就到这了, 作为Flutter届的一个小学生,希望大家多多指教,有问题的地方一起讨论