Flutter 插件 Federated plugins

本文介绍了Flutter的联邦化插件(Federated plugins)概念,旨在将不同平台的代码分离。Federated plugins包含平台接口包、平台实现包和面向应用的包。文中提供了一个简单的演示,通过接口中的静态成员`instance`来获取平台实现,并讨论了官方与个人实践的不同做法。此外,还推荐了相关阅读资料以深入理解。

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<String> 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<String> 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<String> get platformVersion async {
    final String version = await DemoInterface.instance.platformVersion;
    return version;
  }
}
/// 在 Flutter app 中的使用
import 'dart:async';

import 'federated_plugin_demo.dart';

Future<void> 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】从启动到插件开始执行

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值