mirror of
https://github.com/flutter/packages.git
synced 2025-07-02 08:34:31 +08:00
[webview_flutter_wkwebview] Adds the isInspectable
to WebKitWebViewController
. (#3984)
Fixes: flutter/flutter#126899 Starting from iOS version 16.4, it is now possible to change the value of the isInspectable property in WKWebView. https://developer.apple.com/documentation/webkit/wkwebview/4111163-isinspectable Since iOS 16.4, the Web Inspector feature is disabled by default. Therefore, to use Web Inspector, need to change the value of isInspectable. Here is a blog post from WebKit that discusses this https://webkit.org/blog/13936/enabling-the-inspection-of-web-content-in-apps/ Apple Developer Forums thread (iOS 16.4 webview can not debug in safari web inspector) https://developer.apple.com/forums/thread/727049
This commit is contained in:
@ -1,3 +1,8 @@
|
||||
## 3.6.0
|
||||
|
||||
* Adds support to enable debugging of web contents on the latest versions of WebKit. See
|
||||
`WebKitWebViewController.setInspectable`.
|
||||
|
||||
## 3.5.0
|
||||
|
||||
* Adds support to limit navigation to pages within the app’s domain. See
|
||||
|
@ -464,4 +464,20 @@ static bool feq(CGFloat a, CGFloat b) { return fabs(b - a) < FLT_EPSILON; }
|
||||
XCTAssertTrue(feq(webView.scrollView.contentInset.bottom, -insetToAdjust.bottom));
|
||||
XCTAssertTrue(CGRectEqualToRect(webView.frame, CGRectMake(0, 0, 300, 100)));
|
||||
}
|
||||
|
||||
- (void)testSetInspectable API_AVAILABLE(ios(16.4), macos(13.3), tvos(16.4)) {
|
||||
FWFWebView *mockWebView = OCMClassMock([FWFWebView class]);
|
||||
|
||||
FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
|
||||
[instanceManager addDartCreatedInstance:mockWebView withIdentifier:0];
|
||||
|
||||
FWFWebViewHostApiImpl *hostAPI = [[FWFWebViewHostApiImpl alloc]
|
||||
initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
|
||||
instanceManager:instanceManager];
|
||||
|
||||
FlutterError *error;
|
||||
[hostAPI setInspectableForWebViewWithIdentifier:@0 inspectable:@YES error:&error];
|
||||
OCMVerify([mockWebView setInspectable:YES]);
|
||||
XCTAssertNil(error);
|
||||
}
|
||||
@end
|
||||
|
@ -751,6 +751,9 @@ NSObject<FlutterMessageCodec> *FWFWKWebViewHostApiGetCodec(void);
|
||||
javaScriptString:(NSString *)javaScriptString
|
||||
completion:(void (^)(id _Nullable,
|
||||
FlutterError *_Nullable))completion;
|
||||
- (void)setInspectableForWebViewWithIdentifier:(NSNumber *)identifier
|
||||
inspectable:(NSNumber *)inspectable
|
||||
error:(FlutterError *_Nullable *_Nonnull)error;
|
||||
@end
|
||||
|
||||
extern void FWFWKWebViewHostApiSetup(id<FlutterBinaryMessenger> binaryMessenger,
|
||||
|
@ -2481,6 +2481,31 @@ void FWFWKWebViewHostApiSetup(id<FlutterBinaryMessenger> binaryMessenger,
|
||||
[channel setMessageHandler:nil];
|
||||
}
|
||||
}
|
||||
{
|
||||
FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
|
||||
initWithName:@"dev.flutter.pigeon.WKWebViewHostApi.setInspectable"
|
||||
binaryMessenger:binaryMessenger
|
||||
codec:FWFWKWebViewHostApiGetCodec()];
|
||||
if (api) {
|
||||
NSCAssert([api respondsToSelector:@selector(setInspectableForWebViewWithIdentifier:
|
||||
inspectable:error:)],
|
||||
@"FWFWKWebViewHostApi api (%@) doesn't respond to "
|
||||
@"@selector(setInspectableForWebViewWithIdentifier:inspectable:error:)",
|
||||
api);
|
||||
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
|
||||
NSArray *args = message;
|
||||
NSNumber *arg_identifier = GetNullableObjectAtIndex(args, 0);
|
||||
NSNumber *arg_inspectable = GetNullableObjectAtIndex(args, 1);
|
||||
FlutterError *error;
|
||||
[api setInspectableForWebViewWithIdentifier:arg_identifier
|
||||
inspectable:arg_inspectable
|
||||
error:&error];
|
||||
callback(wrapResult(nil, error));
|
||||
}];
|
||||
} else {
|
||||
[channel setMessageHandler:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
NSObject<FlutterMessageCodec> *FWFWKUIDelegateHostApiGetCodec(void) {
|
||||
static FlutterStandardMessageCodec *sSharedObject = nil;
|
||||
|
@ -197,6 +197,18 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setInspectableForWebViewWithIdentifier:(NSNumber *)identifier
|
||||
inspectable:(NSNumber *)inspectable
|
||||
error:(FlutterError *_Nullable *_Nonnull)error {
|
||||
if (@available(macOS 13.3, iOS 16.4, tvOS 16.4, *)) {
|
||||
[[self webViewForIdentifier:identifier] setInspectable:inspectable.boolValue];
|
||||
} else {
|
||||
*error = [FlutterError errorWithCode:@"FWFUnsupportedVersionError"
|
||||
message:@"setInspectable is only supported on versions 16.4+."
|
||||
details:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)goBackForWebViewWithIdentifier:(nonnull NSNumber *)identifier
|
||||
error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
|
||||
[[self webViewForIdentifier:identifier] goBack];
|
||||
|
@ -675,6 +675,7 @@ class ObjectOrIdentifier {
|
||||
|
||||
class _WKWebsiteDataStoreHostApiCodec extends StandardMessageCodec {
|
||||
const _WKWebsiteDataStoreHostApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is WKWebsiteDataTypeEnumData) {
|
||||
@ -961,6 +962,7 @@ class UIScrollViewHostApi {
|
||||
|
||||
class _WKWebViewConfigurationHostApiCodec extends StandardMessageCodec {
|
||||
const _WKWebViewConfigurationHostApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is WKAudiovisualMediaTypeEnumData) {
|
||||
@ -1150,6 +1152,7 @@ abstract class WKWebViewConfigurationFlutterApi {
|
||||
|
||||
class _WKUserContentControllerHostApiCodec extends StandardMessageCodec {
|
||||
const _WKUserContentControllerHostApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is WKUserScriptData) {
|
||||
@ -1435,6 +1438,7 @@ class WKScriptMessageHandlerHostApi {
|
||||
|
||||
class _WKScriptMessageHandlerFlutterApiCodec extends StandardMessageCodec {
|
||||
const _WKScriptMessageHandlerFlutterApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is WKScriptMessageData) {
|
||||
@ -1537,6 +1541,7 @@ class WKNavigationDelegateHostApi {
|
||||
|
||||
class _WKNavigationDelegateFlutterApiCodec extends StandardMessageCodec {
|
||||
const _WKNavigationDelegateFlutterApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is NSErrorData) {
|
||||
@ -1768,6 +1773,7 @@ abstract class WKNavigationDelegateFlutterApi {
|
||||
|
||||
class _NSObjectHostApiCodec extends StandardMessageCodec {
|
||||
const _NSObjectHostApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is NSKeyValueObservingOptionsEnumData) {
|
||||
@ -1881,6 +1887,7 @@ class NSObjectHostApi {
|
||||
|
||||
class _NSObjectFlutterApiCodec extends StandardMessageCodec {
|
||||
const _NSObjectFlutterApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is NSKeyValueChangeKeyEnumData) {
|
||||
@ -1982,6 +1989,7 @@ abstract class NSObjectFlutterApi {
|
||||
|
||||
class _WKWebViewHostApiCodec extends StandardMessageCodec {
|
||||
const _WKWebViewHostApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is NSErrorData) {
|
||||
@ -2527,6 +2535,28 @@ class WKWebViewHostApi {
|
||||
return replyList[0];
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setInspectable(int arg_identifier, bool arg_inspectable) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.WKWebViewHostApi.setInspectable', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList = await channel
|
||||
.send(<Object?>[arg_identifier, arg_inspectable]) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
message: 'Unable to establish connection on channel.',
|
||||
);
|
||||
} else if (replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: replyList[0]! as String,
|
||||
message: replyList[1] as String?,
|
||||
details: replyList[2],
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Mirror of WKUIDelegate.
|
||||
@ -2567,6 +2597,7 @@ class WKUIDelegateHostApi {
|
||||
|
||||
class _WKUIDelegateFlutterApiCodec extends StandardMessageCodec {
|
||||
const _WKUIDelegateFlutterApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is NSUrlRequestData) {
|
||||
@ -2703,6 +2734,7 @@ abstract class WKUIDelegateFlutterApi {
|
||||
|
||||
class _WKHttpCookieStoreHostApiCodec extends StandardMessageCodec {
|
||||
const _WKHttpCookieStoreHostApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is NSHttpCookieData) {
|
||||
|
@ -1107,6 +1107,24 @@ class WKWebView extends UIView {
|
||||
);
|
||||
}
|
||||
|
||||
/// Enables debugging of web contents (HTML / CSS / JavaScript) in the
|
||||
/// underlying WebView.
|
||||
///
|
||||
/// This flag can be enabled in order to facilitate debugging of web layouts
|
||||
/// and JavaScript code running inside WebViews. Please refer to [WKWebView](https://developer.apple.com/documentation/webkit/wkwebview?language=objc).
|
||||
/// documentation for the debugging guide.
|
||||
///
|
||||
/// Starting from macOS version 13.3, iOS version 16.4, and tvOS version 16.4,
|
||||
/// the default value is set to false.
|
||||
///
|
||||
/// Defaults to true in previous versions.
|
||||
Future<void> setInspectable(bool inspectable) {
|
||||
return _webViewApi.setInspectableForInstances(
|
||||
this,
|
||||
inspectable,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
WKWebView copy() {
|
||||
return WKWebView.detached(
|
||||
|
@ -1067,6 +1067,17 @@ class WKWebViewHostApiImpl extends WKWebViewHostApi {
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls [setInspectable] with the ids of the provided object instances.
|
||||
Future<void> setInspectableForInstances(
|
||||
WKWebView instance,
|
||||
bool inspectable,
|
||||
) async {
|
||||
return setInspectable(
|
||||
instanceManager.getIdentifier(instance)!,
|
||||
inspectable,
|
||||
);
|
||||
}
|
||||
|
||||
/// Calls [setNavigationDelegate] with the ids of the provided object instances.
|
||||
Future<void> setNavigationDelegateForInstances(
|
||||
WKWebView instance,
|
||||
|
@ -544,6 +544,18 @@ class WebKitWebViewController extends PlatformWebViewController {
|
||||
) async {
|
||||
_onPermissionRequestCallback = onPermissionRequest;
|
||||
}
|
||||
|
||||
/// Whether to enable tools for debugging the current WKWebView content.
|
||||
///
|
||||
/// It needs to be activated in each WKWebView where you want to enable it.
|
||||
///
|
||||
/// Starting from macOS version 13.3, iOS version 16.4, and tvOS version 16.4,
|
||||
/// the default value is set to false.
|
||||
///
|
||||
/// Defaults to true in previous versions.
|
||||
Future<void> setInspectable(bool inspectable) {
|
||||
return _webView.setInspectable(inspectable);
|
||||
}
|
||||
}
|
||||
|
||||
/// An implementation of [JavaScriptChannelParams] with the WebKit api.
|
||||
|
@ -694,6 +694,9 @@ abstract class WKWebViewHostApi {
|
||||
@ObjCSelector('evaluateJavaScriptForWebViewWithIdentifier:javaScriptString:')
|
||||
@async
|
||||
Object? evaluateJavaScript(int identifier, String javaScriptString);
|
||||
|
||||
@ObjCSelector('setInspectableForWebViewWithIdentifier:inspectable:')
|
||||
void setInspectable(int identifier, bool inspectable);
|
||||
}
|
||||
|
||||
/// Mirror of WKUIDelegate.
|
||||
|
@ -2,7 +2,7 @@ name: webview_flutter_wkwebview
|
||||
description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control.
|
||||
repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_wkwebview
|
||||
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
|
||||
version: 3.5.0
|
||||
version: 3.6.0
|
||||
|
||||
environment:
|
||||
sdk: ">=2.18.0 <4.0.0"
|
||||
|
@ -641,6 +641,15 @@ class MockWKWebView extends _i1.Mock implements _i4.WKWebView {
|
||||
returnValue: _i5.Future<Object?>.value(),
|
||||
) as _i5.Future<Object?>);
|
||||
@override
|
||||
_i5.Future<void> setInspectable(bool? inspectable) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#setInspectable,
|
||||
[inspectable],
|
||||
),
|
||||
returnValue: _i5.Future<void>.value(),
|
||||
returnValueForMissingStub: _i5.Future<void>.value(),
|
||||
) as _i5.Future<void>);
|
||||
@override
|
||||
_i4.WKWebView copy() => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#copy,
|
||||
|
@ -7,14 +7,15 @@
|
||||
// ignore_for_file: avoid_relative_lib_imports
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
|
||||
|
||||
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:webview_flutter_wkwebview/src/common/web_kit.g.dart';
|
||||
|
||||
class _TestWKWebsiteDataStoreHostApiCodec extends StandardMessageCodec {
|
||||
const _TestWKWebsiteDataStoreHostApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is WKWebsiteDataTypeEnumData) {
|
||||
@ -333,6 +334,7 @@ abstract class TestUIScrollViewHostApi {
|
||||
|
||||
class _TestWKWebViewConfigurationHostApiCodec extends StandardMessageCodec {
|
||||
const _TestWKWebViewConfigurationHostApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is WKAudiovisualMediaTypeEnumData) {
|
||||
@ -511,6 +513,7 @@ abstract class TestWKWebViewConfigurationHostApi {
|
||||
|
||||
class _TestWKUserContentControllerHostApiCodec extends StandardMessageCodec {
|
||||
const _TestWKUserContentControllerHostApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is WKUserScriptData) {
|
||||
@ -867,6 +870,7 @@ abstract class TestWKNavigationDelegateHostApi {
|
||||
|
||||
class _TestNSObjectHostApiCodec extends StandardMessageCodec {
|
||||
const _TestNSObjectHostApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is NSKeyValueObservingOptionsEnumData) {
|
||||
@ -995,6 +999,7 @@ abstract class TestNSObjectHostApi {
|
||||
|
||||
class _TestWKWebViewHostApiCodec extends StandardMessageCodec {
|
||||
const _TestWKWebViewHostApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is NSErrorData) {
|
||||
@ -1145,6 +1150,8 @@ abstract class TestWKWebViewHostApi {
|
||||
|
||||
Future<Object?> evaluateJavaScript(int identifier, String javaScriptString);
|
||||
|
||||
void setInspectable(int identifier, bool inspectable);
|
||||
|
||||
static void setup(TestWKWebViewHostApi? api,
|
||||
{BinaryMessenger? binaryMessenger}) {
|
||||
{
|
||||
@ -1575,6 +1582,31 @@ abstract class TestWKWebViewHostApi {
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.WKWebViewHostApi.setInspectable', codec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
_testBinaryMessengerBinding!.defaultBinaryMessenger
|
||||
.setMockDecodedMessageHandler<Object?>(channel, null);
|
||||
} else {
|
||||
_testBinaryMessengerBinding!.defaultBinaryMessenger
|
||||
.setMockDecodedMessageHandler<Object?>(channel,
|
||||
(Object? message) async {
|
||||
assert(message != null,
|
||||
'Argument for dev.flutter.pigeon.WKWebViewHostApi.setInspectable was null.');
|
||||
final List<Object?> args = (message as List<Object?>?)!;
|
||||
final int? arg_identifier = (args[0] as int?);
|
||||
assert(arg_identifier != null,
|
||||
'Argument for dev.flutter.pigeon.WKWebViewHostApi.setInspectable was null, expected non-null int.');
|
||||
final bool? arg_inspectable = (args[1] as bool?);
|
||||
assert(arg_inspectable != null,
|
||||
'Argument for dev.flutter.pigeon.WKWebViewHostApi.setInspectable was null, expected non-null bool.');
|
||||
api.setInspectable(arg_identifier!, arg_inspectable!);
|
||||
return <Object?>[];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1617,6 +1649,7 @@ abstract class TestWKUIDelegateHostApi {
|
||||
|
||||
class _TestWKHttpCookieStoreHostApiCodec extends StandardMessageCodec {
|
||||
const _TestWKHttpCookieStoreHostApiCodec();
|
||||
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is NSHttpCookieData) {
|
||||
|
@ -321,6 +321,21 @@ class MockTestWKWebViewHostApi extends _i1.Mock
|
||||
),
|
||||
returnValue: _i4.Future<Object?>.value(),
|
||||
) as _i4.Future<Object?>);
|
||||
@override
|
||||
void setInspectable(
|
||||
int? identifier,
|
||||
bool? inspectable,
|
||||
) =>
|
||||
super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#setInspectable,
|
||||
[
|
||||
identifier,
|
||||
inspectable,
|
||||
],
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
}
|
||||
|
||||
/// A class which mocks [TestUIScrollViewHostApi].
|
||||
|
@ -550,6 +550,21 @@ class MockTestWKWebViewHostApi extends _i1.Mock
|
||||
),
|
||||
returnValue: _i3.Future<Object?>.value(),
|
||||
) as _i3.Future<Object?>);
|
||||
@override
|
||||
void setInspectable(
|
||||
int? identifier,
|
||||
bool? inspectable,
|
||||
) =>
|
||||
super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#setInspectable,
|
||||
[
|
||||
identifier,
|
||||
inspectable,
|
||||
],
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
}
|
||||
|
||||
/// A class which mocks [TestWKWebsiteDataStoreHostApi].
|
||||
|
@ -1153,6 +1153,17 @@ void main() {
|
||||
]);
|
||||
expect(decision, WKPermissionDecision.grant);
|
||||
});
|
||||
|
||||
test('inspectable', () async {
|
||||
final MockWKWebView mockWebView = MockWKWebView();
|
||||
|
||||
final WebKitWebViewController controller = createControllerWithMocks(
|
||||
createMockWebView: (_, {dynamic observeValue}) => mockWebView,
|
||||
);
|
||||
|
||||
await controller.setInspectable(true);
|
||||
verify(mockWebView.setInspectable(true));
|
||||
});
|
||||
});
|
||||
|
||||
group('WebKitJavaScriptChannelParams', () {
|
||||
@ -1204,6 +1215,7 @@ class CapturingNavigationDelegate extends WKNavigationDelegate {
|
||||
}) : super.detached() {
|
||||
lastCreatedDelegate = this;
|
||||
}
|
||||
|
||||
static CapturingNavigationDelegate lastCreatedDelegate =
|
||||
CapturingNavigationDelegate();
|
||||
}
|
||||
@ -1217,5 +1229,6 @@ class CapturingUIDelegate extends WKUIDelegate {
|
||||
}) : super.detached() {
|
||||
lastCreatedDelegate = this;
|
||||
}
|
||||
|
||||
static CapturingUIDelegate lastCreatedDelegate = CapturingUIDelegate();
|
||||
}
|
||||
|
@ -738,6 +738,15 @@ class MockWKWebView extends _i1.Mock implements _i5.WKWebView {
|
||||
returnValue: _i6.Future<Object?>.value(),
|
||||
) as _i6.Future<Object?>);
|
||||
@override
|
||||
_i6.Future<void> setInspectable(bool? inspectable) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#setInspectable,
|
||||
[inspectable],
|
||||
),
|
||||
returnValue: _i6.Future<void>.value(),
|
||||
returnValueForMissingStub: _i6.Future<void>.value(),
|
||||
) as _i6.Future<void>);
|
||||
@override
|
||||
_i5.WKWebView copy() => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#copy,
|
||||
|
Reference in New Issue
Block a user