flutter-plugin-generator
Goal
Scaffolds and configures Flutter plugin packages, handling standard method channels, FFI integrations, and federated plugin architectures. It configures platform-specific native code environments, implements Android v2 embedding lifecycle interfaces, and establishes platform interface packages.
Decision Logic
Use the following decision tree to determine the plugin architecture and template:
- Does the plugin require C/C++ native code via
dart:ffi?
- Yes: Use
--template=plugin_ffi.
- Note: FFI plugins support bundling native code and method channel registration, but not method channels themselves.
- No: Proceed to step 2.
- Does the plugin require BOTH
dart:ffi and Method Channels?
- Yes: Use
--template=plugin (Non-FFI). You must configure FFI manually within the standard plugin structure.
- No: Proceed to step 3.
- Will the plugin be developed by multiple teams or require highly decoupled platform implementations?
- Yes: Implement a Package-Separated Federated Plugin (App-facing package, Platform Interface package, Platform Implementation packages).
- No: Implement a standard monolithic plugin.
Instructions
Gather Plugin Requirements
STOP AND ASK THE USER:
- What is the plugin name?
- What is the organization name (reverse domain notation, e.g.,
com.example)?
- Which platforms should be supported (comma-separated:
android,ios,web,linux,macos,windows)?
- Do you need an FFI plugin or a standard Method Channel plugin?
- Do you prefer Java or Kotlin for Android? Objective-C or Swift for iOS?
- Should this be a federated plugin?
Generate the Plugin Package
Execute the Flutter CLI command based on the user's parameters.
Standard Plugin Example:
flutter create --org com.example --template=plugin --platforms=android,ios,macos -a kotlin -i swift my_plugin
FFI Plugin Example:
flutter create --template=plugin_ffi my_ffi_plugin
Configure Federated Plugin Architecture (If Applicable)
If the user requested a federated plugin, configure the pubspec.yaml of the app-facing package to endorse the platform implementations.
# App-facing pubspec.yaml
flutter:
plugin:
platforms:
android:
default_package: my_plugin_android
windows:
default_package: my_plugin_windows
dependencies:
my_plugin_android: ^1.0.0
my_plugin_windows: ^1.0.0
For the platform implementation packages, define the implements key:
# Platform implementation pubspec.yaml (e.g., my_plugin_windows)
flutter:
plugin:
implements: my_plugin
platforms:
windows:
pluginClass: MyPlugin
Prepare Native Environments for Editing
Before modifying native code, you MUST build the example app to resolve dependencies and generate necessary files.
cd my_plugin/example
flutter build apk --config-only # For Android
flutter build ios --no-codesign --config-only # For iOS
flutter build windows # For Windows
Implement Android v2 Embedding Lifecycle
Modify the Android plugin class (e.g., android/src/main/kotlin/com/example/my_plugin/MyPlugin.kt). Extract logic from registerWith() into a private method shared with onAttachedToEngine(). Implement ActivityAware or ServiceAware if context is needed.
package com.example.my_plugin
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
class MyPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
private lateinit var channel : MethodChannel
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
setupChannel(flutterPluginBinding.binaryMessenger)
}
// Shared private method for v1 and v2 embedding compatibility
private fun setupChannel(messenger: BinaryMessenger) {
channel = MethodChannel(messenger, "my_plugin")
channel.setMethodCallHandler(this)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else {
result.notImplemented()
}
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
// Handle Activity attachment
}
override fun onDetachedFromActivityForConfigChanges() {}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {}
override fun onDetachedFromActivity() {}
}
Validate and Fix
Run the plugin tests and analyzer to ensure the generated code is valid.
cd my_plugin
flutter analyze
flutter test
If the analyzer reports missing dependencies or unresolved native symbols, verify that step 4 (building the example app) was executed successfully. Fix any missing imports in the native code blocks.
Constraints
- Never attempt to use Method Channels inside a package created with
--template=plugin_ffi. If both are required, use --template=plugin.
- Always build the example project (
flutter build <platform>) at least once before attempting to edit or analyze native Android (build.gradle), iOS (.xcworkspace), or Windows (.sln) files.
- Never leave public members undocumented in the Dart API (
lib/<package_name>.dart).
- Always use the v2 Android embedding (
FlutterPlugin). Do not rely solely on the deprecated PluginRegistry.Registrar.
- Never edit the
.android or .ios directories inside a Flutter module; only edit the native code inside the plugin's android/ or ios/ directories.
1---2name: flutter-plugins3description: Build a Flutter plugin that provides native interop for other Flutter apps to use4---5# flutter-plugin-generator67## Goal8Scaffolds and configures Flutter plugin packages, handling standard method channels, FFI integrations, and federated plugin architectures. It configures platform-specific native code environments, implements Android v2 embedding lifecycle interfaces, and establishes platform interface packages.910## Decision Logic1112Use the following decision tree to determine the plugin architecture and template:13141. **Does the plugin require C/C++ native code via `dart:ffi`?**15 * **Yes:** Use `--template=plugin_ffi`.16 * *Note:* FFI plugins support bundling native code and method channel registration, but *not* method channels themselves.17 * **No:** Proceed to step 2.182. **Does the plugin require BOTH `dart:ffi` and Method Channels?**19 * **Yes:** Use `--template=plugin` (Non-FFI). You must configure FFI manually within the standard plugin structure.20 * **No:** Proceed to step 3.213. **Will the plugin be developed by multiple teams or require highly decoupled platform implementations?**22 * **Yes:** Implement a **Package-Separated Federated Plugin** (App-facing package, Platform Interface package, Platform Implementation packages).23 * **No:** Implement a standard monolithic plugin.2425## Instructions26271. **Gather Plugin Requirements**28 **STOP AND ASK THE USER:**29 * What is the plugin name?30 * What is the organization name (reverse domain notation, e.g., `com.example`)?31 * Which platforms should be supported (comma-separated: `android,ios,web,linux,macos,windows`)?32 * Do you need an FFI plugin or a standard Method Channel plugin?33 * Do you prefer Java or Kotlin for Android? Objective-C or Swift for iOS?34 * Should this be a federated plugin?35362. **Generate the Plugin Package**37 Execute the Flutter CLI command based on the user's parameters. 38 39 *Standard Plugin Example:*40 ```bash41 flutter create --org com.example --template=plugin --platforms=android,ios,macos -a kotlin -i swift my_plugin42 ```43 44 *FFI Plugin Example:*45 ```bash46 flutter create --template=plugin_ffi my_ffi_plugin47 ```48493. **Configure Federated Plugin Architecture (If Applicable)**50 If the user requested a federated plugin, configure the `pubspec.yaml` of the app-facing package to endorse the platform implementations.5152 ```yaml53 # App-facing pubspec.yaml54 flutter:55 plugin:56 platforms:57 android:58 default_package: my_plugin_android59 windows:60 default_package: my_plugin_windows6162 dependencies:63 my_plugin_android: ^1.0.064 my_plugin_windows: ^1.0.065 ```6667 For the platform implementation packages, define the `implements` key:68 ```yaml69 # Platform implementation pubspec.yaml (e.g., my_plugin_windows)70 flutter:71 plugin:72 implements: my_plugin73 platforms:74 windows:75 pluginClass: MyPlugin76 ```77784. **Prepare Native Environments for Editing**79 Before modifying native code, you MUST build the example app to resolve dependencies and generate necessary files.80 ```bash81 cd my_plugin/example82 flutter build apk --config-only # For Android83 flutter build ios --no-codesign --config-only # For iOS84 flutter build windows # For Windows85 ```86875. **Implement Android v2 Embedding Lifecycle**88 Modify the Android plugin class (e.g., `android/src/main/kotlin/com/example/my_plugin/MyPlugin.kt`). Extract logic from `registerWith()` into a private method shared with `onAttachedToEngine()`. Implement `ActivityAware` or `ServiceAware` if context is needed.8990 ```kotlin91 package com.example.my_plugin9293 import androidx.annotation.NonNull94 import io.flutter.embedding.engine.plugins.FlutterPlugin95 import io.flutter.embedding.engine.plugins.activity.ActivityAware96 import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding97 import io.flutter.plugin.common.MethodCall98 import io.flutter.plugin.common.MethodChannel99 import io.flutter.plugin.common.MethodChannel.MethodCallHandler100 import io.flutter.plugin.common.MethodChannel.Result101102 class MyPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {103 private lateinit var channel : MethodChannel104105 override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {106 setupChannel(flutterPluginBinding.binaryMessenger)107 }108109 // Shared private method for v1 and v2 embedding compatibility110 private fun setupChannel(messenger: BinaryMessenger) {111 channel = MethodChannel(messenger, "my_plugin")112 channel.setMethodCallHandler(this)113 }114115 override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {116 if (call.method == "getPlatformVersion") {117 result.success("Android ${android.os.Build.VERSION.RELEASE}")118 } else {119 result.notImplemented()120 }121 }122123 override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {124 channel.setMethodCallHandler(null)125 }126127 override fun onAttachedToActivity(binding: ActivityPluginBinding) {128 // Handle Activity attachment129 }130131 override fun onDetachedFromActivityForConfigChanges() {}132 override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {}133 override fun onDetachedFromActivity() {}134 }135 ```1361376. **Validate and Fix**138 Run the plugin tests and analyzer to ensure the generated code is valid.139 ```bash140 cd my_plugin141 flutter analyze142 flutter test143 ```144 *If the analyzer reports missing dependencies or unresolved native symbols, verify that step 4 (building the example app) was executed successfully. Fix any missing imports in the native code blocks.*145146## Constraints147148* **Never** attempt to use Method Channels inside a package created with `--template=plugin_ffi`. If both are required, use `--template=plugin`.149* **Always** build the example project (`flutter build <platform>`) at least once before attempting to edit or analyze native Android (`build.gradle`), iOS (`.xcworkspace`), or Windows (`.sln`) files.150* **Never** leave public members undocumented in the Dart API (`lib/<package_name>.dart`).151* **Always** use the v2 Android embedding (`FlutterPlugin`). Do not rely solely on the deprecated `PluginRegistry.Registrar`.152* **Never** edit the `.android` or `.ios` directories inside a Flutter module; only edit the native code inside the plugin's `android/` or `ios/` directories.