Flutter 插件 Federated plugins

2020-05-15 12:19:39
Federated plugins

Federated plugins

插件 2.0 还提出了 federated plugins 的概念。
官网的大致意思是:
在这之前,一个插件中包含了 Dart 代码,Android 平台代码 和 iOS 平台代码,他们都在一个包中。
federated plugins 的目的是把他们分离成独立的包。

需要3种类型的包:

  • platform interface package
    各平台需要提供的功能,都以接口的形式声明在了这个包中。
  • platform package(s)
    特定平台实现接口的包。可以有多个,比如一个用于 Web ,一个用于 Mac OS 。
  • app-facing package
    是给使用插件的人用的。插件为 app 提供的各种功能在这个包中,插件使用者调用这个包中的方法。
    接口为这个包提供一个平台的实现,这个包调用实现中的方法。

使用一个插件,直接用到的就是 app-facing package 。

官网给出了一个 Medium 上的文章 How To Write a Flutter Web Plugin, Part 2。
但是不太容易看懂,可以先看另一篇。Modern Flutter Plugin Development 。

文章中反复强调实现接口的时候要用 extends ,不要用 implements 。

虽然官方提出了这个东西,但是官方插件中的安卓和 iOS 代码还是写在老地方。
因为 federated plugins 的出现,主要是方便为安卓和 iOS 之外的平台添加支持,
比如 Web 和 Mac OS 。
不过挺多插件已经把接口分离出来了。

我的演示

如果把插件示例改成 federated plugins 的话。
可以先简单点。直接在同一个位置放3个文件就好了。

/// 文件 platform_interface.dart
/// 相当于 platform interface package

import 'platform_channel.dart';

abstract class DemoInterface {

  static DemoInterface instance = DemoChannel();

  Future get platformVersion {
    throw UnimplementedError('platformVersion has not been implemented.');
  }
}
/// 文件 platform_channel.dart
/// 相当于 platform package

import 'package:flutter/services.dart';

import 'platform_interface.dart';

const MethodChannel _channel = const MethodChannel('platform_channel');

class DemoChannel extends DemoInterface {

  static void register() {
    DemoInterface.instance = DemoChannel();
  }

  @override
  Future get platformVersion async {
    final String version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }
}
/// 文件 federated_plugin_demo.dart
/// 相当于 app-facing package

import 'dart:async';

import 'platform_interface.dart';

class DemoPlugin {

  static Future get platformVersion async {
    final String version = await DemoInterface.instance.platformVersion;
    return version;
  }
}
/// 在 Flutter app 中的使用
import 'dart:async';

import 'federated_plugin_demo.dart';

Future foo() async {
  String platformVersion = await DemoPlugin.platformVersion;
}

platform package 实现了接口。
app-facing package 通过接口类的静态成员 instance 得到接口类的实现,
然后就可以调用接口中的方法。

接口中的静态成员 instance 。

当前 app 运行在哪个平台,就会把它设置成哪个平台的实现。
例如通过 DemoChannel 中的 register() 方法进行设置。
这样 “app-facing package” 就可以调用那个特定平台中的实现了。

上面的例子把 instance 初始化了一个需要 MethodChannel 才能与特定平台通信的实例。
这个初始化其实算是设置了一个默认值。

复杂点的例子

码云地址

这个例子也就是把上面的例子放在不同的包中。

我这个例子和官方做法不太一样,
是3个独立的包,放在了另一个包中。
最外层的包,是 “app-facing package” ,
里面放了

  • platform interface package 是接口
  • platform channel 作为 “platform package”,这个包中有Android 和 iOS 平台代码。
  • platform register 用来设置接口中的 instance 。

官方的做法是把 “app-facing package” 和 Android,iOS原生平台代码放一起了。
我觉得 channel 算是 “platform package”,
官方把它和 “platform interface package” 放一起了。

官方的做法感觉逻辑比较混乱,我就尝试分开下,加深理解。
要注意 pubspec 文件的使用。
另外我写了一个 “platform register”,
感觉这个应该可以由编译器实现,为哪个平台编译,就把 instance 设置成对应平台的实现。

虽然感觉官方的做法不太符合逻辑,
但是实际写插件的话,还是按照官方的写法比较简单。

相关文章

  1. 【Flutter】从启动到插件开始执行

参考资料

  • federated plugins
  • Modern Flutter Plugin Development
  • How To Write a Flutter Web Plugin, Part 2

你可能感兴趣的:(Flutter 插件 Federated plugins)