flutter-building-plugins

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Developing Flutter Plugins

开发Flutter插件

Contents

目录

Architecture & Design Patterns

架构与设计模式

Federated Plugins

联邦式插件

Implement federated plugins to split a plugin's API across multiple packages, allowing independent teams to build platform-specific implementations. Structure federated plugins into three distinct components:
  1. App-facing interface: The primary package users depend on. It exports the public API.
  2. Platform interface: The package defining the common interface that all platform implementations must implement.
  3. Platform implementations: Independent packages containing platform-specific code (e.g.,
    my_plugin_android
    ,
    my_plugin_windows
    ).
实现联邦式插件可将插件的API拆分到多个包中,允许独立团队构建平台专属的实现。将联邦式插件分为三个不同组件:
  1. 面向应用的接口:用户依赖的主包,导出公开API。
  2. 平台接口:定义所有平台实现必须遵循的通用接口的包。
  3. 平台实现:包含平台专属代码的独立包(例如
    my_plugin_android
    my_plugin_windows
    )。

FFI vs. Standard Plugins

FFI插件与标准插件对比

Choose the correct plugin template based on your native interoperability requirements:
  • Standard Plugins (
    --template=plugin
    ):
    Use for accessing platform-specific APIs (e.g., Android SDK, iOS frameworks) via Method Channels.
  • FFI Plugins (
    --template=plugin_ffi
    ):
    Use for accessing C/C++ native libraries, configuring Google Play services on Android, or using static linking on iOS/macOS.
    • Constraint: FFI plugin packages support bundling native code and method channel registration code, but not method channels themselves. If you require both method channels and FFI, use the standard non-FFI plugin template.
根据你的原生互操作需求选择正确的插件模板:
  • 标准插件(
    --template=plugin
    ):
    用于通过Method Channels访问平台专属API(如Android SDK、iOS框架)。
  • FFI插件(
    --template=plugin_ffi
    ):
    用于访问C/C++原生库、在Android上配置Google Play服务,或在iOS/macOS上使用静态链接。
    • 限制条件: FFI插件包支持捆绑原生代码和Method Channel注册代码,但不支持Method Channel本身。如果同时需要Method Channels和FFI,请使用标准非FFI插件模板。

Workflow: Creating a New Plugin

工作流:创建新插件

Follow this workflow to initialize a new plugin package.
Task Progress:
  • Determine if the plugin requires FFI or standard Method Channels.
  • Execute the appropriate
    flutter create
    command.
  • Verify the generated directory structure.
Conditional Initialization:
  • If creating a STANDARD plugin: Run the following command, specifying your supported platforms, organization, and preferred languages (defaults are Swift and Kotlin):
    bash
    flutter create --template=plugin \
      --platforms=android,ios,web,linux,macos,windows \
      --org com.example.organization \
      -i objc -a java \
      my_plugin
  • If creating an FFI plugin: Run the following command to generate a project with Dart code in
    lib
    (using
    dart:ffi
    ) and native source code in
    src
    (with a
    CMakeLists.txt
    ):
    bash
    flutter create --template=plugin_ffi my_ffi_plugin
按照以下工作流初始化新的插件包。
任务进度:
  • 确定插件是否需要FFI或标准Method Channels。
  • 执行对应的
    flutter create
    命令。
  • 验证生成的目录结构。
条件初始化:
  • 如果创建标准插件: 运行以下命令,指定支持的平台、组织和首选语言(默认是Swift和Kotlin):
    bash
    flutter create --template=plugin \
      --platforms=android,ios,web,linux,macos,windows \
      --org com.example.organization \
      -i objc -a java \
      my_plugin
  • 如果创建FFI插件: 运行以下命令生成项目,
    lib
    目录下是使用
    dart:ffi
    的Dart代码,
    src
    目录下是原生源代码(包含
    CMakeLists.txt
    ):
    bash
    flutter create --template=plugin_ffi my_ffi_plugin

Workflow: Implementing Android Platform Code

工作流:实现Android平台代码

