Flutter 百题斩#15 | 列出 SDK 所有 StatelesWidget 组件


最近在着手开发我的 《匠心星问》 ,它定位是一款 题库 应用,将集题目浏览、发布、解答、做题为一体。打算第一步先以 Flutter 为核心,准备题库资源。于是诞生《每日一题》 系列,准备精心设计一些 Flutter 的问题与解答,作为题库的养料。

加下来的几题,将从一个需求逐步演进,让答题者给出方案设计。本题的焦点是探讨:

列出 Flutter SDK 中所有 StatelesWidget 组件


1. 题目概述

请你设计一套方案,通过 dart 的命令行脚本,分析并提取 Flutter SDK 中所有的 StatelesWidget 的派生类。基础代码如下所示,命令行中传入 flutter_sdk 路径。题目考查:

  • 对 Flutter SDK 文件目录的了解
  • 对文件操作接口熟悉度
  • 解析 Dart 类和整理数据的能力
dart 复制代码
void main(List<String> args) async {
  int length = args.length;
  if (length < 1) {
    print('run with <flutter_sdk_path>');
    return;
  }

  final flutterSdkPath = args[0];
  print('Parsing Flutter SDK at: $flutterSdkPath');
  await parser(flutterSdkPath);
}

Future<void> parser(String sdkPath) async{
  /// TODO 解析 sdk 中所有的 StatelessWidget 派生类
  /// 得到组件名列表
}

2. 思路分析

实现,我们应该知道,Flutter SDK 中的组件都在 packages/flutter/lib/src 下。随便点击一个组件,进入源码,悬浮时就可以看到路径:

可以进入对应的文件夹中参观一下,如下所示。接下来就需要遍历其中的文件,收集期望的数据。


文件有了,但是如何解析 dart 文件是比较头疼的。如果单纯自己使用正则匹配,虽然可行,但是操作太复杂。Flutter 官方有一个 analyzer 的类库,可以分析 Dart 代码。包括在上下文中的类继承信息、字段、方法等,这对于代码


3.代码实现

第一步,遍历源码文件夹,找出所有的 dart 文件:

dart 复制代码
String srcDir = p.join(sdkPath,'packages','flutter','lib','src');                
                                                                                 
final List<String>  dartFiles = [];                                              
await for (FileSystemEntity entity in Directory(sdkPath).list(recursive: true)) {
  if (entity is File && entity.path.endsWith('.dart')) {                         
    dartFiles.add(entity.path);                                                  
  }                                                                              
}                                                                                

创建一个 RecursiveAstVisitor 访问器,在 visitClassDeclaration 回调中,可以访问类的声明信息。在其中可以得到其父类信息,校验名称是不是 StatelessWidget 即可:

dart 复制代码
class StatelessWidgetVisitor extends RecursiveAstVisitor<void> {               
  final List<String> components = [];                                          
                                                                               
  @override                                                                    
  void visitClassDeclaration(ClassDeclaration node) {                          
    final String className = node.name.lexeme;                                 
    final ExtendsClause? extendsClause = node.extendsClause;                   
                                                                               
    if (extendsClause != null) {                                               
      final String superClass = extendsClause.superclass.name2.lexeme;         
      if (superClass == 'StatelessWidget') {                                   
        components.add(className);                                             
      }                                                                        
    }                                                                          
    super.visitClassDeclaration(node);                                         
  }                                                                            
}                                                                              

AnalysisContextCollection分析上下文集合,用于解析 Dart 代码, 其中 includedPaths 是要分析的目录。然后遍历每个 Dart 文件进行分析,ResolvedUnitResult 表示解析 AST 成功。

接下来创建 StatelessWidgetVisitor,在 accept 时会让访问者遍历 AST,从而触发 visitClassDeclaration 执行收集工作:

dart 复制代码
final List<String> components = [];                                                             
final AnalysisContextCollection collection = AnalysisContextCollection(includedPaths: [srcDir]);
                                                                                                
for (String file in dartFiles) {                                                                
  try {                                                                                         
    AnalysisContext context = collection.contextFor(file);                                      
    SomeResolvedUnitResult result = await context.currentSession.getResolvedUnit(file);         
                                                                                                
    if (result is ResolvedUnitResult) {                                                         
      StatelessWidgetVisitor visitor = StatelessWidgetVisitor();                                
      result.unit.accept(visitor);                                                              
      components.addAll(visitor.components);                                                    
    }                                                                                           
  } catch (e) {                                                                                 
    // Skip files with errors                                                                   
  }                                                                                             
}                                                                                               

最后 components 列表就是收集的所有组件名,这里做了一个字母排序,并将其输出到了 stateless_components.md 中。这样就完成了第一版的 StatelesWidget 组件提取器:

dart 复制代码
components.sort((a,b)=>a.compareTo(b));
File outfile = File('stateless_components.md');
await outfile.writeAsString(components.join("\n"));
print('Results saved to: ${outfile.path}');

虽然输出了结果,不过目前的解析器功能还非常薄弱,甚至连父类的父类是 StatelesWidget 的组件都解析不出来。接下来的题目将会逐步优化,以及收集更多的数据信息。通过解析可以全方位查看某个版本 Flutter SDK 组件的内容。


4. 小结

本题的核心,在于接触 如何用工程化的手段解析 SDK 并提取结构化信息。相比手工检索或靠阅读源码,本题所展示的方法借助 Dart 官方的 analyzer 工具链,实现了自动化分析和提取,非常适合做代码扫描、组件统计、依赖图谱等任务。

这正是《匠心星问》系列题库设计的初衷:不仅是"会不会用",而是鼓励开发者去思考 "怎么做才更合理、更系统" 。希望你在解决本题的过程中,收获的不只是 Flutter 技术本身,更是一种解决问题的方式。

后续的《每日一题》也将持续围绕实战问题展开,欢迎持续关注和参与,一起构建一个 开放、精致、有深度 的 Flutter 题库生态!

你是否也有想出的题目,欢迎投稿加入《匠心星问》共同打造!


如果你有其他的看法,或者有什么想要的题目、或者想提供题目和答案,都欢迎在评论区留言。更多文章和视频知识资讯,大家可以关注我的公众号、掘金和 B 站 。

相关推荐
菠萝加点糖22 分钟前
Android 使用MediaMuxer+MediaCodec编码MP4视频
android·音视频·编码
ideal树叶1 小时前
flutter 中 的 关键字
flutter
雨白1 小时前
手写 MaterialEditText:实现浮动标签(Floating Label)效果
android
CYRUS_STUDIO3 小时前
使用 readelf 分析 so 文件:ELF 结构解析全攻略
android·linux·逆向
世界不及妳微笑4 小时前
Flutter 记录应用授权登录踩坑之旅
flutter
小强开学前4 小时前
WebView 静态页面秒加载方案要点
android·webview
纽马约4 小时前
Android Room的使用详解
android
游戏开发爱好者85 小时前
基于uni-app的iOS应用上架,从打包到分发的全流程
android·ios·小程序·https·uni-app·iphone·webview
深盾科技6 小时前
Android Keystore签名文件详解与安全防护
android·安全·gitee