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 站 。

相关推荐
雨白1 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk1 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
TT_Close1 小时前
【Flutter×鸿蒙】一个"插队"技巧,解决90%的 command not found
flutter·harmonyos
LING2 小时前
RN容器启动优化实践
android·react native
恋猫de小郭4 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker9 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴9 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭20 小时前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab21 小时前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
明君879971 天前
Flutter 如何给图片添加多行文字水印
前端·flutter