2、创建第一个Flutter插件项目

好,咱们直接动手。这一章我会带你从零创建一个Flutter插件项目,然后把它跑起来。你想想看,一个插件项目到底长什么样?里面那些android、ios、lib目录都是干嘛的?咱们今天一次性说清楚。

2.1 使用flutter create创建插件项目

创建Flutter插件,官方推荐用这条命令:

flutter create --template=plugin --org com.example my_first_plugin

这里解释一下参数:

  • --template=plugin:告诉Flutter你要创建的是插件项目,不是普通应用
  • --org com.example:指定包名,我习惯用公司域名倒写,比如com.mycompany
  • my_first_plugin:项目名称,建议全小写加下划线

执行完之后,你会看到终端输出一堆信息。嗯,这里要注意——如果你用的是Flutter 3.x以上版本,它还会问你要不要支持某些平台。我个人建议先全选,后面再删减都来得及。

💡 小技巧: 如果你只想创建Android和iOS的插件,可以加参数 --platforms=android,ios。我在早期项目里经常这么干,省得生成一堆用不上的目录。

2.2 项目结构解析

创建完成后,用VS Code或Android Studio打开项目。你会看到这样的目录结构:

my_first_plugin/
├── android/          # Android原生代码
├── ios/              # iOS原生代码
├── lib/              # Dart代码(插件API定义)
├── example/          # 示例应用
├── test/             # 单元测试
├── pubspec.yaml      # 插件配置文件
└── CHANGELOG.md      # 版本更新日志

咱们一个一个说。

2.2.1 android/ 目录

这里面放的是Android原生代码。说白了,就是Java或Kotlin写的代码。Flutter通过MethodChannel跟它通信。我刚开始做插件时,经常在Android Studio里单独打开这个目录来调试,因为Android原生代码的断点只能在AS里生效。

关键文件:

  • android/src/main/java/.../MyFirstPlugin.java:插件的主入口类
  • android/build.gradle:Android构建配置,可以在这里加依赖库
  • android/src/main/AndroidManifest.xml:权限声明

2.2.2 ios/ 目录

iOS原生代码放在这里。用Swift或Objective-C写。我记得第一次写iOS插件时,被Xcode的配置折腾了半天——桥接头文件、Podfile、Swift版本……嗯,这些坑后面会专门讲。

关键文件:

  • ios/Classes/MyFirstPlugin.swift:插件的主入口类
  • ios/my_first_plugin.podspec:CocoaPods配置文件

2.2.3 lib/ 目录

这是Dart代码的根据地。插件对外暴露的API都写在这里。比如:

// lib/my_first_plugin.dart
import 'dart:async';
import 'package:flutter/services.dart';

class MyFirstPlugin {
  static const MethodChannel _channel = MethodChannel('my_first_plugin');

  static Future<String?> getPlatformVersion() async {
    final version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }
}

你看,这里定义了一个MethodChannel,名字叫my_first_plugin。这个字符串必须跟Android和iOS端注册的channel名字一致,否则通信会失败。我曾经因为拼写错误,排查了整整一个下午……

2.2.4 example/ 目录

这是一个完整的Flutter应用,专门用来测试你的插件。它有自己的pubspec.yaml,并且通过path依赖引用父目录的插件:

dependencies:
  my_first_plugin:
    path: ../

这样做的好处是:你改完插件代码,不用发布到pub.dev,直接在example里就能看到效果。我平时开发插件,90%的时间都在example里调试。

2.3 运行示例应用

好,现在咱们把示例应用跑起来。打开终端,进入example目录:

cd my_first_plugin/example
flutter run

如果你连接了真机或模拟器,Flutter会自动安装并启动应用。你会看到一个简单的界面,显示当前设备的平台版本——比如"Android 13"或"iOS 16.4"。

🎯 核心逻辑: 示例应用调用了插件提供的getPlatformVersion()方法。这个方法通过MethodChannel发送消息到原生端,原生端获取系统版本后返回给Dart层。整个过程就是一次标准的Flutter与原生交互。

2.4 知识体系结构图

下面这张图帮你理清整个插件项目的核心逻辑:

Flutter插件项目核心结构 Flutter层 (lib/) Dart代码 · 定义MethodChannel · 暴露API给开发者 MethodChannel 原生层 (android/ + ios/) Java/Kotlin · Swift/ObjC · 调用系统API 系统API调用 操作系统 (Android / iOS) 提供硬件能力 · 系统版本 · 传感器 · 文件系统 📱 example/ 测试应用

这张图展示了插件工作的三层结构:Flutter层通过MethodChannel调用原生层,原生层再调用系统API。example应用则位于最上层,用来验证整个链路是否通畅。

2.5 避坑指南

⚠️ 我曾经踩过的坑:
  • Channel名字不一致:Dart端和原生端的channel名字必须完全一样,大小写敏感。我建议把channel名字定义成常量,两边共用。
  • Android包名冲突:如果你同时开发多个插件,注意--org参数要不同,否则Android编译时会报Duplicate class错误。
  • iOS模拟器问题:有些iOS功能(比如相机、蓝牙)在模拟器上不支持,跑不起来别慌,换真机试试。

2.6 小结

这一章我们完成了三件事:创建了第一个Flutter插件项目、搞清楚了每个目录的作用、成功运行了示例应用。说白了,你现在已经知道插件项目长什么样了。下一章我们会深入MethodChannel的通信细节,看看Dart和原生代码到底是怎么「打电话」的。

📌 课后练习: 试着修改example应用里的UI,把平台版本显示成红色大字。然后改一下插件代码,让它返回设备型号而不是系统版本。动手试试,你会发现插件开发其实没那么神秘。

公众号:蓝海资料掘金营,微信deep3321