mirror of
https://github.com/flutter/packages.git
synced 2025-06-29 06:06:59 +08:00
[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:
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
|
@ -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;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user