Always edit Android platform code using Android Studio to ensure proper code completion and Gradle synchronization.
Task Progress:
  • Run initial build to generate necessary Gradle files.
  • Open the Android module in Android Studio.
  • Implement
    FlutterPlugin
    and lifecycle-aware interfaces.
  • Refactor legacy
    registerWith
    logic.
  • Run validator -> review errors -> fix.
  1. Generate Build Files: Build the code at least once before editing to resolve dependencies.
    bash
    cd example
    flutter build apk --config-only
  2. Open in IDE: Launch Android Studio and open the
    example/android/build.gradle
    or
    example/android/build.gradle.kts
    file.
  3. Locate Source: Navigate to your plugin's source code at
    java/<organization-path>/<PluginName>
    .
  4. Implement V2 Embedding:
    • Implement the
      FlutterPlugin
      interface.
    • Ensure your plugin class has a public constructor.
    • Extract shared initialization logic from the legacy
      registerWith()
      method and the new
      onAttachedToEngine()
      method into a single private method. Both entry points must call this private method to maintain backward compatibility without duplicating logic.
  5. Implement Lifecycle Interfaces:
    • If your plugin requires an
      Activity
      reference:
      Implement the
      ActivityAware
      interface and handle the
      onAttachedToActivity
      ,
      onDetachedFromActivityForConfigChanges
      ,
      onReattachedToActivityForConfigChanges
      , and
      onDetachedFromActivity
      callbacks.
    • If your plugin runs in a background
      Service
      :
      Implement the
      ServiceAware
      interface.
  6. Update Example App: Ensure the example app's
    MainActivity.java
    extends the v2 embedding
    io.flutter.embedding.android.FlutterActivity
    .
  7. Document API: Document all non-overridden public members in your Android implementation.
请始终使用Android Studio编辑Android平台代码,以确保获得正确的代码补全和Gradle同步支持。
任务进度:
  • 运行初始构建以生成必要的Gradle文件。
  • 在Android Studio中打开Android模块。
  • 实现
    FlutterPlugin
    和生命周期感知接口。
  • 重构旧版
    registerWith
    逻辑。
  • 运行验证工具 -> 查看错误 -> 修复问题。
  1. 生成构建文件: 在编辑前至少构建一次代码以解析依赖。
    bash
    cd example
    flutter build apk --config-only
  2. 在IDE中打开: 启动Android Studio并打开
    example/android/build.gradle
    example/android/build.gradle.kts
    文件。
  3. 定位源代码:
    java/<组织路径>/<插件名称>
    下找到插件的源代码。
  4. 实现V2嵌入:
    • 实现
      FlutterPlugin
      接口。
    • 确保插件类拥有公共构造函数。
    • 将旧版
      registerWith()
      方法和新版
      onAttachedToEngine()
      方法中的共享初始化逻辑提取到一个私有方法中。两个入口点都必须调用此私有方法,以在不重复代码的前提下保持向后兼容性。
  5. 实现生命周期接口:
    • 如果插件需要
      Activity
      引用:
      实现
      ActivityAware
      接口并处理
      onAttachedToActivity
      onDetachedFromActivityForConfigChanges
      onReattachedToActivityForConfigChanges
      onDetachedFromActivity
      回调。
    • 如果插件在后台
      Service
      中运行:
      实现
      ServiceAware
      接口。
  6. 更新示例应用: 确保示例应用的
    MainActivity.java
    继承自V2嵌入的
    io.flutter.embedding.android.FlutterActivity
  7. 文档化API: 为Android实现中所有非重写的公共成员添加文档注释。

Workflow: Implementing Windows Platform Code

工作流:实现Windows平台代码

Always edit Windows platform code using Visual Studio.
Task Progress:
  • Run initial build to generate the Visual Studio solution.
  • Open the solution in Visual Studio.
  • Implement C++ logic.
  • Rebuild the solution.
  1. Generate Build Files:
    bash
    cd example
    flutter build windows
  2. Open in IDE: Launch Visual Studio and open the
    example/build/windows/hello_example.sln
    file.
  3. Locate Source: Navigate to
    hello_plugin/Source Files
    and
    hello_plugin/Header Files
    in the Solution Explorer.
  4. Rebuild: After making changes to the C++ plugin code, you must rebuild the solution in Visual Studio before running the app, or the outdated plugin binary will be used.
