[plugin_platform_interface] Adopt code-excerpts (#4534)

Updates the README to use code excerpts from the unit test file, adjusting the existing test code slightly to make it suitable for use in the example.

Also fleshes out the example a bit more, to make it look more like a real class.

Finally, adds a note about `base`, linking to the ongoing discussion, since we don't have a decision yet, but people may well wonder why this class exists given `base`.

Part of https://github.com/flutter/flutter/issues/102679
This commit is contained in:
stuartmorgan
2023-07-20 14:14:10 -07:00
committed by GitHub
parent 442d9db347
commit 05fdd1337f
5 changed files with 69 additions and 27 deletions

View File

@ -1,5 +1,6 @@
## NEXT ## 2.1.5
* Updates README to improve example and discuss `base`.
* Updates minimum Flutter version to 3.3. * Updates minimum Flutter version to 3.3.
## 2.1.4 ## 2.1.4

View File

@ -2,8 +2,8 @@
This package provides a base class for platform interfaces of [federated flutter plugins](https://flutter.dev/go/federated-plugins). This package provides a base class for platform interfaces of [federated flutter plugins](https://flutter.dev/go/federated-plugins).
Platform implementations should extend their platform interface classes rather than implement it as Platform implementations should `extends` their platform interface class rather than `implement`s it, as
newly added methods to platform interfaces are not considered as breaking changes. Extending a platform newly added methods to platform interfaces are not considered breaking changes. Extending a platform
interface ensures that subclasses will get the default implementations from the base class, while interface ensures that subclasses will get the default implementations from the base class, while
platform implementations that `implements` their platform interface will be broken by newly added methods. platform implementations that `implements` their platform interface will be broken by newly added methods.
@ -12,24 +12,34 @@ and not implemented.
## Sample usage: ## Sample usage:
<?code-excerpt "test/plugin_platform_interface_test.dart (Example)"?>
```dart ```dart
abstract class UrlLauncherPlatform extends PlatformInterface { abstract class SamplePluginPlatform extends PlatformInterface {
UrlLauncherPlatform() : super(token: _token); SamplePluginPlatform() : super(token: _token);
static UrlLauncherPlatform _instance = MethodChannelUrlLauncher();
static final Object _token = Object(); static final Object _token = Object();
static UrlLauncherPlatform get instance => _instance; // A plugin can have a default implementation, as shown here, or `instance`
// can be nullable, and the default instance can be null.
static SamplePluginPlatform _instance = SamplePluginDefault();
/// Platform-specific plugins should set this with their own platform-specific static SamplePluginPlatform get instance => _instance;
/// class that extends [UrlLauncherPlatform] when they register themselves.
static set instance(UrlLauncherPlatform instance) { /// Platform-specific implementations should set this to their own
/// platform-specific class that extends [SamplePluginPlatform] when they
/// register themselves.
static set instance(SamplePluginPlatform instance) {
PlatformInterface.verify(instance, _token); PlatformInterface.verify(instance, _token);
_instance = instance; _instance = instance;
} }
} // Methods for the plugin's platform interface would go here, often with
// implementations that throw UnimplementedError.
}
class SamplePluginDefault extends SamplePluginPlatform {
// A default real implementation of the platform interface would go here.
}
``` ```
This guarantees that UrlLauncherPlatform.instance cannot be set to an object that `implements` This guarantees that UrlLauncherPlatform.instance cannot be set to an object that `implements`
@ -45,8 +55,24 @@ code only to disable the `extends` enforcement.
For example, a Mockito mock of a platform interface can be created with: For example, a Mockito mock of a platform interface can be created with:
<?code-excerpt "test/plugin_platform_interface_test.dart (Mock)"?>
```dart ```dart
class UrlLauncherPlatformMock extends Mock class SamplePluginPlatformMock extends Mock
with MockPlatformInterfaceMixin with MockPlatformInterfaceMixin
implements UrlLauncherPlatform {} implements SamplePluginPlatform {}
``` ```
## A note about `base`
In Dart 3, [the `base` keyword](https://dart.dev/language/class-modifiers#base)
was introduced to the language, which enforces that subclasses use `extends`
rather than `implements` at compile time. The Flutter team is
[considering deprecating this package in favor of using
`base`](https://github.com/flutter/flutter/issues/127396) for platfom interfaces,
but no decision has been made yet since it removes the ability to do mocking/faking
as shown above.
Plugin authors may want to consider using `base` instead of this package when
creating new plugins.
https://github.com/flutter/flutter/issues/127396

View File

@ -15,7 +15,7 @@ issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+
# be done when absolutely necessary and after the ecosystem has already migrated to 2.X.Y version # be done when absolutely necessary and after the ecosystem has already migrated to 2.X.Y version
# that is forward compatible with 3.0.0 (ideally the ecosystem have migrated to depend on: # that is forward compatible with 3.0.0 (ideally the ecosystem have migrated to depend on:
# `plugin_platform_interface: >=2.X.Y <4.0.0`). # `plugin_platform_interface: >=2.X.Y <4.0.0`).
version: 2.1.4 version: 2.1.5
environment: environment:
sdk: ">=2.18.0 <4.0.0" sdk: ">=2.18.0 <4.0.0"

View File

@ -6,18 +6,35 @@ import 'package:mockito/mockito.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
class SamplePluginPlatform extends PlatformInterface { // #docregion Example
abstract class SamplePluginPlatform extends PlatformInterface {
SamplePluginPlatform() : super(token: _token); SamplePluginPlatform() : super(token: _token);
static final Object _token = Object(); static final Object _token = Object();
// ignore: avoid_setters_without_getters // A plugin can have a default implementation, as shown here, or `instance`
// can be nullable, and the default instance can be null.
static SamplePluginPlatform _instance = SamplePluginDefault();
static SamplePluginPlatform get instance => _instance;
/// Platform-specific implementations should set this to their own
/// platform-specific class that extends [SamplePluginPlatform] when they
/// register themselves.
static set instance(SamplePluginPlatform instance) { static set instance(SamplePluginPlatform instance) {
PlatformInterface.verify(instance, _token); PlatformInterface.verify(instance, _token);
// A real implementation would set a static instance field here. _instance = instance;
} }
// Methods for the plugin's platform interface would go here, often with
// implementations that throw UnimplementedError.
} }
class SamplePluginDefault extends SamplePluginPlatform {
// A default real implementation of the platform interface would go here.
}
// #enddocregion Example
class ImplementsSamplePluginPlatform extends Mock class ImplementsSamplePluginPlatform extends Mock
implements SamplePluginPlatform {} implements SamplePluginPlatform {}
@ -27,11 +44,13 @@ class ImplementsSamplePluginPlatformUsingNoSuchMethod
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
} }
class ImplementsSamplePluginPlatformUsingMockPlatformInterfaceMixin extends Mock // #docregion Mock
class SamplePluginPlatformMock extends Mock
with MockPlatformInterfaceMixin with MockPlatformInterfaceMixin
implements SamplePluginPlatform {} implements SamplePluginPlatform {}
// #enddocregion Mock
class ImplementsSamplePluginPlatformUsingFakePlatformInterfaceMixin extends Fake class SamplePluginPlatformFake extends Fake
with MockPlatformInterfaceMixin with MockPlatformInterfaceMixin
implements SamplePluginPlatform {} implements SamplePluginPlatform {}
@ -112,14 +131,12 @@ void main() {
}); });
test('allows mocking with `implements`', () { test('allows mocking with `implements`', () {
final SamplePluginPlatform mock = final SamplePluginPlatform mock = SamplePluginPlatformMock();
ImplementsSamplePluginPlatformUsingMockPlatformInterfaceMixin();
SamplePluginPlatform.instance = mock; SamplePluginPlatform.instance = mock;
}); });
test('allows faking with `implements`', () { test('allows faking with `implements`', () {
final SamplePluginPlatform fake = final SamplePluginPlatform fake = SamplePluginPlatformFake();
ImplementsSamplePluginPlatformUsingFakePlatformInterfaceMixin();
SamplePluginPlatform.instance = fake; SamplePluginPlatform.instance = fake;
}); });

View File

@ -22,8 +22,6 @@
- ios_platform_images - ios_platform_images
- multicast_dns - multicast_dns
- palette_generator - palette_generator
- pigeon
- plugin_platform_interface
- pointer_interceptor - pointer_interceptor
- quick_actions/quick_actions - quick_actions/quick_actions
- webview_flutter_android - webview_flutter_android