Flutter平台接口抽象插件plugin_platform_interface的使用

发布于 1周前 作者 bupafengyu 来自 Flutter

Flutter平台接口抽象插件plugin_platform_interface的使用

插件概述

plugin_platform_interface 包为联合Flutter插件提供了一个基础类。该包确保了平台接口被继承而不是实现,以保证新增的方法不会被视为破坏性变更。通过扩展平台接口,子类可以从基类中获取默认实现;而如果使用实现(implements),则在接口新增方法时会导致现有实现失效。

此包提供的功能强制平台接口必须被继承而不是实现,以此来提供公共的功能和约束。

示例用法

以下代码展示了如何定义一个平台接口,并为其提供默认实现:

import 'package:plugin_platform_interface/plugin_platform_interface.dart';

abstract class SamplePluginPlatform extends PlatformInterface {
  /// 构造函数,需要传入token用于验证
  SamplePluginPlatform() : super(token: _token);

  static final Object _token = Object();

  // 定义静态成员变量_instance,持有当前的实例,默认是SamplePluginDefault。
  static SamplePluginPlatform _instance = SamplePluginDefault();

  // 提供getter和setter访问_instance
  static SamplePluginPlatform get instance => _instance;

  /// 平台特定的实现应该将此属性设置为它们自己的平台特定类,
  /// 该类应扩展 [SamplePluginPlatform] 并在注册自己时调用。
  static set instance(SamplePluginPlatform instance) {
    // 验证新的实例是否正确地扩展了平台接口
    PlatformInterface.verify(instance, _token);
    _instance = instance;
  }

  // 插件平台接口的方法会在此处定义,通常这些方法会抛出 UnimplementedError 异常
}

// 默认的具体实现
class SamplePluginDefault extends SamplePluginPlatform {
  // 实现平台接口中的方法
}

上述代码保证了 SamplePluginPlatform.instance 不能被设置为实现了 SamplePluginPlatform 的对象(只能设置为扩展了它的对象)。

模拟或伪造平台接口

测试平台接口的实现(如使用 mockitoMocktestFake)会在 verify 验证时失败。本包提供了 MockPlatformInterfaceMixin,它可以在测试代码中使用,以禁用 extends 约束。

例如,可以创建一个模拟的平台接口如下:

import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:mockito/mockito.dart';

class SamplePluginPlatformMock extends Mock with MockPlatformInterfaceMixin implements SamplePluginPlatform {}

关于base关键字的一点说明

在Dart 3中引入了base关键字,它在编译时强制要求子类使用extends而非implements。Flutter团队正在考虑弃用这个包转而使用base关键字来定义平台接口,但目前还没有做出决定,因为这将移除上文提到的模拟/伪造的能力。

插件作者在创建新插件时可能希望考虑使用base关键字代替这个包。

参考链接:GitHub Issue #127396

完整示例Demo

下面是一个完整的示例,演示了如何创建一个简单的插件,并使用plugin_platform_interface定义其平台接口:

main.dart

import 'package:flutter/material.dart';
import 'package:sample_plugin/sample_plugin.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Plugin Example')),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              String result = await SamplePlugin().doSomething();
              print(result); // 输出结果
            },
            child: Text('Do Something'),
          ),
        ),
      ),
    );
  }
}

sample_plugin.dart

import 'package:flutter/services.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';

abstract class SamplePluginPlatform extends PlatformInterface {
  SamplePluginPlatform() : super(token: _token);

  static final Object _token = Object();

  static SamplePluginPlatform _instance = SamplePluginDefault();

  static SamplePluginPlatform get instance => _instance;

  static set instance(SamplePluginPlatform instance) {
    PlatformInterface.verify(instance, _token);
    _instance = instance;
  }

  Future<String> doSomething();
}

class SamplePluginDefault extends SamplePluginPlatform {
  @override
  Future<String> doSomething() async {
    return "Default Implementation";
  }
}

class SamplePlugin {
  Future<String> doSomething() async {
    return await SamplePluginPlatform.instance.doSomething();
  }
}

以上就是关于plugin_platform_interface的基本介绍和使用方法,希望对您有所帮助!


更多关于Flutter平台接口抽象插件plugin_platform_interface的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter平台接口抽象插件plugin_platform_interface的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter开发中,plugin_platform_interface 包是一个关键组件,它提供了一套通用的接口和抽象类,用于在跨平台插件中实现平台特定的逻辑。通过使用这些接口和抽象类,插件开发者可以确保他们的插件在不同平台上具有一致的API,同时允许平台特定的实现。