请始终使用Visual Studio编辑Windows平台代码。
任务进度:
  • 运行初始构建以生成Visual Studio解决方案。
  • 在Visual Studio中打开解决方案。
  • 实现C++逻辑。
  • 重新构建解决方案。
  1. 生成构建文件:
    bash
    cd example
    flutter build windows
  2. 在IDE中打开: 启动Visual Studio并打开
    example/build/windows/hello_example.sln
    文件。
  3. 定位源代码: 在解决方案资源管理器中找到
    hello_plugin/Source Files
    hello_plugin/Header Files
  4. 重新构建: 修改C++插件代码后,必须在Visual Studio中重新构建解决方案,然后再运行应用,否则会使用过时的插件二进制文件。

Workflow: Adding Platforms to an Existing Plugin

工作流:为现有插件添加平台支持

Use this workflow to retrofit an existing plugin with support for additional platforms.
Task Progress:
  • Run the platform addition command.
  • Update iOS/macOS podspecs (if applicable).
  • Implement the platform-specific code.
  1. Run Create Command: Navigate to the root directory of your existing plugin and run:
    bash
    flutter create --template=plugin --platforms=web,macos .
  2. Update Podspecs: If adding iOS or macOS support, open the generated
    .podspec
    file and configure the required dependencies and deployment targets.
使用此工作流为现有插件添加对更多平台的支持。
任务进度:
  • 运行添加平台的命令。
  • 更新iOS/macOS的podspec文件(如适用)。
  • 实现平台专属代码。
  1. 运行创建命令: 导航到现有插件的根目录并运行:
    bash
    flutter create --template=plugin --platforms=web,macos .
  2. 更新Podspec文件: 如果添加iOS或macOS支持,请打开生成的
    .podspec
    文件并配置所需的依赖项和部署目标。

Examples

示例

Android V2 Embedding Implementation

Android V2嵌入实现

High-fidelity example of an Android plugin implementing
FlutterPlugin
and
ActivityAware
while maintaining legacy compatibility.
java
package com.example.myplugin;

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;
import io.flutter.plugin.common.PluginRegistry.Registrar;

/** MyPlugin */
public class MyPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
  private MethodChannel channel;

  // Public constructor required for v2 embedding
  public MyPlugin() {}

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    setupChannel(flutterPluginBinding.getBinaryMessenger());
  }

  // Legacy v1 embedding support
  public static void registerWith(Registrar registrar) {
    MyPlugin plugin = new MyPlugin();
    plugin.setupChannel(registrar.messenger());
  }

  // Shared initialization logic
  private void setupChannel(BinaryMessenger messenger) {
    channel = new MethodChannel(messenger, "my_plugin");
    channel.setMethodCallHandler(this);
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    if (call.method.equals("getPlatformVersion")) {
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    } else {
      result.notImplemented();
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }

  @Override
  public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
    // Handle Activity attachment
  }

  @Override
  public void onDetachedFromActivityForConfigChanges() {
    // Handle config changes
  }

  @Override
  public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
    // Handle reattachment
  }

  @Override
  public void onDetachedFromActivity() {
    // Clean up Activity references
  }
}
这是一个高保真示例,展示了Android插件如何实现
FlutterPlugin
ActivityAware
接口,同时保持旧版兼容性。
java
package com.example.myplugin;

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;
import io.flutter.plugin.common.PluginRegistry.Registrar;

/** MyPlugin */
public class MyPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
  private MethodChannel channel;

  // V2嵌入要求的公共构造函数
  public MyPlugin() {}

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    setupChannel(flutterPluginBinding.getBinaryMessenger());
  }

  // 支持旧版V1嵌入
  public static void registerWith(Registrar registrar) {
    MyPlugin plugin = new MyPlugin();
    plugin.setupChannel(registrar.messenger());
  }

  // 共享初始化逻辑
  private void setupChannel(BinaryMessenger messenger) {
    channel = new MethodChannel(messenger, "my_plugin");
    channel.setMethodCallHandler(this);
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    if (call.method.equals("getPlatformVersion")) {
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    } else {
      result.notImplemented();
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }

  @Override
  public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
    // 处理Activity绑定
  }

  @Override
  public void onDetachedFromActivityForConfigChanges() {
    // 处理配置变更时的解绑
  }

  @Override
  public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
    // 处理配置变更后的重新绑定
  }

  @Override
  public void onDetachedFromActivity() {
    // 清理Activity引用
  }
}