下面是一个简单的示例,展示了如何在Flutter插件中使用 plugin_platform_interface 来创建一个跨平台的接口,并在iOS和Android平台上实现它。

1. 创建插件接口

首先,在你的Flutter插件项目中,创建一个新的Dart文件来定义你的插件接口。例如,创建一个名为 my_plugin_interface.dart 的文件:

// my_plugin_interface.dart
import 'dart:async';

// 定义插件接口
abstract class MyPluginInterface {
  // 一个示例方法,用于获取平台特定的信息
  Future<String> getPlatformInfo();
}

2. 创建平台实现

接下来,你需要为不同的平台(如iOS和Android)创建实现该接口的具体类。

iOS 实现

在你的iOS平台实现中,创建一个Swift或Objective-C文件来实现这个接口。例如,创建一个名为 MyPlugin.swift 的文件:

// MyPlugin.swift
import Flutter

public class MyPlugin: NSObject, FlutterPlugin, MyPluginInterface {
  public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(name: "com.example.my_plugin", binaryMessenger: registrar.messenger())
    let instance = MyPlugin()
    registrar.addMethodCallDelegate(instance, channel: channel)
    _ = channel.setMethodCallHandler({
      (call: FlutterMethodCall, result: @escaping FlutterResult) in
      
      switch call.method {
      case "getPlatformInfo":
        let platformInfo = instance.getPlatformInfo()
        result(platformInfo)
      default:
        result(FlutterMethodNotImplemented)
      }
    })
  }
  
  public func getPlatformInfo() -> String {
    return "iOS"
  }
}

注意,这里我们使用了 FlutterMethodChannel 来处理来自Dart代码的方法调用,并返回平台特定的信息。

Android 实现

在你的Android平台实现中,创建一个Kotlin或Java文件来实现这个接口。例如,创建一个名为 MyPlugin.kt 的文件:

// MyPlugin.kt
package com.example.my_plugin

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 android.app.Activity

class MyPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
  private lateinit var channel: MethodChannel
  private var activity: Activity? = null

  override fun onAttachedToEngine(binding: FlutterPluginBinding) {
    channel = MethodChannel(binding.binaryMessenger, "com.example.my_plugin")
    channel.setMethodCallHandler(this)
  }

  override fun onMethodCall(call: MethodCall, result: Result) {
    if (call.method == "getPlatformInfo") {
      result.success("Android")
    } else {
      result.notImplemented()
    }
  }

  override fun onDetachedFromEngine(binding: FlutterPluginBinding) {
    channel.setMethodCallHandler(null)
  }

  override fun onAttachedToActivity(binding: ActivityPluginBinding) {
    activity = binding.activity
  }

  override fun onDetachedFromActivityForConfigChanges() {
    activity = null
  }

  override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
    activity = binding.activity
  }

  override fun onDetachedFromActivity() {
    activity = null
  }
}

3. Dart 代码调用

最后,在你的Dart代码中,你可以使用 MethodChannel 来调用这些平台特定的实现。例如,在你的Flutter应用中:

// main.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'my_plugin_interface.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  static const platform = MethodChannel('com.example.my_plugin');
  static late MyPluginInterface _myPlugin;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin Demo'),
        ),
        body: Center(
          child: FutureBuilder<String>(
            future: _getPlatformInfo(),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                if (snapshot.hasError) {
                  return Text('Error: ${snapshot.error}');
                } else {
                  return Text('Platform: ${snapshot.data}');
                }
              } else {
                return CircularProgressIndicator();
              }
            },
          ),
        ),
      ),
    );
  }

  Future<String> _getPlatformInfo() async {
    // 这里你可以实例化你的插件接口,但在这个例子中我们直接使用MethodChannel
    String platformInfo;
    try {
      platformInfo = await platform.invokeMethod('getPlatformInfo');
    } on PlatformException catch (e) {
      platformInfo = "Failed to get platform info: '${e.message}'.";
    }
    return platformInfo;
  }
}

注意,在这个示例中,我们直接在Dart代码中使用了 MethodChannel 来调用平台特定的方法。在更复杂的情况下,你可能需要在Dart中实例化一个实现了 MyPluginInterface 的具体类,该类内部使用 MethodChannel 来与原生代码通信。

这个示例展示了如何在Flutter插件中使用 plugin_platform_interface 来定义和实现跨平台的接口。通过这种方式,你可以确保你的插件在不同平台上具有一致的API,同时允许平台特定的实现。

回到顶部