mirror of
https://github.com/flutter/packages.git
synced 2025-06-27 04:37:07 +08:00
[webview_flutter] Support for handling basic authentication requests (iOS) (#5455)
Adds the iOS implementation for basic http authentication. This PR is part of a series of PRs that aim to close https://github.com/flutter/flutter/issues/83556. The PR that contains all changes can be found at https://github.com/flutter/packages/pull/4140.
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
## NEXT
|
||||
## 3.10.0
|
||||
|
||||
* Adds support for `PlatformNavigationDelegate.setOnHttpAuthRequest`.
|
||||
* Updates minimum supported SDK version to Flutter 3.10/Dart 3.0.
|
||||
|
||||
## 3.9.4
|
||||
|
@ -34,6 +34,15 @@ Future<void> main() async {
|
||||
request.response.writeln('${request.headers}');
|
||||
} else if (request.uri.path == '/favicon.ico') {
|
||||
request.response.statusCode = HttpStatus.notFound;
|
||||
} else if (request.uri.path == '/http-basic-authentication') {
|
||||
final bool isAuthenticating = request.headers['Authorization'] != null;
|
||||
if (isAuthenticating) {
|
||||
request.response.writeln('Authorized');
|
||||
} else {
|
||||
request.response.headers
|
||||
.add('WWW-Authenticate', 'Basic realm="Test realm"');
|
||||
request.response.statusCode = HttpStatus.unauthorized;
|
||||
}
|
||||
} else {
|
||||
fail('unexpected request: ${request.method} ${request.uri}');
|
||||
}
|
||||
@ -43,6 +52,7 @@ Future<void> main() async {
|
||||
final String primaryUrl = '$prefixUrl/hello.txt';
|
||||
final String secondaryUrl = '$prefixUrl/secondary.txt';
|
||||
final String headersUrl = '$prefixUrl/headers';
|
||||
final String basicAuthUrl = '$prefixUrl/http-basic-authentication';
|
||||
|
||||
testWidgets(
|
||||
'withWeakReferenceTo allows encapsulating class to be garbage collected',
|
||||
@ -1127,6 +1137,82 @@ Future<void> main() async {
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('can receive HTTP basic auth requests',
|
||||
(WidgetTester tester) async {
|
||||
final Completer<void> authRequested = Completer<void>();
|
||||
final PlatformWebViewController controller = PlatformWebViewController(
|
||||
const PlatformWebViewControllerCreationParams(),
|
||||
);
|
||||
|
||||
final PlatformNavigationDelegate navigationDelegate =
|
||||
PlatformNavigationDelegate(
|
||||
const PlatformNavigationDelegateCreationParams(),
|
||||
);
|
||||
await navigationDelegate.setOnHttpAuthRequest(
|
||||
(HttpAuthRequest request) => authRequested.complete());
|
||||
await controller.setPlatformNavigationDelegate(navigationDelegate);
|
||||
|
||||
// Clear cache so that the auth request is always received and we don't get
|
||||
// a cached response.
|
||||
await controller.clearCache();
|
||||
|
||||
await tester.pumpWidget(
|
||||
Builder(
|
||||
builder: (BuildContext context) {
|
||||
return PlatformWebViewWidget(
|
||||
WebKitWebViewWidgetCreationParams(controller: controller),
|
||||
).build(context);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
await controller.loadRequest(
|
||||
LoadRequestParams(uri: Uri.parse(basicAuthUrl)),
|
||||
);
|
||||
|
||||
await expectLater(authRequested.future, completes);
|
||||
});
|
||||
|
||||
testWidgets('can reply to HTTP basic auth requests',
|
||||
(WidgetTester tester) async {
|
||||
final Completer<void> pageFinished = Completer<void>();
|
||||
final PlatformWebViewController controller = PlatformWebViewController(
|
||||
const PlatformWebViewControllerCreationParams(),
|
||||
);
|
||||
|
||||
final PlatformNavigationDelegate navigationDelegate =
|
||||
PlatformNavigationDelegate(
|
||||
const PlatformNavigationDelegateCreationParams(),
|
||||
);
|
||||
await navigationDelegate.setOnPageFinished((_) => pageFinished.complete());
|
||||
await navigationDelegate.setOnHttpAuthRequest(
|
||||
(HttpAuthRequest request) => request.onProceed(
|
||||
const WebViewCredential(user: 'user', password: 'password'),
|
||||
),
|
||||
);
|
||||
await controller.setPlatformNavigationDelegate(navigationDelegate);
|
||||
|
||||
// Clear cache so that the auth request is always received and we don't get
|
||||
// a cached response.
|
||||
await controller.clearCache();
|
||||
|
||||
await tester.pumpWidget(
|
||||
Builder(
|
||||
builder: (BuildContext context) {
|
||||
return PlatformWebViewWidget(
|
||||
WebKitWebViewWidgetCreationParams(controller: controller),
|
||||
).build(context);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
await controller.loadRequest(
|
||||
LoadRequestParams(uri: Uri.parse(basicAuthUrl)),
|
||||
);
|
||||
|
||||
await expectLater(pageFinished.future, completes);
|
||||
});
|
||||
|
||||
testWidgets('launches with gestureNavigationEnabled on iOS',
|
||||
(WidgetTester tester) async {
|
||||
final WebKitWebViewController controller = WebKitWebViewController(
|
||||
|
@ -11,6 +11,9 @@
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
8F4FF949299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F4FF948299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m */; };
|
||||
8F4FF94B29AC223F000A6586 /* FWFURLTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F4FF94A29AC223F000A6586 /* FWFURLTests.m */; };
|
||||
8F562F902A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F562F8F2A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m */; };
|
||||
8F562F922A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F562F912A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m */; };
|
||||
8F562F942A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F562F932A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m */; };
|
||||
8F78EAAA2A02CB9100C2E520 /* FWFErrorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F78EAA92A02CB9100C2E520 /* FWFErrorTests.m */; };
|
||||
8FA6A87928062CD000A4B183 /* FWFInstanceManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8FA6A87828062CD000A4B183 /* FWFInstanceManagerTests.m */; };
|
||||
8FB79B5328134C3100C101D3 /* FWFWebViewHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8FB79B5228134C3100C101D3 /* FWFWebViewHostApiTests.m */; };
|
||||
@ -81,6 +84,9 @@
|
||||
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
8F4FF948299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FWFWebViewFlutterWKWebViewExternalAPITests.m; sourceTree = "<group>"; };
|
||||
8F4FF94A29AC223F000A6586 /* FWFURLTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFURLTests.m; sourceTree = "<group>"; };
|
||||
8F562F8F2A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFURLCredentialHostApiTests.m; sourceTree = "<group>"; };
|
||||
8F562F912A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFURLProtectionSpaceHostApiTests.m; sourceTree = "<group>"; };
|
||||
8F562F932A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFURLAuthenticationChallengeHostApiTests.m; sourceTree = "<group>"; };
|
||||
8F78EAA92A02CB9100C2E520 /* FWFErrorTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFErrorTests.m; sourceTree = "<group>"; };
|
||||
8FA6A87828062CD000A4B183 /* FWFInstanceManagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFInstanceManagerTests.m; sourceTree = "<group>"; };
|
||||
8FB79B5228134C3100C101D3 /* FWFWebViewHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFWebViewHostApiTests.m; sourceTree = "<group>"; };
|
||||
@ -167,6 +173,9 @@
|
||||
8FB79B902820BAC700C101D3 /* FWFUIViewHostApiTests.m */,
|
||||
8FB79B962821985200C101D3 /* FWFObjectHostApiTests.m */,
|
||||
8F4FF94A29AC223F000A6586 /* FWFURLTests.m */,
|
||||
8F562F8F2A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m */,
|
||||
8F562F912A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m */,
|
||||
8F562F932A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m */,
|
||||
8F78EAA92A02CB9100C2E520 /* FWFErrorTests.m */,
|
||||
);
|
||||
path = RunnerTests;
|
||||
@ -318,7 +327,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
DefaultBuildSystemTypeForWorkspace = Original;
|
||||
LastUpgradeCheck = 1300;
|
||||
LastUpgradeCheck = 1430;
|
||||
ORGANIZATIONNAME = "The Flutter Authors";
|
||||
TargetAttributes = {
|
||||
68BDCAE823C3F7CB00D9C032 = {
|
||||
@ -327,7 +336,6 @@
|
||||
};
|
||||
97C146ED1CF9000F007C117D = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
DevelopmentTeam = 7624MWN53C;
|
||||
};
|
||||
F7151F73266057800028CB91 = {
|
||||
CreatedOnToolsVersion = 12.5;
|
||||
@ -474,12 +482,15 @@
|
||||
8FB79B852820A3A400C101D3 /* FWFUIDelegateHostApiTests.m in Sources */,
|
||||
8FB79B972821985200C101D3 /* FWFObjectHostApiTests.m in Sources */,
|
||||
8FB79B672820453400C101D3 /* FWFHTTPCookieStoreHostApiTests.m in Sources */,
|
||||
8F562F942A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m in Sources */,
|
||||
8FB79B5328134C3100C101D3 /* FWFWebViewHostApiTests.m in Sources */,
|
||||
8FB79B73282096B500C101D3 /* FWFScriptMessageHandlerHostApiTests.m in Sources */,
|
||||
8FB79B7928209D1300C101D3 /* FWFUserContentControllerHostApiTests.m in Sources */,
|
||||
8F562F902A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m in Sources */,
|
||||
8F4FF949299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m in Sources */,
|
||||
8FB79B6B28204EE500C101D3 /* FWFWebsiteDataStoreHostApiTests.m in Sources */,
|
||||
8FB79B8F2820BAB300C101D3 /* FWFScrollViewHostApiTests.m in Sources */,
|
||||
8F562F922A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m in Sources */,
|
||||
8FB79B912820BAC700C101D3 /* FWFUIViewHostApiTests.m in Sources */,
|
||||
8FB79B55281B24F600C101D3 /* FWFDataConvertersTests.m in Sources */,
|
||||
8FB79B6D2820533B00C101D3 /* FWFWebViewConfigurationHostApiTests.m in Sources */,
|
||||
@ -689,6 +700,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 7624MWN53C;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@ -715,6 +727,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 7624MWN53C;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1300"
|
||||
LastUpgradeVersion = "1430"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -213,4 +213,58 @@
|
||||
webViewIdentifier:1
|
||||
completion:OCMOCK_ANY]);
|
||||
}
|
||||
|
||||
- (void)testDidReceiveAuthenticationChallenge {
|
||||
FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
|
||||
|
||||
FWFNavigationDelegate *mockDelegate = [self mockNavigationDelegateWithManager:instanceManager
|
||||
identifier:0];
|
||||
FWFNavigationDelegateFlutterApiImpl *mockFlutterAPI =
|
||||
[self mockFlutterApiWithManager:instanceManager];
|
||||
|
||||
OCMStub([mockDelegate navigationDelegateAPI]).andReturn(mockFlutterAPI);
|
||||
|
||||
WKWebView *mockWebView = OCMClassMock([WKWebView class]);
|
||||
[instanceManager addDartCreatedInstance:mockWebView withIdentifier:1];
|
||||
|
||||
NSURLAuthenticationChallenge *mockChallenge = OCMClassMock([NSURLAuthenticationChallenge class]);
|
||||
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:@"host"
|
||||
port:0
|
||||
protocol:nil
|
||||
realm:@"realm"
|
||||
authenticationMethod:nil];
|
||||
OCMStub([mockChallenge protectionSpace]).andReturn(protectionSpace);
|
||||
[instanceManager addDartCreatedInstance:mockChallenge withIdentifier:2];
|
||||
|
||||
NSURLCredential *credential = [NSURLCredential credentialWithUser:@"user"
|
||||
password:@"password"
|
||||
persistence:NSURLCredentialPersistenceNone];
|
||||
[instanceManager addDartCreatedInstance:credential withIdentifier:5];
|
||||
|
||||
OCMStub([mockFlutterAPI
|
||||
didReceiveAuthenticationChallengeForDelegateWithIdentifier:0
|
||||
webViewIdentifier:1
|
||||
challengeIdentifier:2
|
||||
completion:
|
||||
([OCMArg
|
||||
invokeBlockWithArgs:
|
||||
[FWFAuthenticationChallengeResponse
|
||||
makeWithDisposition:
|
||||
FWFNSUrlSessionAuthChallengeDispositionCancelAuthenticationChallenge
|
||||
credentialIdentifier:@(5)],
|
||||
[NSNull null], nil])]);
|
||||
|
||||
NSURLSessionAuthChallengeDisposition __block callbackDisposition = -1;
|
||||
NSURLCredential *__block callbackCredential;
|
||||
[mockDelegate webView:mockWebView
|
||||
didReceiveAuthenticationChallenge:mockChallenge
|
||||
completionHandler:^(NSURLSessionAuthChallengeDisposition disposition,
|
||||
NSURLCredential *credential) {
|
||||
callbackDisposition = disposition;
|
||||
callbackCredential = credential;
|
||||
}];
|
||||
|
||||
XCTAssertEqual(callbackDisposition, NSURLSessionAuthChallengeCancelAuthenticationChallenge);
|
||||
XCTAssertEqualObjects(callbackCredential, credential);
|
||||
}
|
||||
@end
|
||||
|
@ -0,0 +1,47 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@import Flutter;
|
||||
@import XCTest;
|
||||
@import webview_flutter_wkwebview;
|
||||
|
||||
#import <OCMock/OCMock.h>
|
||||
|
||||
@interface FWFURLAuthenticationChallengeHostApiTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation FWFURLAuthenticationChallengeHostApiTests
|
||||
- (void)testFlutterApiCreate {
|
||||
FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
|
||||
FWFURLAuthenticationChallengeFlutterApiImpl *flutterApi =
|
||||
[[FWFURLAuthenticationChallengeFlutterApiImpl alloc]
|
||||
initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
|
||||
instanceManager:instanceManager];
|
||||
|
||||
flutterApi.api = OCMClassMock([FWFNSUrlAuthenticationChallengeFlutterApi class]);
|
||||
|
||||
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:@"host"
|
||||
port:0
|
||||
protocol:nil
|
||||
realm:@"realm"
|
||||
authenticationMethod:nil];
|
||||
|
||||
NSURLAuthenticationChallenge *mockChallenge = OCMClassMock([NSURLAuthenticationChallenge class]);
|
||||
OCMStub([mockChallenge protectionSpace]).andReturn(protectionSpace);
|
||||
|
||||
[flutterApi createWithInstance:mockChallenge
|
||||
protectionSpace:protectionSpace
|
||||
completion:^(FlutterError *error){
|
||||
|
||||
}];
|
||||
|
||||
long identifier = [instanceManager identifierWithStrongReferenceForInstance:mockChallenge];
|
||||
long protectionSpaceIdentifier =
|
||||
[instanceManager identifierWithStrongReferenceForInstance:protectionSpace];
|
||||
OCMVerify([flutterApi.api createWithIdentifier:identifier
|
||||
protectionSpaceIdentifier:protectionSpaceIdentifier
|
||||
completion:OCMOCK_ANY]);
|
||||
}
|
||||
@end
|
@ -0,0 +1,35 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@import Flutter;
|
||||
@import XCTest;
|
||||
@import webview_flutter_wkwebview;
|
||||
|
||||
#import <OCMock/OCMock.h>
|
||||
|
||||
@interface FWFURLCredentialHostApiTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation FWFURLCredentialHostApiTests
|
||||
- (void)testHostApiCreate {
|
||||
FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
|
||||
|
||||
FWFURLCredentialHostApiImpl *hostApi = [[FWFURLCredentialHostApiImpl alloc]
|
||||
initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
|
||||
instanceManager:instanceManager];
|
||||
|
||||
FlutterError *error;
|
||||
[hostApi createWithUserWithIdentifier:0
|
||||
user:@"user"
|
||||
password:@"password"
|
||||
persistence:FWFNSUrlCredentialPersistencePermanent
|
||||
error:&error];
|
||||
XCTAssertNil(error);
|
||||
|
||||
NSURLCredential *credential = (NSURLCredential *)[instanceManager instanceForIdentifier:0];
|
||||
XCTAssertEqualObjects(credential.user, @"user");
|
||||
XCTAssertEqualObjects(credential.password, @"password");
|
||||
XCTAssertEqual(credential.persistence, NSURLCredentialPersistencePermanent);
|
||||
}
|
||||
@end
|
@ -0,0 +1,43 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@import Flutter;
|
||||
@import XCTest;
|
||||
@import webview_flutter_wkwebview;
|
||||
|
||||
#import <OCMock/OCMock.h>
|
||||
|
||||
@interface FWFURLProtectionSpaceHostApiTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation FWFURLProtectionSpaceHostApiTests
|
||||
- (void)testFlutterApiCreate {
|
||||
FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
|
||||
FWFURLProtectionSpaceFlutterApiImpl *flutterApi = [[FWFURLProtectionSpaceFlutterApiImpl alloc]
|
||||
initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
|
||||
instanceManager:instanceManager];
|
||||
|
||||
flutterApi.api = OCMClassMock([FWFNSUrlProtectionSpaceFlutterApi class]);
|
||||
|
||||
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:@"host"
|
||||
port:0
|
||||
protocol:nil
|
||||
realm:@"realm"
|
||||
authenticationMethod:nil];
|
||||
[flutterApi createWithInstance:protectionSpace
|
||||
host:@"host"
|
||||
realm:@"realm"
|
||||
authenticationMethod:@"method"
|
||||
completion:^(FlutterError *error){
|
||||
|
||||
}];
|
||||
|
||||
long identifier = [instanceManager identifierWithStrongReferenceForInstance:protectionSpace];
|
||||
OCMVerify([flutterApi.api createWithIdentifier:identifier
|
||||
host:@"host"
|
||||
realm:@"realm"
|
||||
authenticationMethod:@"method"
|
||||
completion:OCMOCK_ANY]);
|
||||
}
|
||||
@end
|
@ -162,6 +162,9 @@ Page resource error:
|
||||
})
|
||||
..setOnUrlChange((UrlChange change) {
|
||||
debugPrint('url change to ${change.url}');
|
||||
})
|
||||
..setOnHttpAuthRequest((HttpAuthRequest request) {
|
||||
openDialog(request);
|
||||
}),
|
||||
)
|
||||
..addJavaScriptChannel(JavaScriptChannelParams(
|
||||
@ -220,6 +223,62 @@ Page resource error:
|
||||
child: const Icon(Icons.favorite),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> openDialog(HttpAuthRequest httpRequest) async {
|
||||
final TextEditingController usernameTextController =
|
||||
TextEditingController();
|
||||
final TextEditingController passwordTextController =
|
||||
TextEditingController();
|
||||
|
||||
return showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('${httpRequest.host}: ${httpRequest.realm ?? '-'}'),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
TextField(
|
||||
decoration: const InputDecoration(labelText: 'Username'),
|
||||
autofocus: true,
|
||||
controller: usernameTextController,
|
||||
),
|
||||
TextField(
|
||||
decoration: const InputDecoration(labelText: 'Password'),
|
||||
controller: passwordTextController,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
// Explicitly cancel the request on iOS as the OS does not emit new
|
||||
// requests when a previous request is pending.
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
httpRequest.onCancel();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
httpRequest.onProceed(
|
||||
WebViewCredential(
|
||||
user: usernameTextController.text,
|
||||
password: passwordTextController.text,
|
||||
),
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('Authenticate'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum MenuOptions {
|
||||
@ -237,6 +296,7 @@ enum MenuOptions {
|
||||
transparentBackground,
|
||||
setCookie,
|
||||
logExample,
|
||||
basicAuthentication,
|
||||
}
|
||||
|
||||
class SampleMenu extends StatelessWidget {
|
||||
@ -300,6 +360,9 @@ class SampleMenu extends StatelessWidget {
|
||||
case MenuOptions.logExample:
|
||||
_onLogExample();
|
||||
break;
|
||||
case MenuOptions.basicAuthentication:
|
||||
_promptForUrl(context);
|
||||
break;
|
||||
}
|
||||
},
|
||||
itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
|
||||
@ -360,6 +423,10 @@ class SampleMenu extends StatelessWidget {
|
||||
value: MenuOptions.logExample,
|
||||
child: Text('Log example'),
|
||||
),
|
||||
const PopupMenuItem<MenuOptions>(
|
||||
value: MenuOptions.basicAuthentication,
|
||||
child: Text('Basic Authentication Example'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -518,6 +585,41 @@ class SampleMenu extends StatelessWidget {
|
||||
|
||||
return webViewController.loadHtmlString(kLogExamplePage);
|
||||
}
|
||||
|
||||
Future<void> _promptForUrl(BuildContext context) {
|
||||
final TextEditingController urlTextController =
|
||||
TextEditingController(text: 'https://');
|
||||
|
||||
return showDialog<String>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Input URL to visit'),
|
||||
content: TextField(
|
||||
decoration: const InputDecoration(labelText: 'URL'),
|
||||
autofocus: true,
|
||||
controller: urlTextController,
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
if (urlTextController.text.isNotEmpty) {
|
||||
final Uri? uri = Uri.tryParse(urlTextController.text);
|
||||
if (uri != null && uri.scheme.isNotEmpty) {
|
||||
webViewController.loadRequest(
|
||||
LoadRequestParams(uri: uri),
|
||||
);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: const Text('Visit'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NavigationControls extends StatelessWidget {
|
||||
|
@ -10,7 +10,7 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
path_provider: ^2.0.6
|
||||
webview_flutter_platform_interface: ^2.6.0
|
||||
webview_flutter_platform_interface: ^2.7.0
|
||||
webview_flutter_wkwebview:
|
||||
# When depending on this package from a real application you should use:
|
||||
# webview_flutter: ^x.y.z
|
||||
|
@ -13,6 +13,7 @@
|
||||
#import "FWFScrollViewHostApi.h"
|
||||
#import "FWFUIDelegateHostApi.h"
|
||||
#import "FWFUIViewHostApi.h"
|
||||
#import "FWFURLCredentialHostApi.h"
|
||||
#import "FWFURLHostApi.h"
|
||||
#import "FWFUserContentControllerHostApi.h"
|
||||
#import "FWFWebViewConfigurationHostApi.h"
|
||||
@ -105,6 +106,11 @@
|
||||
[[FWFURLHostApiImpl alloc] initWithBinaryMessenger:registrar.messenger
|
||||
instanceManager:instanceManager]);
|
||||
|
||||
SetUpFWFNSUrlCredentialHostApi(
|
||||
registrar.messenger,
|
||||
[[FWFURLCredentialHostApiImpl alloc] initWithBinaryMessenger:registrar.messenger
|
||||
instanceManager:instanceManager]);
|
||||
|
||||
FWFWebViewFactory *webviewFactory = [[FWFWebViewFactory alloc] initWithManager:instanceManager];
|
||||
[registrar registerViewFactory:webviewFactory withId:@"plugins.flutter.io/webview"];
|
||||
|
||||
|
@ -193,4 +193,26 @@ API_AVAILABLE(ios(15.0))
|
||||
extern FWFWKMediaCaptureTypeData *FWFWKMediaCaptureTypeDataFromNativeWKMediaCaptureType(
|
||||
WKMediaCaptureType type);
|
||||
|
||||
/**
|
||||
* Converts an FWFNSUrlSessionAuthChallengeDisposition to an NSURLSessionAuthChallengeDisposition.
|
||||
*
|
||||
* @param value The object containing information to create an NSURLSessionAuthChallengeDisposition.
|
||||
*
|
||||
* @return A NSURLSessionAuthChallengeDisposition or -1 if data could not be converted.
|
||||
*/
|
||||
extern NSURLSessionAuthChallengeDisposition
|
||||
FWFNativeNSURLSessionAuthChallengeDispositionFromFWFNSUrlSessionAuthChallengeDisposition(
|
||||
FWFNSUrlSessionAuthChallengeDisposition value);
|
||||
|
||||
/**
|
||||
* Converts an FWFNSUrlCredentialPersistence to an NSURLCredentialPersistence.
|
||||
*
|
||||
* @param value The object containing information to create an NSURLCredentialPersistence.
|
||||
*
|
||||
* @return A NSURLCredentialPersistence or -1 if data could not be converted.
|
||||
*/
|
||||
extern NSURLCredentialPersistence
|
||||
FWFNativeNSURLCredentialPersistenceFromFWFNSUrlCredentialPersistence(
|
||||
FWFNSUrlCredentialPersistence value);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
@ -285,3 +285,36 @@ FWFWKMediaCaptureTypeData *FWFWKMediaCaptureTypeDataFromNativeWKMediaCaptureType
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSURLSessionAuthChallengeDisposition
|
||||
FWFNativeNSURLSessionAuthChallengeDispositionFromFWFNSUrlSessionAuthChallengeDisposition(
|
||||
FWFNSUrlSessionAuthChallengeDisposition value) {
|
||||
switch (value) {
|
||||
case FWFNSUrlSessionAuthChallengeDispositionUseCredential:
|
||||
return NSURLSessionAuthChallengeUseCredential;
|
||||
case FWFNSUrlSessionAuthChallengeDispositionPerformDefaultHandling:
|
||||
return NSURLSessionAuthChallengePerformDefaultHandling;
|
||||
case FWFNSUrlSessionAuthChallengeDispositionCancelAuthenticationChallenge:
|
||||
return NSURLSessionAuthChallengeCancelAuthenticationChallenge;
|
||||
case FWFNSUrlSessionAuthChallengeDispositionRejectProtectionSpace:
|
||||
return NSURLSessionAuthChallengeRejectProtectionSpace;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
NSURLCredentialPersistence FWFNativeNSURLCredentialPersistenceFromFWFNSUrlCredentialPersistence(
|
||||
FWFNSUrlCredentialPersistence value) {
|
||||
switch (value) {
|
||||
case FWFNSUrlCredentialPersistenceNone:
|
||||
return NSURLCredentialPersistenceNone;
|
||||
case FWFNSUrlCredentialPersistenceSession:
|
||||
return NSURLCredentialPersistenceForSession;
|
||||
case FWFNSUrlCredentialPersistencePermanent:
|
||||
return NSURLCredentialPersistencePermanent;
|
||||
case FWFNSUrlCredentialPersistenceSynchronizable:
|
||||
return NSURLCredentialPersistenceSynchronizable;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -264,6 +264,73 @@ typedef NS_ENUM(NSUInteger, FWFWKMediaCaptureType) {
|
||||
- (instancetype)initWithValue:(FWFWKMediaCaptureType)value;
|
||||
@end
|
||||
|
||||
/// Responses to an authentication challenge.
|
||||
///
|
||||
/// See
|
||||
/// https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition?language=objc.
|
||||
typedef NS_ENUM(NSUInteger, FWFNSUrlSessionAuthChallengeDisposition) {
|
||||
/// Use the specified credential, which may be nil.
|
||||
///
|
||||
/// See
|
||||
/// https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengeusecredential?language=objc.
|
||||
FWFNSUrlSessionAuthChallengeDispositionUseCredential = 0,
|
||||
/// Use the default handling for the challenge as though this delegate method
|
||||
/// were not implemented.
|
||||
///
|
||||
/// See
|
||||
/// https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengeperformdefaulthandling?language=objc.
|
||||
FWFNSUrlSessionAuthChallengeDispositionPerformDefaultHandling = 1,
|
||||
/// Cancel the entire request.
|
||||
///
|
||||
/// See
|
||||
/// https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengecancelauthenticationchallenge?language=objc.
|
||||
FWFNSUrlSessionAuthChallengeDispositionCancelAuthenticationChallenge = 2,
|
||||
/// Reject this challenge, and call the authentication delegate method again
|
||||
/// with the next authentication protection space.
|
||||
///
|
||||
/// See
|
||||
/// https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengerejectprotectionspace?language=objc.
|
||||
FWFNSUrlSessionAuthChallengeDispositionRejectProtectionSpace = 3,
|
||||
};
|
||||
|
||||
/// Wrapper for FWFNSUrlSessionAuthChallengeDisposition to allow for nullability.
|
||||
@interface FWFNSUrlSessionAuthChallengeDispositionBox : NSObject
|
||||
@property(nonatomic, assign) FWFNSUrlSessionAuthChallengeDisposition value;
|
||||
- (instancetype)initWithValue:(FWFNSUrlSessionAuthChallengeDisposition)value;
|
||||
@end
|
||||
|
||||
/// Specifies how long a credential will be kept.
|
||||
typedef NS_ENUM(NSUInteger, FWFNSUrlCredentialPersistence) {
|
||||
/// The credential should not be stored.
|
||||
///
|
||||
/// See
|
||||
/// https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencenone?language=objc.
|
||||
FWFNSUrlCredentialPersistenceNone = 0,
|
||||
/// The credential should be stored only for this session.
|
||||
///
|
||||
/// See
|
||||
/// https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistenceforsession?language=objc.
|
||||
FWFNSUrlCredentialPersistenceSession = 1,
|
||||
/// The credential should be stored in the keychain.
|
||||
///
|
||||
/// See
|
||||
/// https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencepermanent?language=objc.
|
||||
FWFNSUrlCredentialPersistencePermanent = 2,
|
||||
/// The credential should be stored permanently in the keychain, and in
|
||||
/// addition should be distributed to other devices based on the owning Apple
|
||||
/// ID.
|
||||
///
|
||||
/// See
|
||||
/// https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencesynchronizable?language=objc.
|
||||
FWFNSUrlCredentialPersistenceSynchronizable = 3,
|
||||
};
|
||||
|
||||
/// Wrapper for FWFNSUrlCredentialPersistence to allow for nullability.
|
||||
@interface FWFNSUrlCredentialPersistenceBox : NSObject
|
||||
@property(nonatomic, assign) FWFNSUrlCredentialPersistence value;
|
||||
- (instancetype)initWithValue:(FWFNSUrlCredentialPersistence)value;
|
||||
@end
|
||||
|
||||
@class FWFNSKeyValueObservingOptionsEnumData;
|
||||
@class FWFNSKeyValueChangeKeyEnumData;
|
||||
@class FWFWKUserScriptInjectionTimeEnumData;
|
||||
@ -282,6 +349,7 @@ typedef NS_ENUM(NSUInteger, FWFWKMediaCaptureType) {
|
||||
@class FWFWKSecurityOriginData;
|
||||
@class FWFNSHttpCookieData;
|
||||
@class FWFObjectOrIdentifier;
|
||||
@class FWFAuthenticationChallengeResponse;
|
||||
|
||||
@interface FWFNSKeyValueObservingOptionsEnumData : NSObject
|
||||
/// `init` unavailable to enforce nonnull fields, see the `make` class method.
|
||||
@ -462,6 +530,15 @@ typedef NS_ENUM(NSUInteger, FWFWKMediaCaptureType) {
|
||||
@property(nonatomic, assign) BOOL isIdentifier;
|
||||
@end
|
||||
|
||||
@interface FWFAuthenticationChallengeResponse : NSObject
|
||||
/// `init` unavailable to enforce nonnull fields, see the `make` class method.
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
+ (instancetype)makeWithDisposition:(FWFNSUrlSessionAuthChallengeDisposition)disposition
|
||||
credentialIdentifier:(nullable NSNumber *)credentialIdentifier;
|
||||
@property(nonatomic, assign) FWFNSUrlSessionAuthChallengeDisposition disposition;
|
||||
@property(nonatomic, strong, nullable) NSNumber *credentialIdentifier;
|
||||
@end
|
||||
|
||||
/// The codec used by FWFWKWebsiteDataStoreHostApi.
|
||||
NSObject<FlutterMessageCodec> *FWFWKWebsiteDataStoreHostApiGetCodec(void);
|
||||
|
||||
@ -711,6 +788,14 @@ NSObject<FlutterMessageCodec> *FWFWKNavigationDelegateFlutterApiGetCodec(void);
|
||||
completion:
|
||||
(void (^)(FlutterError *_Nullable))
|
||||
completion;
|
||||
- (void)didReceiveAuthenticationChallengeForDelegateWithIdentifier:(NSInteger)identifier
|
||||
webViewIdentifier:(NSInteger)webViewIdentifier
|
||||
challengeIdentifier:(NSInteger)challengeIdentifier
|
||||
completion:
|
||||
(void (^)(
|
||||
FWFAuthenticationChallengeResponse
|
||||
*_Nullable,
|
||||
FlutterError *_Nullable))completion;
|
||||
@end
|
||||
|
||||
/// The codec used by FWFNSObjectHostApi.
|
||||
@ -919,4 +1004,65 @@ NSObject<FlutterMessageCodec> *FWFNSUrlFlutterApiGetCodec(void);
|
||||
completion:(void (^)(FlutterError *_Nullable))completion;
|
||||
@end
|
||||
|
||||
/// The codec used by FWFNSUrlCredentialHostApi.
|
||||
NSObject<FlutterMessageCodec> *FWFNSUrlCredentialHostApiGetCodec(void);
|
||||
|
||||
/// Host API for `NSUrlCredential`.
|
||||
///
|
||||
/// This class may handle instantiating and adding native object instances that
|
||||
/// are attached to a Dart instance or handle method calls on the associated
|
||||
/// native class or an instance of the class.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlcredential?language=objc.
|
||||
@protocol FWFNSUrlCredentialHostApi
|
||||
/// Create a new native instance and add it to the `InstanceManager`.
|
||||
- (void)createWithUserWithIdentifier:(NSInteger)identifier
|
||||
user:(NSString *)user
|
||||
password:(NSString *)password
|
||||
persistence:(FWFNSUrlCredentialPersistence)persistence
|
||||
error:(FlutterError *_Nullable *_Nonnull)error;
|
||||
@end
|
||||
|
||||
extern void SetUpFWFNSUrlCredentialHostApi(id<FlutterBinaryMessenger> binaryMessenger,
|
||||
NSObject<FWFNSUrlCredentialHostApi> *_Nullable api);
|
||||
|
||||
/// The codec used by FWFNSUrlProtectionSpaceFlutterApi.
|
||||
NSObject<FlutterMessageCodec> *FWFNSUrlProtectionSpaceFlutterApiGetCodec(void);
|
||||
|
||||
/// Flutter API for `NSUrlProtectionSpace`.
|
||||
///
|
||||
/// This class may handle instantiating and adding Dart instances that are
|
||||
/// attached to a native instance or receiving callback methods from an
|
||||
/// overridden native class.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlprotectionspace?language=objc.
|
||||
@interface FWFNSUrlProtectionSpaceFlutterApi : NSObject
|
||||
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger;
|
||||
/// Create a new Dart instance and add it to the `InstanceManager`.
|
||||
- (void)createWithIdentifier:(NSInteger)identifier
|
||||
host:(nullable NSString *)host
|
||||
realm:(nullable NSString *)realm
|
||||
authenticationMethod:(nullable NSString *)authenticationMethod
|
||||
completion:(void (^)(FlutterError *_Nullable))completion;
|
||||
@end
|
||||
|
||||
/// The codec used by FWFNSUrlAuthenticationChallengeFlutterApi.
|
||||
NSObject<FlutterMessageCodec> *FWFNSUrlAuthenticationChallengeFlutterApiGetCodec(void);
|
||||
|
||||
/// Flutter API for `NSUrlAuthenticationChallenge`.
|
||||
///
|
||||
/// This class may handle instantiating and adding Dart instances that are
|
||||
/// attached to a native instance or receiving callback methods from an
|
||||
/// overridden native class.
|
||||
///
|
||||
/// See
|
||||
/// https://developer.apple.com/documentation/foundation/nsurlauthenticationchallenge?language=objc.
|
||||
@interface FWFNSUrlAuthenticationChallengeFlutterApi : NSObject
|
||||
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger;
|
||||
/// Create a new Dart instance and add it to the `InstanceManager`.
|
||||
- (void)createWithIdentifier:(NSInteger)identifier
|
||||
protectionSpaceIdentifier:(NSInteger)protectionSpaceIdentifier
|
||||
completion:(void (^)(FlutterError *_Nullable))completion;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
@ -164,6 +164,31 @@
|
||||
}
|
||||
@end
|
||||
|
||||
/// Responses to an authentication challenge.
|
||||
///
|
||||
/// See
|
||||
/// https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition?language=objc.
|
||||
@implementation FWFNSUrlSessionAuthChallengeDispositionBox
|
||||
- (instancetype)initWithValue:(FWFNSUrlSessionAuthChallengeDisposition)value {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_value = value;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
/// Specifies how long a credential will be kept.
|
||||
@implementation FWFNSUrlCredentialPersistenceBox
|
||||
- (instancetype)initWithValue:(FWFNSUrlCredentialPersistence)value {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_value = value;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
static NSArray *wrapResult(id result, FlutterError *error) {
|
||||
if (error) {
|
||||
return @[
|
||||
@ -285,6 +310,12 @@ static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) {
|
||||
- (NSArray *)toList;
|
||||
@end
|
||||
|
||||
@interface FWFAuthenticationChallengeResponse ()
|
||||
+ (FWFAuthenticationChallengeResponse *)fromList:(NSArray *)list;
|
||||
+ (nullable FWFAuthenticationChallengeResponse *)nullableFromList:(NSArray *)list;
|
||||
- (NSArray *)toList;
|
||||
@end
|
||||
|
||||
@implementation FWFNSKeyValueObservingOptionsEnumData
|
||||
+ (instancetype)makeWithValue:(FWFNSKeyValueObservingOptionsEnum)value {
|
||||
FWFNSKeyValueObservingOptionsEnumData *pigeonResult =
|
||||
@ -727,6 +758,33 @@ static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) {
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation FWFAuthenticationChallengeResponse
|
||||
+ (instancetype)makeWithDisposition:(FWFNSUrlSessionAuthChallengeDisposition)disposition
|
||||
credentialIdentifier:(nullable NSNumber *)credentialIdentifier {
|
||||
FWFAuthenticationChallengeResponse *pigeonResult =
|
||||
[[FWFAuthenticationChallengeResponse alloc] init];
|
||||
pigeonResult.disposition = disposition;
|
||||
pigeonResult.credentialIdentifier = credentialIdentifier;
|
||||
return pigeonResult;
|
||||
}
|
||||
+ (FWFAuthenticationChallengeResponse *)fromList:(NSArray *)list {
|
||||
FWFAuthenticationChallengeResponse *pigeonResult =
|
||||
[[FWFAuthenticationChallengeResponse alloc] init];
|
||||
pigeonResult.disposition = [GetNullableObjectAtIndex(list, 0) integerValue];
|
||||
pigeonResult.credentialIdentifier = GetNullableObjectAtIndex(list, 1);
|
||||
return pigeonResult;
|
||||
}
|
||||
+ (nullable FWFAuthenticationChallengeResponse *)nullableFromList:(NSArray *)list {
|
||||
return (list) ? [FWFAuthenticationChallengeResponse fromList:list] : nil;
|
||||
}
|
||||
- (NSArray *)toList {
|
||||
return @[
|
||||
@(self.disposition),
|
||||
self.credentialIdentifier ?: [NSNull null],
|
||||
];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface FWFWKWebsiteDataStoreHostApiCodecReader : FlutterStandardReader
|
||||
@end
|
||||
@implementation FWFWKWebsiteDataStoreHostApiCodecReader
|
||||
@ -1684,14 +1742,16 @@ void SetUpFWFWKNavigationDelegateHostApi(id<FlutterBinaryMessenger> binaryMessen
|
||||
- (nullable id)readValueOfType:(UInt8)type {
|
||||
switch (type) {
|
||||
case 128:
|
||||
return [FWFNSErrorData fromList:[self readValue]];
|
||||
return [FWFAuthenticationChallengeResponse fromList:[self readValue]];
|
||||
case 129:
|
||||
return [FWFNSUrlRequestData fromList:[self readValue]];
|
||||
return [FWFNSErrorData fromList:[self readValue]];
|
||||
case 130:
|
||||
return [FWFWKFrameInfoData fromList:[self readValue]];
|
||||
return [FWFNSUrlRequestData fromList:[self readValue]];
|
||||
case 131:
|
||||
return [FWFWKNavigationActionData fromList:[self readValue]];
|
||||
return [FWFWKFrameInfoData fromList:[self readValue]];
|
||||
case 132:
|
||||
return [FWFWKNavigationActionData fromList:[self readValue]];
|
||||
case 133:
|
||||
return [FWFWKNavigationActionPolicyEnumData fromList:[self readValue]];
|
||||
default:
|
||||
return [super readValueOfType:type];
|
||||
@ -1703,21 +1763,24 @@ void SetUpFWFWKNavigationDelegateHostApi(id<FlutterBinaryMessenger> binaryMessen
|
||||
@end
|
||||
@implementation FWFWKNavigationDelegateFlutterApiCodecWriter
|
||||
- (void)writeValue:(id)value {
|
||||
if ([value isKindOfClass:[FWFNSErrorData class]]) {
|
||||
if ([value isKindOfClass:[FWFAuthenticationChallengeResponse class]]) {
|
||||
[self writeByte:128];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFNSErrorData class]]) {
|
||||
[self writeByte:129];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) {
|
||||
[self writeByte:130];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) {
|
||||
[self writeByte:131];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) {
|
||||
[self writeByte:132];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) {
|
||||
[self writeByte:133];
|
||||
[self writeValue:[value toList]];
|
||||
} else {
|
||||
[super writeValue:value];
|
||||
}
|
||||
@ -1934,6 +1997,40 @@ NSObject<FlutterMessageCodec> *FWFWKNavigationDelegateFlutterApiGetCodec(void) {
|
||||
}
|
||||
}];
|
||||
}
|
||||
- (void)
|
||||
didReceiveAuthenticationChallengeForDelegateWithIdentifier:(NSInteger)arg_identifier
|
||||
webViewIdentifier:(NSInteger)arg_webViewIdentifier
|
||||
challengeIdentifier:(NSInteger)arg_challengeIdentifier
|
||||
completion:
|
||||
(void (^)(FWFAuthenticationChallengeResponse
|
||||
*_Nullable,
|
||||
FlutterError *_Nullable))
|
||||
completion {
|
||||
FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
|
||||
messageChannelWithName:@"dev.flutter.pigeon.webview_flutter_wkwebview."
|
||||
@"WKNavigationDelegateFlutterApi.didReceiveAuthenticationChallenge"
|
||||
binaryMessenger:self.binaryMessenger
|
||||
codec:FWFWKNavigationDelegateFlutterApiGetCodec()];
|
||||
[channel sendMessage:@[ @(arg_identifier), @(arg_webViewIdentifier), @(arg_challengeIdentifier) ]
|
||||
reply:^(NSArray<id> *reply) {
|
||||
if (reply != nil) {
|
||||
if (reply.count > 1) {
|
||||
completion(nil, [FlutterError errorWithCode:reply[0]
|
||||
message:reply[1]
|
||||
details:reply[2]]);
|
||||
} else {
|
||||
FWFAuthenticationChallengeResponse *output =
|
||||
reply[0] == [NSNull null] ? nil : reply[0];
|
||||
completion(output, nil);
|
||||
}
|
||||
} else {
|
||||
completion(nil, [FlutterError
|
||||
errorWithCode:@"channel-error"
|
||||
message:@"Unable to establish connection on channel."
|
||||
details:@""]);
|
||||
}
|
||||
}];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface FWFNSObjectHostApiCodecReader : FlutterStandardReader
|
||||
@ -2201,40 +2298,42 @@ NSObject<FlutterMessageCodec> *FWFNSObjectFlutterApiGetCodec(void) {
|
||||
- (nullable id)readValueOfType:(UInt8)type {
|
||||
switch (type) {
|
||||
case 128:
|
||||
return [FWFNSErrorData fromList:[self readValue]];
|
||||
return [FWFAuthenticationChallengeResponse fromList:[self readValue]];
|
||||
case 129:
|
||||
return [FWFNSHttpCookieData fromList:[self readValue]];
|
||||
return [FWFNSErrorData fromList:[self readValue]];
|
||||
case 130:
|
||||
return [FWFNSHttpCookiePropertyKeyEnumData fromList:[self readValue]];
|
||||
return [FWFNSHttpCookieData fromList:[self readValue]];
|
||||
case 131:
|
||||
return [FWFNSKeyValueChangeKeyEnumData fromList:[self readValue]];
|
||||
return [FWFNSHttpCookiePropertyKeyEnumData fromList:[self readValue]];
|
||||
case 132:
|
||||
return [FWFNSKeyValueObservingOptionsEnumData fromList:[self readValue]];
|
||||
return [FWFNSKeyValueChangeKeyEnumData fromList:[self readValue]];
|
||||
case 133:
|
||||
return [FWFNSUrlRequestData fromList:[self readValue]];
|
||||
return [FWFNSKeyValueObservingOptionsEnumData fromList:[self readValue]];
|
||||
case 134:
|
||||
return [FWFObjectOrIdentifier fromList:[self readValue]];
|
||||
return [FWFNSUrlRequestData fromList:[self readValue]];
|
||||
case 135:
|
||||
return [FWFWKAudiovisualMediaTypeEnumData fromList:[self readValue]];
|
||||
return [FWFObjectOrIdentifier fromList:[self readValue]];
|
||||
case 136:
|
||||
return [FWFWKFrameInfoData fromList:[self readValue]];
|
||||
return [FWFWKAudiovisualMediaTypeEnumData fromList:[self readValue]];
|
||||
case 137:
|
||||
return [FWFWKMediaCaptureTypeData fromList:[self readValue]];
|
||||
return [FWFWKFrameInfoData fromList:[self readValue]];
|
||||
case 138:
|
||||
return [FWFWKNavigationActionData fromList:[self readValue]];
|
||||
return [FWFWKMediaCaptureTypeData fromList:[self readValue]];
|
||||
case 139:
|
||||
return [FWFWKNavigationActionPolicyEnumData fromList:[self readValue]];
|
||||
return [FWFWKNavigationActionData fromList:[self readValue]];
|
||||
case 140:
|
||||
return [FWFWKPermissionDecisionData fromList:[self readValue]];
|
||||
return [FWFWKNavigationActionPolicyEnumData fromList:[self readValue]];
|
||||
case 141:
|
||||
return [FWFWKScriptMessageData fromList:[self readValue]];
|
||||
return [FWFWKPermissionDecisionData fromList:[self readValue]];
|
||||
case 142:
|
||||
return [FWFWKSecurityOriginData fromList:[self readValue]];
|
||||
return [FWFWKScriptMessageData fromList:[self readValue]];
|
||||
case 143:
|
||||
return [FWFWKUserScriptData fromList:[self readValue]];
|
||||
return [FWFWKSecurityOriginData fromList:[self readValue]];
|
||||
case 144:
|
||||
return [FWFWKUserScriptInjectionTimeEnumData fromList:[self readValue]];
|
||||
return [FWFWKUserScriptData fromList:[self readValue]];
|
||||
case 145:
|
||||
return [FWFWKUserScriptInjectionTimeEnumData fromList:[self readValue]];
|
||||
case 146:
|
||||
return [FWFWKWebsiteDataTypeEnumData fromList:[self readValue]];
|
||||
default:
|
||||
return [super readValueOfType:type];
|
||||
@ -2246,60 +2345,63 @@ NSObject<FlutterMessageCodec> *FWFNSObjectFlutterApiGetCodec(void) {
|
||||
@end
|
||||
@implementation FWFWKWebViewHostApiCodecWriter
|
||||
- (void)writeValue:(id)value {
|
||||
if ([value isKindOfClass:[FWFNSErrorData class]]) {
|
||||
if ([value isKindOfClass:[FWFAuthenticationChallengeResponse class]]) {
|
||||
[self writeByte:128];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFNSHttpCookieData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFNSErrorData class]]) {
|
||||
[self writeByte:129];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFNSHttpCookiePropertyKeyEnumData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFNSHttpCookieData class]]) {
|
||||
[self writeByte:130];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFNSKeyValueChangeKeyEnumData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFNSHttpCookiePropertyKeyEnumData class]]) {
|
||||
[self writeByte:131];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFNSKeyValueObservingOptionsEnumData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFNSKeyValueChangeKeyEnumData class]]) {
|
||||
[self writeByte:132];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFNSKeyValueObservingOptionsEnumData class]]) {
|
||||
[self writeByte:133];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFObjectOrIdentifier class]]) {
|
||||
} else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) {
|
||||
[self writeByte:134];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKAudiovisualMediaTypeEnumData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFObjectOrIdentifier class]]) {
|
||||
[self writeByte:135];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFWKAudiovisualMediaTypeEnumData class]]) {
|
||||
[self writeByte:136];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKMediaCaptureTypeData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) {
|
||||
[self writeByte:137];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFWKMediaCaptureTypeData class]]) {
|
||||
[self writeByte:138];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) {
|
||||
[self writeByte:139];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKPermissionDecisionData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) {
|
||||
[self writeByte:140];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKScriptMessageData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFWKPermissionDecisionData class]]) {
|
||||
[self writeByte:141];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKSecurityOriginData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFWKScriptMessageData class]]) {
|
||||
[self writeByte:142];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKUserScriptData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFWKSecurityOriginData class]]) {
|
||||
[self writeByte:143];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKUserScriptInjectionTimeEnumData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFWKUserScriptData class]]) {
|
||||
[self writeByte:144];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKWebsiteDataTypeEnumData class]]) {
|
||||
} else if ([value isKindOfClass:[FWFWKUserScriptInjectionTimeEnumData class]]) {
|
||||
[self writeByte:145];
|
||||
[self writeValue:[value toList]];
|
||||
} else if ([value isKindOfClass:[FWFWKWebsiteDataTypeEnumData class]]) {
|
||||
[self writeByte:146];
|
||||
[self writeValue:[value toList]];
|
||||
} else {
|
||||
[super writeValue:value];
|
||||
}
|
||||
@ -3181,3 +3283,143 @@ NSObject<FlutterMessageCodec> *FWFNSUrlFlutterApiGetCodec(void) {
|
||||
}];
|
||||
}
|
||||
@end
|
||||
|
||||
NSObject<FlutterMessageCodec> *FWFNSUrlCredentialHostApiGetCodec(void) {
|
||||
static FlutterStandardMessageCodec *sSharedObject = nil;
|
||||
sSharedObject = [FlutterStandardMessageCodec sharedInstance];
|
||||
return sSharedObject;
|
||||
}
|
||||
|
||||
void SetUpFWFNSUrlCredentialHostApi(id<FlutterBinaryMessenger> binaryMessenger,
|
||||
NSObject<FWFNSUrlCredentialHostApi> *api) {
|
||||
/// Create a new native instance and add it to the `InstanceManager`.
|
||||
{
|
||||
FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
|
||||
initWithName:
|
||||
@"dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser"
|
||||
binaryMessenger:binaryMessenger
|
||||
codec:FWFNSUrlCredentialHostApiGetCodec()];
|
||||
if (api) {
|
||||
NSCAssert([api respondsToSelector:@selector
|
||||
(createWithUserWithIdentifier:user:password:persistence:error:)],
|
||||
@"FWFNSUrlCredentialHostApi api (%@) doesn't respond to "
|
||||
@"@selector(createWithUserWithIdentifier:user:password:persistence:error:)",
|
||||
api);
|
||||
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
|
||||
NSArray *args = message;
|
||||
NSInteger arg_identifier = [GetNullableObjectAtIndex(args, 0) integerValue];
|
||||
NSString *arg_user = GetNullableObjectAtIndex(args, 1);
|
||||
NSString *arg_password = GetNullableObjectAtIndex(args, 2);
|
||||
FWFNSUrlCredentialPersistence arg_persistence =
|
||||
[GetNullableObjectAtIndex(args, 3) integerValue];
|
||||
FlutterError *error;
|
||||
[api createWithUserWithIdentifier:arg_identifier
|
||||
user:arg_user
|
||||
password:arg_password
|
||||
persistence:arg_persistence
|
||||
error:&error];
|
||||
callback(wrapResult(nil, error));
|
||||
}];
|
||||
} else {
|
||||
[channel setMessageHandler:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
NSObject<FlutterMessageCodec> *FWFNSUrlProtectionSpaceFlutterApiGetCodec(void) {
|
||||
static FlutterStandardMessageCodec *sSharedObject = nil;
|
||||
sSharedObject = [FlutterStandardMessageCodec sharedInstance];
|
||||
return sSharedObject;
|
||||
}
|
||||
|
||||
@interface FWFNSUrlProtectionSpaceFlutterApi ()
|
||||
@property(nonatomic, strong) NSObject<FlutterBinaryMessenger> *binaryMessenger;
|
||||
@end
|
||||
|
||||
@implementation FWFNSUrlProtectionSpaceFlutterApi
|
||||
|
||||
- (instancetype)initWithBinaryMessenger:(NSObject<FlutterBinaryMessenger> *)binaryMessenger {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_binaryMessenger = binaryMessenger;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)createWithIdentifier:(NSInteger)arg_identifier
|
||||
host:(nullable NSString *)arg_host
|
||||
realm:(nullable NSString *)arg_realm
|
||||
authenticationMethod:(nullable NSString *)arg_authenticationMethod
|
||||
completion:(void (^)(FlutterError *_Nullable))completion {
|
||||
FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
|
||||
messageChannelWithName:
|
||||
@"dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlProtectionSpaceFlutterApi.create"
|
||||
binaryMessenger:self.binaryMessenger
|
||||
codec:FWFNSUrlProtectionSpaceFlutterApiGetCodec()];
|
||||
[channel
|
||||
sendMessage:@[
|
||||
@(arg_identifier), arg_host ?: [NSNull null], arg_realm ?: [NSNull null],
|
||||
arg_authenticationMethod ?: [NSNull null]
|
||||
]
|
||||
reply:^(NSArray<id> *reply) {
|
||||
if (reply != nil) {
|
||||
if (reply.count > 1) {
|
||||
completion([FlutterError errorWithCode:reply[0]
|
||||
message:reply[1]
|
||||
details:reply[2]]);
|
||||
} else {
|
||||
completion(nil);
|
||||
}
|
||||
} else {
|
||||
completion([FlutterError errorWithCode:@"channel-error"
|
||||
message:@"Unable to establish connection on channel."
|
||||
details:@""]);
|
||||
}
|
||||
}];
|
||||
}
|
||||
@end
|
||||
|
||||
NSObject<FlutterMessageCodec> *FWFNSUrlAuthenticationChallengeFlutterApiGetCodec(void) {
|
||||
static FlutterStandardMessageCodec *sSharedObject = nil;
|
||||
sSharedObject = [FlutterStandardMessageCodec sharedInstance];
|
||||
return sSharedObject;
|
||||
}
|
||||
|
||||
@interface FWFNSUrlAuthenticationChallengeFlutterApi ()
|
||||
@property(nonatomic, strong) NSObject<FlutterBinaryMessenger> *binaryMessenger;
|
||||
@end
|
||||
|
||||
@implementation FWFNSUrlAuthenticationChallengeFlutterApi
|
||||
|
||||
- (instancetype)initWithBinaryMessenger:(NSObject<FlutterBinaryMessenger> *)binaryMessenger {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_binaryMessenger = binaryMessenger;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)createWithIdentifier:(NSInteger)arg_identifier
|
||||
protectionSpaceIdentifier:(NSInteger)arg_protectionSpaceIdentifier
|
||||
completion:(void (^)(FlutterError *_Nullable))completion {
|
||||
FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
|
||||
messageChannelWithName:@"dev.flutter.pigeon.webview_flutter_wkwebview."
|
||||
@"NSUrlAuthenticationChallengeFlutterApi.create"
|
||||
binaryMessenger:self.binaryMessenger
|
||||
codec:FWFNSUrlAuthenticationChallengeFlutterApiGetCodec()];
|
||||
[channel
|
||||
sendMessage:@[ @(arg_identifier), @(arg_protectionSpaceIdentifier) ]
|
||||
reply:^(NSArray<id> *reply) {
|
||||
if (reply != nil) {
|
||||
if (reply.count > 1) {
|
||||
completion([FlutterError errorWithCode:reply[0]
|
||||
message:reply[1]
|
||||
details:reply[2]]);
|
||||
} else {
|
||||
completion(nil);
|
||||
}
|
||||
} else {
|
||||
completion([FlutterError errorWithCode:@"channel-error"
|
||||
message:@"Unable to establish connection on channel."
|
||||
details:@""]);
|
||||
}
|
||||
}];
|
||||
}
|
||||
@end
|
||||
|
@ -4,9 +4,13 @@
|
||||
|
||||
#import "FWFNavigationDelegateHostApi.h"
|
||||
#import "FWFDataConverters.h"
|
||||
#import "FWFURLAuthenticationChallengeHostApi.h"
|
||||
#import "FWFWebViewConfigurationHostApi.h"
|
||||
|
||||
@interface FWFNavigationDelegateFlutterApiImpl ()
|
||||
// BinaryMessenger must be weak to prevent a circular reference with the host API it
|
||||
// references.
|
||||
@property(nonatomic, weak) id<FlutterBinaryMessenger> binaryMessenger;
|
||||
// InstanceManager must be weak to prevent a circular reference with the object it stores.
|
||||
@property(nonatomic, weak) FWFInstanceManager *instanceManager;
|
||||
@end
|
||||
@ -16,6 +20,7 @@
|
||||
instanceManager:(FWFInstanceManager *)instanceManager {
|
||||
self = [self initWithBinaryMessenger:binaryMessenger];
|
||||
if (self) {
|
||||
_binaryMessenger = binaryMessenger;
|
||||
_instanceManager = instanceManager;
|
||||
}
|
||||
return self;
|
||||
@ -102,6 +107,37 @@
|
||||
webViewIdentifier:webViewIdentifier
|
||||
completion:completion];
|
||||
}
|
||||
|
||||
- (void)
|
||||
didReceiveAuthenticationChallengeForDelegate:(FWFNavigationDelegate *)instance
|
||||
webView:(WKWebView *)webView
|
||||
challenge:(NSURLAuthenticationChallenge *)challenge
|
||||
completion:
|
||||
(void (^)(FWFAuthenticationChallengeResponse *_Nullable,
|
||||
FlutterError *_Nullable))completion {
|
||||
NSInteger webViewIdentifier =
|
||||
[self.instanceManager identifierWithStrongReferenceForInstance:webView];
|
||||
|
||||
FWFURLAuthenticationChallengeFlutterApiImpl *challengeApi =
|
||||
[[FWFURLAuthenticationChallengeFlutterApiImpl alloc]
|
||||
initWithBinaryMessenger:self.binaryMessenger
|
||||
instanceManager:self.instanceManager];
|
||||
[challengeApi createWithInstance:challenge
|
||||
protectionSpace:challenge.protectionSpace
|
||||
completion:^(FlutterError *error) {
|
||||
NSAssert(!error, @"%@", error);
|
||||
}];
|
||||
|
||||
[self
|
||||
didReceiveAuthenticationChallengeForDelegateWithIdentifier:[self
|
||||
identifierForDelegate:instance]
|
||||
webViewIdentifier:webViewIdentifier
|
||||
challengeIdentifier:
|
||||
[self.instanceManager
|
||||
identifierWithStrongReferenceForInstance:
|
||||
challenge]
|
||||
completion:completion];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation FWFNavigationDelegate
|
||||
@ -144,8 +180,13 @@
|
||||
completion:^(FWFWKNavigationActionPolicyEnumData *policy,
|
||||
FlutterError *error) {
|
||||
NSAssert(!error, @"%@", error);
|
||||
decisionHandler(
|
||||
FWFNativeWKNavigationActionPolicyFromEnumData(policy));
|
||||
if (!error) {
|
||||
decisionHandler(
|
||||
FWFNativeWKNavigationActionPolicyFromEnumData(
|
||||
policy));
|
||||
} else {
|
||||
decisionHandler(WKNavigationActionPolicyCancel);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@ -179,6 +220,40 @@
|
||||
NSAssert(!error, @"%@", error);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)webView:(WKWebView *)webView
|
||||
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
|
||||
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition,
|
||||
NSURLCredential *_Nullable))completionHandler {
|
||||
[self.navigationDelegateAPI
|
||||
didReceiveAuthenticationChallengeForDelegate:self
|
||||
webView:webView
|
||||
challenge:challenge
|
||||
completion:^(FWFAuthenticationChallengeResponse *response,
|
||||
FlutterError *error) {
|
||||
NSAssert(!error, @"%@", error);
|
||||
if (!error) {
|
||||
NSURLSessionAuthChallengeDisposition disposition =
|
||||
FWFNativeNSURLSessionAuthChallengeDispositionFromFWFNSUrlSessionAuthChallengeDisposition(
|
||||
response.disposition);
|
||||
|
||||
NSURLCredential *credential =
|
||||
response.credentialIdentifier
|
||||
? (NSURLCredential *)[self.navigationDelegateAPI
|
||||
.instanceManager
|
||||
instanceForIdentifier:
|
||||
response.credentialIdentifier
|
||||
.longValue]
|
||||
: nil;
|
||||
|
||||
completionHandler(disposition, credential);
|
||||
} else {
|
||||
completionHandler(
|
||||
NSURLSessionAuthChallengeCancelAuthenticationChallenge,
|
||||
nil);
|
||||
}
|
||||
}];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface FWFNavigationDelegateHostApiImpl ()
|
||||
|
@ -0,0 +1,33 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import <Flutter/Flutter.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FWFGeneratedWebKitApis.h"
|
||||
#import "FWFInstanceManager.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* Flutter API implementation for `NSURLAuthenticationChallenge`.
|
||||
*
|
||||
* This class may handle instantiating and adding Dart instances that are attached to a native
|
||||
* instance or sending callback methods from an overridden native class.
|
||||
*/
|
||||
@interface FWFURLAuthenticationChallengeFlutterApiImpl : NSObject
|
||||
/**
|
||||
* The Flutter API used to send messages back to Dart.
|
||||
*/
|
||||
@property FWFNSUrlAuthenticationChallengeFlutterApi *api;
|
||||
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
|
||||
instanceManager:(FWFInstanceManager *)instanceManager;
|
||||
/**
|
||||
* Sends a message to Dart to create a new Dart instance and add it to the `InstanceManager`.
|
||||
*/
|
||||
- (void)createWithInstance:(NSURLAuthenticationChallenge *)instance
|
||||
protectionSpace:(NSURLProtectionSpace *)protectionSpace
|
||||
completion:(void (^)(FlutterError *_Nullable))completion;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,52 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "FWFURLAuthenticationChallengeHostApi.h"
|
||||
#import "FWFURLProtectionSpaceHostApi.h"
|
||||
|
||||
@interface FWFURLAuthenticationChallengeFlutterApiImpl ()
|
||||
// BinaryMessenger must be weak to prevent a circular reference with the host API it
|
||||
// references.
|
||||
@property(nonatomic, weak) id<FlutterBinaryMessenger> binaryMessenger;
|
||||
// InstanceManager must be weak to prevent a circular reference with the object it stores.
|
||||
@property(nonatomic, weak) FWFInstanceManager *instanceManager;
|
||||
@end
|
||||
|
||||
@implementation FWFURLAuthenticationChallengeFlutterApiImpl
|
||||
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
|
||||
instanceManager:(FWFInstanceManager *)instanceManager {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
_binaryMessenger = binaryMessenger;
|
||||
_instanceManager = instanceManager;
|
||||
_api =
|
||||
[[FWFNSUrlAuthenticationChallengeFlutterApi alloc] initWithBinaryMessenger:binaryMessenger];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)createWithInstance:(NSURLAuthenticationChallenge *)instance
|
||||
protectionSpace:(NSURLProtectionSpace *)protectionSpace
|
||||
completion:(void (^)(FlutterError *_Nullable))completion {
|
||||
if ([self.instanceManager containsInstance:instance]) {
|
||||
return;
|
||||
}
|
||||
|
||||
FWFURLProtectionSpaceFlutterApiImpl *protectionSpaceApi =
|
||||
[[FWFURLProtectionSpaceFlutterApiImpl alloc] initWithBinaryMessenger:self.binaryMessenger
|
||||
instanceManager:self.instanceManager];
|
||||
[protectionSpaceApi createWithInstance:protectionSpace
|
||||
host:protectionSpace.host
|
||||
realm:protectionSpace.realm
|
||||
authenticationMethod:protectionSpace.authenticationMethod
|
||||
completion:^(FlutterError *error) {
|
||||
NSAssert(!error, @"%@", error);
|
||||
}];
|
||||
|
||||
[self.api createWithIdentifier:[self.instanceManager addHostCreatedInstance:instance]
|
||||
protectionSpaceIdentifier:[self.instanceManager
|
||||
identifierWithStrongReferenceForInstance:protectionSpace]
|
||||
completion:completion];
|
||||
}
|
||||
@end
|
@ -0,0 +1,24 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import <Flutter/Flutter.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FWFDataConverters.h"
|
||||
#import "FWFGeneratedWebKitApis.h"
|
||||
#import "FWFInstanceManager.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* Host API implementation for `NSURLCredential`.
|
||||
*
|
||||
* This class may handle instantiating and adding native object instances that are attached to a
|
||||
* Dart instance or method calls on the associated native class or an instance of the class.
|
||||
*/
|
||||
@interface FWFURLCredentialHostApiImpl : NSObject <FWFNSUrlCredentialHostApi>
|
||||
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
|
||||
instanceManager:(FWFInstanceManager *)instanceManager;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,58 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "FWFURLCredentialHostApi.h"
|
||||
|
||||
@interface FWFURLCredentialHostApiImpl ()
|
||||
// BinaryMessenger must be weak to prevent a circular reference with the host API it
|
||||
// references.
|
||||
@property(nonatomic, weak) id<FlutterBinaryMessenger> binaryMessenger;
|
||||
// InstanceManager must be weak to prevent a circular reference with the object it stores.
|
||||
@property(nonatomic, weak) FWFInstanceManager *instanceManager;
|
||||
@end
|
||||
|
||||
@implementation FWFURLCredentialHostApiImpl
|
||||
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
|
||||
instanceManager:(FWFInstanceManager *)instanceManager {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
_binaryMessenger = binaryMessenger;
|
||||
_instanceManager = instanceManager;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)createWithUserWithIdentifier:(NSInteger)identifier
|
||||
user:(nonnull NSString *)user
|
||||
password:(nonnull NSString *)password
|
||||
persistence:(FWFNSUrlCredentialPersistence)persistence
|
||||
error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
|
||||
[self.instanceManager
|
||||
addDartCreatedInstance:
|
||||
[NSURLCredential
|
||||
credentialWithUser:user
|
||||
password:password
|
||||
persistence:
|
||||
FWFNativeNSURLCredentialPersistenceFromFWFNSUrlCredentialPersistence(
|
||||
persistence)]
|
||||
withIdentifier:identifier];
|
||||
}
|
||||
|
||||
- (nullable NSURL *)credentialForIdentifier:(NSNumber *)identifier
|
||||
error:
|
||||
(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
|
||||
NSURL *instance = (NSURL *)[self.instanceManager instanceForIdentifier:identifier.longValue];
|
||||
|
||||
if (!instance) {
|
||||
NSString *message =
|
||||
[NSString stringWithFormat:@"InstanceManager does not contain an NSURL with identifier: %@",
|
||||
identifier];
|
||||
*error = [FlutterError errorWithCode:NSInternalInconsistencyException
|
||||
message:message
|
||||
details:nil];
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
@end
|
@ -0,0 +1,35 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import <Flutter/Flutter.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FWFGeneratedWebKitApis.h"
|
||||
#import "FWFInstanceManager.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* Flutter API implementation for `NSURLProtectionSpace`.
|
||||
*
|
||||
* This class may handle instantiating and adding Dart instances that are attached to a native
|
||||
* instance or sending callback methods from an overridden native class.
|
||||
*/
|
||||
@interface FWFURLProtectionSpaceFlutterApiImpl : NSObject
|
||||
/**
|
||||
* The Flutter API used to send messages back to Dart.
|
||||
*/
|
||||
@property FWFNSUrlProtectionSpaceFlutterApi *api;
|
||||
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
|
||||
instanceManager:(FWFInstanceManager *)instanceManager;
|
||||
/**
|
||||
* Sends a message to Dart to create a new Dart instance and add it to the `InstanceManager`.
|
||||
*/
|
||||
- (void)createWithInstance:(NSURLProtectionSpace *)instance
|
||||
host:(nullable NSString *)host
|
||||
realm:(nullable NSString *)realm
|
||||
authenticationMethod:(nullable NSString *)authenticationMethod
|
||||
completion:(void (^)(FlutterError *_Nullable))completion;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,36 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "FWFURLProtectionSpaceHostApi.h"
|
||||
|
||||
@interface FWFURLProtectionSpaceFlutterApiImpl ()
|
||||
// InstanceManager must be weak to prevent a circular reference with the object it stores.
|
||||
@property(nonatomic, weak) FWFInstanceManager *instanceManager;
|
||||
@end
|
||||
|
||||
@implementation FWFURLProtectionSpaceFlutterApiImpl
|
||||
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
|
||||
instanceManager:(FWFInstanceManager *)instanceManager {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
_instanceManager = instanceManager;
|
||||
_api = [[FWFNSUrlProtectionSpaceFlutterApi alloc] initWithBinaryMessenger:binaryMessenger];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)createWithInstance:(NSURLProtectionSpace *)instance
|
||||
host:(nullable NSString *)host
|
||||
realm:(nullable NSString *)realm
|
||||
authenticationMethod:(nullable NSString *)authenticationMethod
|
||||
completion:(void (^)(FlutterError *_Nullable))completion {
|
||||
if (![self.instanceManager containsInstance:instance]) {
|
||||
[self.api createWithIdentifier:[self.instanceManager addHostCreatedInstance:instance]
|
||||
host:host
|
||||
realm:realm
|
||||
authenticationMethod:authenticationMethod
|
||||
completion:completion];
|
||||
}
|
||||
}
|
||||
@end
|
@ -16,7 +16,10 @@
|
||||
#import "FWFScrollViewHostApi.h"
|
||||
#import "FWFUIDelegateHostApi.h"
|
||||
#import "FWFUIViewHostApi.h"
|
||||
#import "FWFURLAuthenticationChallengeHostApi.h"
|
||||
#import "FWFURLCredentialHostApi.h"
|
||||
#import "FWFURLHostApi.h"
|
||||
#import "FWFURLProtectionSpaceHostApi.h"
|
||||
#import "FWFUserContentControllerHostApi.h"
|
||||
#import "FWFWebViewConfigurationHostApi.h"
|
||||
#import "FWFWebViewFlutterWKWebViewExternalAPI.h"
|
||||
|
@ -202,6 +202,58 @@ enum WKMediaCaptureType {
|
||||
unknown,
|
||||
}
|
||||
|
||||
/// Responses to an authentication challenge.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition?language=objc.
|
||||
enum NSUrlSessionAuthChallengeDisposition {
|
||||
/// Use the specified credential, which may be nil.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengeusecredential?language=objc.
|
||||
useCredential,
|
||||
|
||||
/// Use the default handling for the challenge as though this delegate method
|
||||
/// were not implemented.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengeperformdefaulthandling?language=objc.
|
||||
performDefaultHandling,
|
||||
|
||||
/// Cancel the entire request.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengecancelauthenticationchallenge?language=objc.
|
||||
cancelAuthenticationChallenge,
|
||||
|
||||
/// Reject this challenge, and call the authentication delegate method again
|
||||
/// with the next authentication protection space.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengerejectprotectionspace?language=objc.
|
||||
rejectProtectionSpace,
|
||||
}
|
||||
|
||||
/// Specifies how long a credential will be kept.
|
||||
enum NSUrlCredentialPersistence {
|
||||
/// The credential should not be stored.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencenone?language=objc.
|
||||
none,
|
||||
|
||||
/// The credential should be stored only for this session.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistenceforsession?language=objc.
|
||||
session,
|
||||
|
||||
/// The credential should be stored in the keychain.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencepermanent?language=objc.
|
||||
permanent,
|
||||
|
||||
/// The credential should be stored permanently in the keychain, and in
|
||||
/// addition should be distributed to other devices based on the owning Apple
|
||||
/// ID.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencesynchronizable?language=objc.
|
||||
synchronizable,
|
||||
}
|
||||
|
||||
class NSKeyValueObservingOptionsEnumData {
|
||||
NSKeyValueObservingOptionsEnumData({
|
||||
required this.value,
|
||||
@ -684,6 +736,33 @@ class ObjectOrIdentifier {
|
||||
}
|
||||
}
|
||||
|
||||
class AuthenticationChallengeResponse {
|
||||
AuthenticationChallengeResponse({
|
||||
required this.disposition,
|
||||
this.credentialIdentifier,
|
||||
});
|
||||
|
||||
NSUrlSessionAuthChallengeDisposition disposition;
|
||||
|
||||
int? credentialIdentifier;
|
||||
|
||||
Object encode() {
|
||||
return <Object?>[
|
||||
disposition.index,
|
||||
credentialIdentifier,
|
||||
];
|
||||
}
|
||||
|
||||
static AuthenticationChallengeResponse decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return AuthenticationChallengeResponse(
|
||||
disposition:
|
||||
NSUrlSessionAuthChallengeDisposition.values[result[0]! as int],
|
||||
credentialIdentifier: result[1] as int?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _WKWebsiteDataStoreHostApiCodec extends StandardMessageCodec {
|
||||
const _WKWebsiteDataStoreHostApiCodec();
|
||||
@override
|
||||
@ -1576,21 +1655,24 @@ class _WKNavigationDelegateFlutterApiCodec extends StandardMessageCodec {
|
||||
const _WKNavigationDelegateFlutterApiCodec();
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is NSErrorData) {
|
||||
if (value is AuthenticationChallengeResponse) {
|
||||
buffer.putUint8(128);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NSUrlRequestData) {
|
||||
} else if (value is NSErrorData) {
|
||||
buffer.putUint8(129);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKFrameInfoData) {
|
||||
} else if (value is NSUrlRequestData) {
|
||||
buffer.putUint8(130);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKNavigationActionData) {
|
||||
} else if (value is WKFrameInfoData) {
|
||||
buffer.putUint8(131);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKNavigationActionPolicyEnumData) {
|
||||
} else if (value is WKNavigationActionData) {
|
||||
buffer.putUint8(132);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKNavigationActionPolicyEnumData) {
|
||||
buffer.putUint8(133);
|
||||
writeValue(buffer, value.encode());
|
||||
} else {
|
||||
super.writeValue(buffer, value);
|
||||
}
|
||||
@ -1600,14 +1682,16 @@ class _WKNavigationDelegateFlutterApiCodec extends StandardMessageCodec {
|
||||
Object? readValueOfType(int type, ReadBuffer buffer) {
|
||||
switch (type) {
|
||||
case 128:
|
||||
return NSErrorData.decode(readValue(buffer)!);
|
||||
return AuthenticationChallengeResponse.decode(readValue(buffer)!);
|
||||
case 129:
|
||||
return NSUrlRequestData.decode(readValue(buffer)!);
|
||||
return NSErrorData.decode(readValue(buffer)!);
|
||||
case 130:
|
||||
return WKFrameInfoData.decode(readValue(buffer)!);
|
||||
return NSUrlRequestData.decode(readValue(buffer)!);
|
||||
case 131:
|
||||
return WKNavigationActionData.decode(readValue(buffer)!);
|
||||
return WKFrameInfoData.decode(readValue(buffer)!);
|
||||
case 132:
|
||||
return WKNavigationActionData.decode(readValue(buffer)!);
|
||||
case 133:
|
||||
return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
|
||||
default:
|
||||
return super.readValueOfType(type, buffer);
|
||||
@ -1641,6 +1725,9 @@ abstract class WKNavigationDelegateFlutterApi {
|
||||
void webViewWebContentProcessDidTerminate(
|
||||
int identifier, int webViewIdentifier);
|
||||
|
||||
Future<AuthenticationChallengeResponse> didReceiveAuthenticationChallenge(
|
||||
int identifier, int webViewIdentifier, int challengeIdentifier);
|
||||
|
||||
static void setup(WKNavigationDelegateFlutterApi? api,
|
||||
{BinaryMessenger? binaryMessenger}) {
|
||||
{
|
||||
@ -1842,6 +1929,41 @@ abstract class WKNavigationDelegateFlutterApi {
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.webview_flutter_wkwebview.WKNavigationDelegateFlutterApi.didReceiveAuthenticationChallenge',
|
||||
codec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
channel.setMessageHandler(null);
|
||||
} else {
|
||||
channel.setMessageHandler((Object? message) async {
|
||||
assert(message != null,
|
||||
'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKNavigationDelegateFlutterApi.didReceiveAuthenticationChallenge 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.webview_flutter_wkwebview.WKNavigationDelegateFlutterApi.didReceiveAuthenticationChallenge was null, expected non-null int.');
|
||||
final int? arg_webViewIdentifier = (args[1] as int?);
|
||||
assert(arg_webViewIdentifier != null,
|
||||
'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKNavigationDelegateFlutterApi.didReceiveAuthenticationChallenge was null, expected non-null int.');
|
||||
final int? arg_challengeIdentifier = (args[2] as int?);
|
||||
assert(arg_challengeIdentifier != null,
|
||||
'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKNavigationDelegateFlutterApi.didReceiveAuthenticationChallenge was null, expected non-null int.');
|
||||
try {
|
||||
final AuthenticationChallengeResponse output =
|
||||
await api.didReceiveAuthenticationChallenge(arg_identifier!,
|
||||
arg_webViewIdentifier!, arg_challengeIdentifier!);
|
||||
return wrapResponse(result: output);
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: e);
|
||||
} catch (e) {
|
||||
return wrapResponse(
|
||||
error: PlatformException(code: 'error', message: e.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2082,60 +2204,63 @@ class _WKWebViewHostApiCodec extends StandardMessageCodec {
|
||||
const _WKWebViewHostApiCodec();
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is NSErrorData) {
|
||||
if (value is AuthenticationChallengeResponse) {
|
||||
buffer.putUint8(128);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NSHttpCookieData) {
|
||||
} else if (value is NSErrorData) {
|
||||
buffer.putUint8(129);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NSHttpCookiePropertyKeyEnumData) {
|
||||
} else if (value is NSHttpCookieData) {
|
||||
buffer.putUint8(130);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NSKeyValueChangeKeyEnumData) {
|
||||
} else if (value is NSHttpCookiePropertyKeyEnumData) {
|
||||
buffer.putUint8(131);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NSKeyValueObservingOptionsEnumData) {
|
||||
} else if (value is NSKeyValueChangeKeyEnumData) {
|
||||
buffer.putUint8(132);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NSUrlRequestData) {
|
||||
} else if (value is NSKeyValueObservingOptionsEnumData) {
|
||||
buffer.putUint8(133);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is ObjectOrIdentifier) {
|
||||
} else if (value is NSUrlRequestData) {
|
||||
buffer.putUint8(134);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKAudiovisualMediaTypeEnumData) {
|
||||
} else if (value is ObjectOrIdentifier) {
|
||||
buffer.putUint8(135);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKFrameInfoData) {
|
||||
} else if (value is WKAudiovisualMediaTypeEnumData) {
|
||||
buffer.putUint8(136);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKMediaCaptureTypeData) {
|
||||
} else if (value is WKFrameInfoData) {
|
||||
buffer.putUint8(137);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKNavigationActionData) {
|
||||
} else if (value is WKMediaCaptureTypeData) {
|
||||
buffer.putUint8(138);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKNavigationActionPolicyEnumData) {
|
||||
} else if (value is WKNavigationActionData) {
|
||||
buffer.putUint8(139);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKPermissionDecisionData) {
|
||||
} else if (value is WKNavigationActionPolicyEnumData) {
|
||||
buffer.putUint8(140);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKScriptMessageData) {
|
||||
} else if (value is WKPermissionDecisionData) {
|
||||
buffer.putUint8(141);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKSecurityOriginData) {
|
||||
} else if (value is WKScriptMessageData) {
|
||||
buffer.putUint8(142);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKUserScriptData) {
|
||||
} else if (value is WKSecurityOriginData) {
|
||||
buffer.putUint8(143);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKUserScriptInjectionTimeEnumData) {
|
||||
} else if (value is WKUserScriptData) {
|
||||
buffer.putUint8(144);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKWebsiteDataTypeEnumData) {
|
||||
} else if (value is WKUserScriptInjectionTimeEnumData) {
|
||||
buffer.putUint8(145);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKWebsiteDataTypeEnumData) {
|
||||
buffer.putUint8(146);
|
||||
writeValue(buffer, value.encode());
|
||||
} else {
|
||||
super.writeValue(buffer, value);
|
||||
}
|
||||
@ -2145,40 +2270,42 @@ class _WKWebViewHostApiCodec extends StandardMessageCodec {
|
||||
Object? readValueOfType(int type, ReadBuffer buffer) {
|
||||
switch (type) {
|
||||
case 128:
|
||||
return NSErrorData.decode(readValue(buffer)!);
|
||||
return AuthenticationChallengeResponse.decode(readValue(buffer)!);
|
||||
case 129:
|
||||
return NSHttpCookieData.decode(readValue(buffer)!);
|
||||
return NSErrorData.decode(readValue(buffer)!);
|
||||
case 130:
|
||||
return NSHttpCookiePropertyKeyEnumData.decode(readValue(buffer)!);
|
||||
return NSHttpCookieData.decode(readValue(buffer)!);
|
||||
case 131:
|
||||
return NSKeyValueChangeKeyEnumData.decode(readValue(buffer)!);
|
||||
return NSHttpCookiePropertyKeyEnumData.decode(readValue(buffer)!);
|
||||
case 132:
|
||||
return NSKeyValueObservingOptionsEnumData.decode(readValue(buffer)!);
|
||||
return NSKeyValueChangeKeyEnumData.decode(readValue(buffer)!);
|
||||
case 133:
|
||||
return NSUrlRequestData.decode(readValue(buffer)!);
|
||||
return NSKeyValueObservingOptionsEnumData.decode(readValue(buffer)!);
|
||||
case 134:
|
||||
return ObjectOrIdentifier.decode(readValue(buffer)!);
|
||||
return NSUrlRequestData.decode(readValue(buffer)!);
|
||||
case 135:
|
||||
return WKAudiovisualMediaTypeEnumData.decode(readValue(buffer)!);
|
||||
return ObjectOrIdentifier.decode(readValue(buffer)!);
|
||||
case 136:
|
||||
return WKFrameInfoData.decode(readValue(buffer)!);
|
||||
return WKAudiovisualMediaTypeEnumData.decode(readValue(buffer)!);
|
||||
case 137:
|
||||
return WKMediaCaptureTypeData.decode(readValue(buffer)!);
|
||||
return WKFrameInfoData.decode(readValue(buffer)!);
|
||||
case 138:
|
||||
return WKNavigationActionData.decode(readValue(buffer)!);
|
||||
return WKMediaCaptureTypeData.decode(readValue(buffer)!);
|
||||
case 139:
|
||||
return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
|
||||
return WKNavigationActionData.decode(readValue(buffer)!);
|
||||
case 140:
|
||||
return WKPermissionDecisionData.decode(readValue(buffer)!);
|
||||
return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
|
||||
case 141:
|
||||
return WKScriptMessageData.decode(readValue(buffer)!);
|
||||
return WKPermissionDecisionData.decode(readValue(buffer)!);
|
||||
case 142:
|
||||
return WKSecurityOriginData.decode(readValue(buffer)!);
|
||||
return WKScriptMessageData.decode(readValue(buffer)!);
|
||||
case 143:
|
||||
return WKUserScriptData.decode(readValue(buffer)!);
|
||||
return WKSecurityOriginData.decode(readValue(buffer)!);
|
||||
case 144:
|
||||
return WKUserScriptInjectionTimeEnumData.decode(readValue(buffer)!);
|
||||
return WKUserScriptData.decode(readValue(buffer)!);
|
||||
case 145:
|
||||
return WKUserScriptInjectionTimeEnumData.decode(readValue(buffer)!);
|
||||
case 146:
|
||||
return WKWebsiteDataTypeEnumData.decode(readValue(buffer)!);
|
||||
default:
|
||||
return super.readValueOfType(type, buffer);
|
||||
@ -3052,3 +3179,148 @@ abstract class NSUrlFlutterApi {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Host API for `NSUrlCredential`.
|
||||
///
|
||||
/// This class may handle instantiating and adding native object instances that
|
||||
/// are attached to a Dart instance or handle method calls on the associated
|
||||
/// native class or an instance of the class.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlcredential?language=objc.
|
||||
class NSUrlCredentialHostApi {
|
||||
/// Constructor for [NSUrlCredentialHostApi]. The [binaryMessenger] named argument is
|
||||
/// available for dependency injection. If it is left null, the default
|
||||
/// BinaryMessenger will be used which routes to the host platform.
|
||||
NSUrlCredentialHostApi({BinaryMessenger? binaryMessenger})
|
||||
: _binaryMessenger = binaryMessenger;
|
||||
final BinaryMessenger? _binaryMessenger;
|
||||
|
||||
static const MessageCodec<Object?> codec = StandardMessageCodec();
|
||||
|
||||
/// Create a new native instance and add it to the `InstanceManager`.
|
||||
Future<void> createWithUser(int arg_identifier, String arg_user,
|
||||
String arg_password, NSUrlCredentialPersistence arg_persistence) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser',
|
||||
codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList = await channel.send(<Object?>[
|
||||
arg_identifier,
|
||||
arg_user,
|
||||
arg_password,
|
||||
arg_persistence.index
|
||||
]) 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Flutter API for `NSUrlProtectionSpace`.
|
||||
///
|
||||
/// This class may handle instantiating and adding Dart instances that are
|
||||
/// attached to a native instance or receiving callback methods from an
|
||||
/// overridden native class.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlprotectionspace?language=objc.
|
||||
abstract class NSUrlProtectionSpaceFlutterApi {
|
||||
static const MessageCodec<Object?> codec = StandardMessageCodec();
|
||||
|
||||
/// Create a new Dart instance and add it to the `InstanceManager`.
|
||||
void create(int identifier, String? host, String? realm,
|
||||
String? authenticationMethod);
|
||||
|
||||
static void setup(NSUrlProtectionSpaceFlutterApi? api,
|
||||
{BinaryMessenger? binaryMessenger}) {
|
||||
{
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlProtectionSpaceFlutterApi.create',
|
||||
codec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
channel.setMessageHandler(null);
|
||||
} else {
|
||||
channel.setMessageHandler((Object? message) async {
|
||||
assert(message != null,
|
||||
'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlProtectionSpaceFlutterApi.create 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.webview_flutter_wkwebview.NSUrlProtectionSpaceFlutterApi.create was null, expected non-null int.');
|
||||
final String? arg_host = (args[1] as String?);
|
||||
final String? arg_realm = (args[2] as String?);
|
||||
final String? arg_authenticationMethod = (args[3] as String?);
|
||||
try {
|
||||
api.create(
|
||||
arg_identifier!, arg_host, arg_realm, arg_authenticationMethod);
|
||||
return wrapResponse(empty: true);
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: e);
|
||||
} catch (e) {
|
||||
return wrapResponse(
|
||||
error: PlatformException(code: 'error', message: e.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Flutter API for `NSUrlAuthenticationChallenge`.
|
||||
///
|
||||
/// This class may handle instantiating and adding Dart instances that are
|
||||
/// attached to a native instance or receiving callback methods from an
|
||||
/// overridden native class.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlauthenticationchallenge?language=objc.
|
||||
abstract class NSUrlAuthenticationChallengeFlutterApi {
|
||||
static const MessageCodec<Object?> codec = StandardMessageCodec();
|
||||
|
||||
/// Create a new Dart instance and add it to the `InstanceManager`.
|
||||
void create(int identifier, int protectionSpaceIdentifier);
|
||||
|
||||
static void setup(NSUrlAuthenticationChallengeFlutterApi? api,
|
||||
{BinaryMessenger? binaryMessenger}) {
|
||||
{
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlAuthenticationChallengeFlutterApi.create',
|
||||
codec,
|
||||
binaryMessenger: binaryMessenger);
|
||||
if (api == null) {
|
||||
channel.setMessageHandler(null);
|
||||
} else {
|
||||
channel.setMessageHandler((Object? message) async {
|
||||
assert(message != null,
|
||||
'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlAuthenticationChallengeFlutterApi.create 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.webview_flutter_wkwebview.NSUrlAuthenticationChallengeFlutterApi.create was null, expected non-null int.');
|
||||
final int? arg_protectionSpaceIdentifier = (args[1] as int?);
|
||||
assert(arg_protectionSpaceIdentifier != null,
|
||||
'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlAuthenticationChallengeFlutterApi.create was null, expected non-null int.');
|
||||
try {
|
||||
api.create(arg_identifier!, arg_protectionSpaceIdentifier!);
|
||||
return wrapResponse(empty: true);
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: e);
|
||||
} catch (e) {
|
||||
return wrapResponse(
|
||||
error: PlatformException(code: 'error', message: e.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,9 @@ import '../common/instance_manager.dart';
|
||||
import '../common/weak_reference_utils.dart';
|
||||
import 'foundation_api_impls.dart';
|
||||
|
||||
export 'foundation_api_impls.dart'
|
||||
show NSUrlSessionAuthChallengeDisposition, NSUrlCredentialPersistence;
|
||||
|
||||
/// The values that can be returned in a change map.
|
||||
///
|
||||
/// Wraps [NSKeyValueObservingOptions](https://developer.apple.com/documentation/foundation/nskeyvalueobservingoptions?language=objc).
|
||||
@ -387,3 +390,131 @@ class NSObject with Copyable {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// An authentication credential consisting of information specific to the type
|
||||
/// of credential and the type of persistent storage to use, if any.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlcredential?language=objc.
|
||||
class NSUrlCredential extends NSObject {
|
||||
/// Creates a URL credential instance for internet password authentication
|
||||
/// with a given user name and password, using a given persistence setting.
|
||||
NSUrlCredential.withUser({
|
||||
required String user,
|
||||
required String password,
|
||||
required NSUrlCredentialPersistence persistence,
|
||||
@visibleForTesting super.binaryMessenger,
|
||||
@visibleForTesting super.instanceManager,
|
||||
}) : _urlCredentialApi = NSUrlCredentialHostApiImpl(
|
||||
binaryMessenger: binaryMessenger, instanceManager: instanceManager),
|
||||
super.detached() {
|
||||
// Ensures Flutter Apis are setup.
|
||||
FoundationFlutterApis.instance.ensureSetUp();
|
||||
_urlCredentialApi.createWithUserFromInstances(
|
||||
this,
|
||||
user,
|
||||
password,
|
||||
persistence,
|
||||
);
|
||||
}
|
||||
|
||||
/// Instantiates a [NSUrlCredential] without creating and attaching to an
|
||||
/// instance of the associated native class.
|
||||
///
|
||||
/// This should only be used outside of tests by subclasses created by this
|
||||
/// library or to create a copy for an [InstanceManager].
|
||||
@protected
|
||||
NSUrlCredential.detached({super.binaryMessenger, super.instanceManager})
|
||||
: _urlCredentialApi = NSUrlCredentialHostApiImpl(
|
||||
binaryMessenger: binaryMessenger, instanceManager: instanceManager),
|
||||
super.detached();
|
||||
|
||||
final NSUrlCredentialHostApiImpl _urlCredentialApi;
|
||||
|
||||
@override
|
||||
NSObject copy() {
|
||||
return NSUrlCredential.detached(
|
||||
binaryMessenger: _urlCredentialApi.binaryMessenger,
|
||||
instanceManager: _urlCredentialApi.instanceManager,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A server or an area on a server, commonly referred to as a realm, that
|
||||
/// requires authentication.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlprotectionspace?language=objc.
|
||||
class NSUrlProtectionSpace extends NSObject {
|
||||
/// Instantiates a [NSUrlProtectionSpace] without creating and attaching to an
|
||||
/// instance of the associated native class.
|
||||
///
|
||||
/// This should only be used outside of tests by subclasses created by this
|
||||
/// library or to create a copy for an [InstanceManager].
|
||||
@protected
|
||||
NSUrlProtectionSpace.detached({
|
||||
required this.host,
|
||||
required this.realm,
|
||||
required this.authenticationMethod,
|
||||
super.binaryMessenger,
|
||||
super.instanceManager,
|
||||
}) : super.detached();
|
||||
|
||||
/// The receiver’s host.
|
||||
final String? host;
|
||||
|
||||
/// The receiver’s authentication realm.
|
||||
final String? realm;
|
||||
|
||||
/// The authentication method used by the receiver.
|
||||
final String? authenticationMethod;
|
||||
|
||||
@override
|
||||
NSUrlProtectionSpace copy() {
|
||||
return NSUrlProtectionSpace.detached(
|
||||
host: host,
|
||||
realm: realm,
|
||||
authenticationMethod: authenticationMethod,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// The authentication method used by the receiver.
|
||||
class NSUrlAuthenticationMethod {
|
||||
/// Use the default authentication method for a protocol.
|
||||
static const String default_ = 'NSURLAuthenticationMethodDefault';
|
||||
|
||||
/// Use HTML form authentication for this protection space.
|
||||
static const String htmlForm = 'NSURLAuthenticationMethodHTMLForm';
|
||||
|
||||
/// Use HTTP basic authentication for this protection space.
|
||||
static const String httpBasic = 'NSURLAuthenticationMethodHTTPBasic';
|
||||
|
||||
/// Use HTTP digest authentication for this protection space.
|
||||
static const String httpDigest = 'NSURLAuthenticationMethodHTTPDigest';
|
||||
}
|
||||
|
||||
/// A challenge from a server requiring authentication from the client.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlauthenticationchallenge?language=objc.
|
||||
class NSUrlAuthenticationChallenge extends NSObject {
|
||||
/// Instantiates a [NSUrlAuthenticationChallenge] without creating and
|
||||
/// attaching to an instance of the associated native class.
|
||||
///
|
||||
/// This should only be used outside of tests by subclasses created by this
|
||||
/// library or to create a copy for an [InstanceManager].
|
||||
@protected
|
||||
NSUrlAuthenticationChallenge.detached({
|
||||
required this.protectionSpace,
|
||||
super.binaryMessenger,
|
||||
super.instanceManager,
|
||||
}) : super.detached();
|
||||
|
||||
/// The receiver’s protection space.
|
||||
late final NSUrlProtectionSpace protectionSpace;
|
||||
|
||||
@override
|
||||
NSUrlAuthenticationChallenge copy() {
|
||||
return NSUrlAuthenticationChallenge.detached(
|
||||
protectionSpace: protectionSpace,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,9 @@ import '../common/instance_manager.dart';
|
||||
import '../common/web_kit.g.dart';
|
||||
import 'foundation.dart';
|
||||
|
||||
export '../common/web_kit.g.dart'
|
||||
show NSUrlSessionAuthChallengeDisposition, NSUrlCredentialPersistence;
|
||||
|
||||
Iterable<NSKeyValueObservingOptionsEnumData>
|
||||
_toNSKeyValueObservingOptionsEnumData(
|
||||
Iterable<NSKeyValueObservingOptions> options,
|
||||
@ -56,6 +59,14 @@ class FoundationFlutterApis {
|
||||
url = NSUrlFlutterApiImpl(
|
||||
binaryMessenger: binaryMessenger,
|
||||
instanceManager: instanceManager,
|
||||
),
|
||||
urlProtectionSpace = NSUrlProtectionSpaceFlutterApiImpl(
|
||||
binaryMessenger: binaryMessenger,
|
||||
instanceManager: instanceManager,
|
||||
),
|
||||
urlAuthenticationChallenge = NSUrlAuthenticationChallengeFlutterApiImpl(
|
||||
binaryMessenger: binaryMessenger,
|
||||
instanceManager: instanceManager,
|
||||
);
|
||||
|
||||
static FoundationFlutterApis _instance = FoundationFlutterApis();
|
||||
@ -82,6 +93,14 @@ class FoundationFlutterApis {
|
||||
@visibleForTesting
|
||||
final NSUrlFlutterApiImpl url;
|
||||
|
||||
/// Flutter Api for [NSUrlProtectionSpace].
|
||||
@visibleForTesting
|
||||
final NSUrlProtectionSpaceFlutterApiImpl urlProtectionSpace;
|
||||
|
||||
/// Flutter Api for [NSUrlAuthenticationChallenge].
|
||||
@visibleForTesting
|
||||
final NSUrlAuthenticationChallengeFlutterApiImpl urlAuthenticationChallenge;
|
||||
|
||||
/// Ensures all the Flutter APIs have been set up to receive calls from native code.
|
||||
void ensureSetUp() {
|
||||
if (!_hasBeenSetUp) {
|
||||
@ -90,6 +109,14 @@ class FoundationFlutterApis {
|
||||
binaryMessenger: _binaryMessenger,
|
||||
);
|
||||
NSUrlFlutterApi.setup(url, binaryMessenger: _binaryMessenger);
|
||||
NSUrlProtectionSpaceFlutterApi.setup(
|
||||
urlProtectionSpace,
|
||||
binaryMessenger: _binaryMessenger,
|
||||
);
|
||||
NSUrlAuthenticationChallengeFlutterApi.setup(
|
||||
urlAuthenticationChallenge,
|
||||
binaryMessenger: _binaryMessenger,
|
||||
);
|
||||
_hasBeenSetUp = true;
|
||||
}
|
||||
}
|
||||
@ -249,3 +276,121 @@ class NSUrlFlutterApiImpl implements NSUrlFlutterApi {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Host api implementation for [NSUrlCredential].
|
||||
class NSUrlCredentialHostApiImpl extends NSUrlCredentialHostApi {
|
||||
/// Constructs an [NSUrlCredentialHostApiImpl].
|
||||
NSUrlCredentialHostApiImpl({
|
||||
this.binaryMessenger,
|
||||
InstanceManager? instanceManager,
|
||||
}) : instanceManager = instanceManager ?? NSObject.globalInstanceManager,
|
||||
super(binaryMessenger: binaryMessenger);
|
||||
|
||||
/// Sends binary data across the Flutter platform barrier.
|
||||
///
|
||||
/// If it is null, the default BinaryMessenger will be used which routes to
|
||||
/// the host platform.
|
||||
final BinaryMessenger? binaryMessenger;
|
||||
|
||||
/// Maintains instances stored to communicate with Objective-C objects.
|
||||
final InstanceManager instanceManager;
|
||||
|
||||
/// Calls [createWithUser] with the ids of the provided object instances.
|
||||
Future<void> createWithUserFromInstances(
|
||||
NSUrlCredential instance,
|
||||
String user,
|
||||
String password,
|
||||
NSUrlCredentialPersistence persistence,
|
||||
) {
|
||||
return createWithUser(
|
||||
instanceManager.addDartCreatedInstance(instance),
|
||||
user,
|
||||
password,
|
||||
persistence,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Flutter API implementation for [NSUrlProtectionSpace].
|
||||
///
|
||||
/// This class may handle instantiating and adding Dart instances that are
|
||||
/// attached to a native instance or receiving callback methods from an
|
||||
/// overridden native class.
|
||||
@protected
|
||||
class NSUrlProtectionSpaceFlutterApiImpl
|
||||
implements NSUrlProtectionSpaceFlutterApi {
|
||||
/// Constructs a [NSUrlProtectionSpaceFlutterApiImpl].
|
||||
NSUrlProtectionSpaceFlutterApiImpl({
|
||||
this.binaryMessenger,
|
||||
InstanceManager? instanceManager,
|
||||
}) : instanceManager = instanceManager ?? NSObject.globalInstanceManager;
|
||||
|
||||
/// Receives binary data across the Flutter platform barrier.
|
||||
///
|
||||
/// If it is null, the default BinaryMessenger will be used which routes to
|
||||
/// the host platform.
|
||||
final BinaryMessenger? binaryMessenger;
|
||||
|
||||
/// Maintains instances stored to communicate with native language objects.
|
||||
final InstanceManager instanceManager;
|
||||
|
||||
@override
|
||||
void create(
|
||||
int identifier,
|
||||
String? host,
|
||||
String? realm,
|
||||
String? authenticationMethod,
|
||||
) {
|
||||
instanceManager.addHostCreatedInstance(
|
||||
NSUrlProtectionSpace.detached(
|
||||
host: host,
|
||||
realm: realm,
|
||||
authenticationMethod: authenticationMethod,
|
||||
binaryMessenger: binaryMessenger,
|
||||
instanceManager: instanceManager,
|
||||
),
|
||||
identifier,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Flutter API implementation for [NSUrlAuthenticationChallenge].
|
||||
///
|
||||
/// This class may handle instantiating and adding Dart instances that are
|
||||
/// attached to a native instance or receiving callback methods from an
|
||||
/// overridden native class.
|
||||
@protected
|
||||
class NSUrlAuthenticationChallengeFlutterApiImpl
|
||||
implements NSUrlAuthenticationChallengeFlutterApi {
|
||||
/// Constructs a [NSUrlAuthenticationChallengeFlutterApiImpl].
|
||||
NSUrlAuthenticationChallengeFlutterApiImpl({
|
||||
this.binaryMessenger,
|
||||
InstanceManager? instanceManager,
|
||||
}) : instanceManager = instanceManager ?? NSObject.globalInstanceManager;
|
||||
|
||||
/// Receives binary data across the Flutter platform barrier.
|
||||
///
|
||||
/// If it is null, the default BinaryMessenger will be used which routes to
|
||||
/// the host platform.
|
||||
final BinaryMessenger? binaryMessenger;
|
||||
|
||||
/// Maintains instances stored to communicate with native language objects.
|
||||
final InstanceManager instanceManager;
|
||||
|
||||
@override
|
||||
void create(
|
||||
int identifier,
|
||||
int protectionSpaceIdentifier,
|
||||
) {
|
||||
instanceManager.addHostCreatedInstance(
|
||||
NSUrlAuthenticationChallenge.detached(
|
||||
protectionSpace: instanceManager.getInstanceWithWeakReference(
|
||||
protectionSpaceIdentifier,
|
||||
)!,
|
||||
binaryMessenger: binaryMessenger,
|
||||
instanceManager: instanceManager,
|
||||
),
|
||||
identifier,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -830,6 +830,7 @@ class WKNavigationDelegate extends NSObject {
|
||||
this.didFailNavigation,
|
||||
this.didFailProvisionalNavigation,
|
||||
this.webViewWebContentProcessDidTerminate,
|
||||
this.didReceiveAuthenticationChallenge,
|
||||
super.observeValue,
|
||||
super.binaryMessenger,
|
||||
super.instanceManager,
|
||||
@ -855,6 +856,7 @@ class WKNavigationDelegate extends NSObject {
|
||||
this.didFailNavigation,
|
||||
this.didFailProvisionalNavigation,
|
||||
this.webViewWebContentProcessDidTerminate,
|
||||
this.didReceiveAuthenticationChallenge,
|
||||
super.observeValue,
|
||||
super.binaryMessenger,
|
||||
super.instanceManager,
|
||||
@ -901,6 +903,16 @@ class WKNavigationDelegate extends NSObject {
|
||||
/// {@macro webview_flutter_wkwebview.foundation.callbacks}
|
||||
final void Function(WKWebView webView)? webViewWebContentProcessDidTerminate;
|
||||
|
||||
/// Called when the delegate needs a response to an authentication challenge.
|
||||
final void Function(
|
||||
WKWebView webView,
|
||||
NSUrlAuthenticationChallenge challenge,
|
||||
void Function(
|
||||
NSUrlSessionAuthChallengeDisposition disposition,
|
||||
NSUrlCredential? credential,
|
||||
) completionHandler,
|
||||
)? didReceiveAuthenticationChallenge;
|
||||
|
||||
@override
|
||||
WKNavigationDelegate copy() {
|
||||
return WKNavigationDelegate.detached(
|
||||
@ -911,6 +923,7 @@ class WKNavigationDelegate extends NSObject {
|
||||
didFailProvisionalNavigation: didFailProvisionalNavigation,
|
||||
webViewWebContentProcessDidTerminate:
|
||||
webViewWebContentProcessDidTerminate,
|
||||
didReceiveAuthenticationChallenge: didReceiveAuthenticationChallenge,
|
||||
observeValue: observeValue,
|
||||
binaryMessenger: _navigationDelegateApi.binaryMessenger,
|
||||
instanceManager: _navigationDelegateApi.instanceManager,
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
@ -904,6 +906,53 @@ class WKNavigationDelegateFlutterApiImpl
|
||||
as WKWebView,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<AuthenticationChallengeResponse> didReceiveAuthenticationChallenge(
|
||||
int identifier,
|
||||
int webViewIdentifier,
|
||||
int challengeIdentifier,
|
||||
) async {
|
||||
final void Function(
|
||||
WKWebView webView,
|
||||
NSUrlAuthenticationChallenge challenge,
|
||||
void Function(
|
||||
NSUrlSessionAuthChallengeDisposition disposition,
|
||||
NSUrlCredential? credential,
|
||||
),
|
||||
)? function = _getDelegate(identifier).didReceiveAuthenticationChallenge;
|
||||
|
||||
if (function == null) {
|
||||
return AuthenticationChallengeResponse(
|
||||
disposition: NSUrlSessionAuthChallengeDisposition.rejectProtectionSpace,
|
||||
);
|
||||
}
|
||||
|
||||
final Completer<AuthenticationChallengeResponse> responseCompleter =
|
||||
Completer<AuthenticationChallengeResponse>();
|
||||
|
||||
function.call(
|
||||
instanceManager.getInstanceWithWeakReference(webViewIdentifier)!
|
||||
as WKWebView,
|
||||
instanceManager.getInstanceWithWeakReference(challengeIdentifier)!
|
||||
as NSUrlAuthenticationChallenge,
|
||||
(
|
||||
NSUrlSessionAuthChallengeDisposition disposition,
|
||||
NSUrlCredential? credential,
|
||||
) {
|
||||
responseCompleter.complete(
|
||||
AuthenticationChallengeResponse(
|
||||
disposition: disposition,
|
||||
credentialIdentifier: credential != null
|
||||
? instanceManager.getIdentifier(credential)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return responseCompleter.future;
|
||||
}
|
||||
}
|
||||
|
||||
/// Host api implementation for [WKWebView].
|
||||
|
@ -71,6 +71,14 @@ class WebKitProxy {
|
||||
void Function(WKWebView webView, NSError error)?
|
||||
didFailProvisionalNavigation,
|
||||
void Function(WKWebView webView)? webViewWebContentProcessDidTerminate,
|
||||
void Function(
|
||||
WKWebView webView,
|
||||
NSUrlAuthenticationChallenge challenge,
|
||||
void Function(
|
||||
NSUrlSessionAuthChallengeDisposition disposition,
|
||||
NSUrlCredential? credential,
|
||||
) completionHandler,
|
||||
)? didReceiveAuthenticationChallenge,
|
||||
}) createNavigationDelegate;
|
||||
|
||||
/// Constructs a [WKUIDelegate].
|
||||
|
@ -948,6 +948,54 @@ class WebKitNavigationDelegate extends PlatformNavigationDelegate {
|
||||
);
|
||||
}
|
||||
},
|
||||
didReceiveAuthenticationChallenge: (
|
||||
WKWebView webView,
|
||||
NSUrlAuthenticationChallenge challenge,
|
||||
void Function(
|
||||
NSUrlSessionAuthChallengeDisposition disposition,
|
||||
NSUrlCredential? credential,
|
||||
) completionHandler,
|
||||
) {
|
||||
if (challenge.protectionSpace.authenticationMethod ==
|
||||
NSUrlAuthenticationMethod.httpBasic) {
|
||||
final void Function(HttpAuthRequest)? callback =
|
||||
weakThis.target?._onHttpAuthRequest;
|
||||
final String? host = challenge.protectionSpace.host;
|
||||
final String? realm = challenge.protectionSpace.realm;
|
||||
|
||||
if (callback != null && host != null) {
|
||||
callback(
|
||||
HttpAuthRequest(
|
||||
onProceed: (WebViewCredential credential) {
|
||||
completionHandler(
|
||||
NSUrlSessionAuthChallengeDisposition.useCredential,
|
||||
NSUrlCredential.withUser(
|
||||
user: credential.user,
|
||||
password: credential.password,
|
||||
persistence: NSUrlCredentialPersistence.session,
|
||||
),
|
||||
);
|
||||
},
|
||||
onCancel: () {
|
||||
completionHandler(
|
||||
NSUrlSessionAuthChallengeDisposition
|
||||
.cancelAuthenticationChallenge,
|
||||
null,
|
||||
);
|
||||
},
|
||||
host: host,
|
||||
realm: realm,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
completionHandler(
|
||||
NSUrlSessionAuthChallengeDisposition.performDefaultHandling,
|
||||
null,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@ -960,6 +1008,7 @@ class WebKitNavigationDelegate extends PlatformNavigationDelegate {
|
||||
WebResourceErrorCallback? _onWebResourceError;
|
||||
NavigationRequestCallback? _onNavigationRequest;
|
||||
UrlChangeCallback? _onUrlChange;
|
||||
HttpAuthRequestCallback? _onHttpAuthRequest;
|
||||
|
||||
@override
|
||||
Future<void> setOnPageFinished(PageEventCallback onPageFinished) async {
|
||||
@ -994,6 +1043,13 @@ class WebKitNavigationDelegate extends PlatformNavigationDelegate {
|
||||
Future<void> setOnUrlChange(UrlChangeCallback onUrlChange) async {
|
||||
_onUrlChange = onUrlChange;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setOnHttpAuthRequest(
|
||||
HttpAuthRequestCallback onHttpAuthRequest,
|
||||
) async {
|
||||
_onHttpAuthRequest = onHttpAuthRequest;
|
||||
}
|
||||
}
|
||||
|
||||
/// WebKit implementation of [PlatformWebViewPermissionRequest].
|
||||
|
@ -258,6 +258,58 @@ class WKMediaCaptureTypeData {
|
||||
late WKMediaCaptureType value;
|
||||
}
|
||||
|
||||
/// Responses to an authentication challenge.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition?language=objc.
|
||||
enum NSUrlSessionAuthChallengeDisposition {
|
||||
/// Use the specified credential, which may be nil.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengeusecredential?language=objc.
|
||||
useCredential,
|
||||
|
||||
/// Use the default handling for the challenge as though this delegate method
|
||||
/// were not implemented.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengeperformdefaulthandling?language=objc.
|
||||
performDefaultHandling,
|
||||
|
||||
/// Cancel the entire request.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengecancelauthenticationchallenge?language=objc.
|
||||
cancelAuthenticationChallenge,
|
||||
|
||||
/// Reject this challenge, and call the authentication delegate method again
|
||||
/// with the next authentication protection space.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengerejectprotectionspace?language=objc.
|
||||
rejectProtectionSpace,
|
||||
}
|
||||
|
||||
/// Specifies how long a credential will be kept.
|
||||
enum NSUrlCredentialPersistence {
|
||||
/// The credential should not be stored.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencenone?language=objc.
|
||||
none,
|
||||
|
||||
/// The credential should be stored only for this session.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistenceforsession?language=objc.
|
||||
session,
|
||||
|
||||
/// The credential should be stored in the keychain.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencepermanent?language=objc.
|
||||
permanent,
|
||||
|
||||
/// The credential should be stored permanently in the keychain, and in
|
||||
/// addition should be distributed to other devices based on the owning Apple
|
||||
/// ID.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencesynchronizable?language=objc.
|
||||
synchronizable,
|
||||
}
|
||||
|
||||
/// Mirror of NSURLRequest.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlrequest?language=objc.
|
||||
@ -343,6 +395,11 @@ class ObjectOrIdentifier {
|
||||
late bool isIdentifier;
|
||||
}
|
||||
|
||||
class AuthenticationChallengeResponse {
|
||||
late NSUrlSessionAuthChallengeDisposition disposition;
|
||||
late int? credentialIdentifier;
|
||||
}
|
||||
|
||||
/// Mirror of WKWebsiteDataStore.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/webkit/wkwebsitedatastore?language=objc.
|
||||
@ -582,6 +639,16 @@ abstract class WKNavigationDelegateFlutterApi {
|
||||
int identifier,
|
||||
int webViewIdentifier,
|
||||
);
|
||||
|
||||
@async
|
||||
@ObjCSelector(
|
||||
'didReceiveAuthenticationChallengeForDelegateWithIdentifier:webViewIdentifier:challengeIdentifier:',
|
||||
)
|
||||
AuthenticationChallengeResponse didReceiveAuthenticationChallenge(
|
||||
int identifier,
|
||||
int webViewIdentifier,
|
||||
int challengeIdentifier,
|
||||
);
|
||||
}
|
||||
|
||||
/// Mirror of NSObject.
|
||||
@ -781,3 +848,57 @@ abstract class NSUrlFlutterApi {
|
||||
@ObjCSelector('createWithIdentifier:')
|
||||
void create(int identifier);
|
||||
}
|
||||
|
||||
/// Host API for `NSUrlCredential`.
|
||||
///
|
||||
/// This class may handle instantiating and adding native object instances that
|
||||
/// are attached to a Dart instance or handle method calls on the associated
|
||||
/// native class or an instance of the class.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlcredential?language=objc.
|
||||
@HostApi(dartHostTestHandler: 'TestNSUrlCredentialHostApi')
|
||||
abstract class NSUrlCredentialHostApi {
|
||||
/// Create a new native instance and add it to the `InstanceManager`.
|
||||
@ObjCSelector(
|
||||
'createWithUserWithIdentifier:user:password:persistence:',
|
||||
)
|
||||
void createWithUser(
|
||||
int identifier,
|
||||
String user,
|
||||
String password,
|
||||
NSUrlCredentialPersistence persistence,
|
||||
);
|
||||
}
|
||||
|
||||
/// Flutter API for `NSUrlProtectionSpace`.
|
||||
///
|
||||
/// This class may handle instantiating and adding Dart instances that are
|
||||
/// attached to a native instance or receiving callback methods from an
|
||||
/// overridden native class.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlprotectionspace?language=objc.
|
||||
@FlutterApi()
|
||||
abstract class NSUrlProtectionSpaceFlutterApi {
|
||||
/// Create a new Dart instance and add it to the `InstanceManager`.
|
||||
@ObjCSelector('createWithIdentifier:host:realm:authenticationMethod:')
|
||||
void create(
|
||||
int identifier,
|
||||
String? host,
|
||||
String? realm,
|
||||
String? authenticationMethod,
|
||||
);
|
||||
}
|
||||
|
||||
/// Flutter API for `NSUrlAuthenticationChallenge`.
|
||||
///
|
||||
/// This class may handle instantiating and adding Dart instances that are
|
||||
/// attached to a native instance or receiving callback methods from an
|
||||
/// overridden native class.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlauthenticationchallenge?language=objc.
|
||||
@FlutterApi()
|
||||
abstract class NSUrlAuthenticationChallengeFlutterApi {
|
||||
/// Create a new Dart instance and add it to the `InstanceManager`.
|
||||
@ObjCSelector('createWithIdentifier:protectionSpaceIdentifier:')
|
||||
void create(int identifier, int protectionSpaceIdentifier);
|
||||
}
|
||||
|
@ -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.9.4
|
||||
version: 3.10.0
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
@ -20,7 +20,7 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
path: ^1.8.0
|
||||
webview_flutter_platform_interface: ^2.6.0
|
||||
webview_flutter_platform_interface: ^2.7.0
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.1.5
|
||||
|
@ -1199,60 +1199,63 @@ class _TestWKWebViewHostApiCodec extends StandardMessageCodec {
|
||||
const _TestWKWebViewHostApiCodec();
|
||||
@override
|
||||
void writeValue(WriteBuffer buffer, Object? value) {
|
||||
if (value is NSErrorData) {
|
||||
if (value is AuthenticationChallengeResponse) {
|
||||
buffer.putUint8(128);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NSHttpCookieData) {
|
||||
} else if (value is NSErrorData) {
|
||||
buffer.putUint8(129);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NSHttpCookiePropertyKeyEnumData) {
|
||||
} else if (value is NSHttpCookieData) {
|
||||
buffer.putUint8(130);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NSKeyValueChangeKeyEnumData) {
|
||||
} else if (value is NSHttpCookiePropertyKeyEnumData) {
|
||||
buffer.putUint8(131);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NSKeyValueObservingOptionsEnumData) {
|
||||
} else if (value is NSKeyValueChangeKeyEnumData) {
|
||||
buffer.putUint8(132);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NSUrlRequestData) {
|
||||
} else if (value is NSKeyValueObservingOptionsEnumData) {
|
||||
buffer.putUint8(133);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is ObjectOrIdentifier) {
|
||||
} else if (value is NSUrlRequestData) {
|
||||
buffer.putUint8(134);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKAudiovisualMediaTypeEnumData) {
|
||||
} else if (value is ObjectOrIdentifier) {
|
||||
buffer.putUint8(135);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKFrameInfoData) {
|
||||
} else if (value is WKAudiovisualMediaTypeEnumData) {
|
||||
buffer.putUint8(136);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKMediaCaptureTypeData) {
|
||||
} else if (value is WKFrameInfoData) {
|
||||
buffer.putUint8(137);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKNavigationActionData) {
|
||||
} else if (value is WKMediaCaptureTypeData) {
|
||||
buffer.putUint8(138);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKNavigationActionPolicyEnumData) {
|
||||
} else if (value is WKNavigationActionData) {
|
||||
buffer.putUint8(139);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKPermissionDecisionData) {
|
||||
} else if (value is WKNavigationActionPolicyEnumData) {
|
||||
buffer.putUint8(140);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKScriptMessageData) {
|
||||
} else if (value is WKPermissionDecisionData) {
|
||||
buffer.putUint8(141);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKSecurityOriginData) {
|
||||
} else if (value is WKScriptMessageData) {
|
||||
buffer.putUint8(142);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKUserScriptData) {
|
||||
} else if (value is WKSecurityOriginData) {
|
||||
buffer.putUint8(143);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKUserScriptInjectionTimeEnumData) {
|
||||
} else if (value is WKUserScriptData) {
|
||||
buffer.putUint8(144);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKWebsiteDataTypeEnumData) {
|
||||
} else if (value is WKUserScriptInjectionTimeEnumData) {
|
||||
buffer.putUint8(145);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is WKWebsiteDataTypeEnumData) {
|
||||
buffer.putUint8(146);
|
||||
writeValue(buffer, value.encode());
|
||||
} else {
|
||||
super.writeValue(buffer, value);
|
||||
}
|
||||
@ -1262,40 +1265,42 @@ class _TestWKWebViewHostApiCodec extends StandardMessageCodec {
|
||||
Object? readValueOfType(int type, ReadBuffer buffer) {
|
||||
switch (type) {
|
||||
case 128:
|
||||
return NSErrorData.decode(readValue(buffer)!);
|
||||
return AuthenticationChallengeResponse.decode(readValue(buffer)!);
|
||||
case 129:
|
||||
return NSHttpCookieData.decode(readValue(buffer)!);
|
||||
return NSErrorData.decode(readValue(buffer)!);
|
||||
case 130:
|
||||
return NSHttpCookiePropertyKeyEnumData.decode(readValue(buffer)!);
|
||||
return NSHttpCookieData.decode(readValue(buffer)!);
|
||||
case 131:
|
||||
return NSKeyValueChangeKeyEnumData.decode(readValue(buffer)!);
|
||||
return NSHttpCookiePropertyKeyEnumData.decode(readValue(buffer)!);
|
||||
case 132:
|
||||
return NSKeyValueObservingOptionsEnumData.decode(readValue(buffer)!);
|
||||
return NSKeyValueChangeKeyEnumData.decode(readValue(buffer)!);
|
||||
case 133:
|
||||
return NSUrlRequestData.decode(readValue(buffer)!);
|
||||
return NSKeyValueObservingOptionsEnumData.decode(readValue(buffer)!);
|
||||
case 134:
|
||||
return ObjectOrIdentifier.decode(readValue(buffer)!);
|
||||
return NSUrlRequestData.decode(readValue(buffer)!);
|
||||
case 135:
|
||||
return WKAudiovisualMediaTypeEnumData.decode(readValue(buffer)!);
|
||||
return ObjectOrIdentifier.decode(readValue(buffer)!);
|
||||
case 136:
|
||||
return WKFrameInfoData.decode(readValue(buffer)!);
|
||||
return WKAudiovisualMediaTypeEnumData.decode(readValue(buffer)!);
|
||||
case 137:
|
||||
return WKMediaCaptureTypeData.decode(readValue(buffer)!);
|
||||
return WKFrameInfoData.decode(readValue(buffer)!);
|
||||
case 138:
|
||||
return WKNavigationActionData.decode(readValue(buffer)!);
|
||||
return WKMediaCaptureTypeData.decode(readValue(buffer)!);
|
||||
case 139:
|
||||
return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
|
||||
return WKNavigationActionData.decode(readValue(buffer)!);
|
||||
case 140:
|
||||
return WKPermissionDecisionData.decode(readValue(buffer)!);
|
||||
return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
|
||||
case 141:
|
||||
return WKScriptMessageData.decode(readValue(buffer)!);
|
||||
return WKPermissionDecisionData.decode(readValue(buffer)!);
|
||||
case 142:
|
||||
return WKSecurityOriginData.decode(readValue(buffer)!);
|
||||
return WKScriptMessageData.decode(readValue(buffer)!);
|
||||
case 143:
|
||||
return WKUserScriptData.decode(readValue(buffer)!);
|
||||
return WKSecurityOriginData.decode(readValue(buffer)!);
|
||||
case 144:
|
||||
return WKUserScriptInjectionTimeEnumData.decode(readValue(buffer)!);
|
||||
return WKUserScriptData.decode(readValue(buffer)!);
|
||||
case 145:
|
||||
return WKUserScriptInjectionTimeEnumData.decode(readValue(buffer)!);
|
||||
case 146:
|
||||
return WKWebsiteDataTypeEnumData.decode(readValue(buffer)!);
|
||||
default:
|
||||
return super.readValueOfType(type, buffer);
|
||||
@ -2196,3 +2201,66 @@ abstract class TestNSUrlHostApi {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Host API for `NSUrlCredential`.
|
||||
///
|
||||
/// This class may handle instantiating and adding native object instances that
|
||||
/// are attached to a Dart instance or handle method calls on the associated
|
||||
/// native class or an instance of the class.
|
||||
///
|
||||
/// See https://developer.apple.com/documentation/foundation/nsurlcredential?language=objc.
|
||||
abstract class TestNSUrlCredentialHostApi {
|
||||
static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
|
||||
TestDefaultBinaryMessengerBinding.instance;
|
||||
static const MessageCodec<Object?> codec = StandardMessageCodec();
|
||||
|
||||
/// Create a new native instance and add it to the `InstanceManager`.
|
||||
void createWithUser(int identifier, String user, String password,
|
||||
NSUrlCredentialPersistence persistence);
|
||||
|
||||
static void setup(TestNSUrlCredentialHostApi? api,
|
||||
{BinaryMessenger? binaryMessenger}) {
|
||||
{
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser',
|
||||
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.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser 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.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser was null, expected non-null int.');
|
||||
final String? arg_user = (args[1] as String?);
|
||||
assert(arg_user != null,
|
||||
'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser was null, expected non-null String.');
|
||||
final String? arg_password = (args[2] as String?);
|
||||
assert(arg_password != null,
|
||||
'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser was null, expected non-null String.');
|
||||
final NSUrlCredentialPersistence? arg_persistence = args[3] == null
|
||||
? null
|
||||
: NSUrlCredentialPersistence.values[args[3]! as int];
|
||||
assert(arg_persistence != null,
|
||||
'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser was null, expected non-null NSUrlCredentialPersistence.');
|
||||
try {
|
||||
api.createWithUser(
|
||||
arg_identifier!, arg_user!, arg_password!, arg_persistence!);
|
||||
return wrapResponse(empty: true);
|
||||
} on PlatformException catch (e) {
|
||||
return wrapResponse(error: e);
|
||||
} catch (e) {
|
||||
return wrapResponse(
|
||||
error: PlatformException(code: 'error', message: e.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import 'foundation_test.mocks.dart';
|
||||
|
||||
@GenerateMocks(<Type>[
|
||||
TestNSObjectHostApi,
|
||||
TestNSUrlCredentialHostApi,
|
||||
TestNSUrlHostApi,
|
||||
])
|
||||
void main() {
|
||||
@ -245,6 +246,102 @@ void main() {
|
||||
expect(instanceManager.getInstanceWithWeakReference(0), isA<NSUrl>());
|
||||
});
|
||||
});
|
||||
|
||||
group('NSUrlCredential', () {
|
||||
tearDown(() {
|
||||
TestNSUrlCredentialHostApi.setup(null);
|
||||
});
|
||||
|
||||
test('HostApi createWithUser', () {
|
||||
final MockTestNSUrlCredentialHostApi mockApi =
|
||||
MockTestNSUrlCredentialHostApi();
|
||||
TestNSUrlCredentialHostApi.setup(mockApi);
|
||||
|
||||
final InstanceManager instanceManager = InstanceManager(
|
||||
onWeakReferenceRemoved: (_) {},
|
||||
);
|
||||
|
||||
const String user = 'testString';
|
||||
const String password = 'testString2';
|
||||
|
||||
const NSUrlCredentialPersistence persistence =
|
||||
NSUrlCredentialPersistence.permanent;
|
||||
|
||||
final NSUrlCredential instance = NSUrlCredential.withUser(
|
||||
user: user,
|
||||
password: password,
|
||||
persistence: persistence,
|
||||
instanceManager: instanceManager,
|
||||
);
|
||||
|
||||
verify(mockApi.createWithUser(
|
||||
instanceManager.getIdentifier(instance),
|
||||
user,
|
||||
password,
|
||||
persistence,
|
||||
));
|
||||
});
|
||||
});
|
||||
|
||||
group('NSUrlProtectionSpace', () {
|
||||
test('FlutterAPI create', () {
|
||||
final InstanceManager instanceManager = InstanceManager(
|
||||
onWeakReferenceRemoved: (_) {},
|
||||
);
|
||||
|
||||
final NSUrlProtectionSpaceFlutterApiImpl api =
|
||||
NSUrlProtectionSpaceFlutterApiImpl(
|
||||
instanceManager: instanceManager,
|
||||
);
|
||||
|
||||
const int instanceIdentifier = 0;
|
||||
|
||||
api.create(
|
||||
instanceIdentifier,
|
||||
'testString',
|
||||
'testString',
|
||||
'testAuthenticationMethod',
|
||||
);
|
||||
|
||||
expect(
|
||||
instanceManager.getInstanceWithWeakReference(instanceIdentifier),
|
||||
isA<NSUrlProtectionSpace>(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('NSUrlAuthenticationChallenge', () {
|
||||
test('FlutterAPI create', () {
|
||||
final InstanceManager instanceManager = InstanceManager(
|
||||
onWeakReferenceRemoved: (_) {},
|
||||
);
|
||||
|
||||
final NSUrlAuthenticationChallengeFlutterApiImpl api =
|
||||
NSUrlAuthenticationChallengeFlutterApiImpl(
|
||||
instanceManager: instanceManager,
|
||||
);
|
||||
|
||||
const int instanceIdentifier = 0;
|
||||
|
||||
const int protectionSpaceIdentifier = 1;
|
||||
instanceManager.addHostCreatedInstance(
|
||||
NSUrlProtectionSpace.detached(
|
||||
host: null,
|
||||
realm: null,
|
||||
authenticationMethod: null,
|
||||
instanceManager: instanceManager,
|
||||
),
|
||||
protectionSpaceIdentifier,
|
||||
);
|
||||
|
||||
api.create(instanceIdentifier, protectionSpaceIdentifier);
|
||||
|
||||
expect(
|
||||
instanceManager.getInstanceWithWeakReference(instanceIdentifier),
|
||||
isA<NSUrlAuthenticationChallenge>(),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('NSError', () {
|
||||
|
@ -78,6 +78,36 @@ class MockTestNSObjectHostApi extends _i1.Mock
|
||||
);
|
||||
}
|
||||
|
||||
/// A class which mocks [TestNSUrlCredentialHostApi].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockTestNSUrlCredentialHostApi extends _i1.Mock
|
||||
implements _i2.TestNSUrlCredentialHostApi {
|
||||
MockTestNSUrlCredentialHostApi() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void createWithUser(
|
||||
int? identifier,
|
||||
String? user,
|
||||
String? password,
|
||||
_i3.NSUrlCredentialPersistence? persistence,
|
||||
) =>
|
||||
super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#createWithUser,
|
||||
[
|
||||
identifier,
|
||||
user,
|
||||
password,
|
||||
persistence,
|
||||
],
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
}
|
||||
|
||||
/// A class which mocks [TestNSUrlHostApi].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
|
@ -683,6 +683,63 @@ void main() {
|
||||
|
||||
expect(argsCompleter.future, completion(<Object?>[webView]));
|
||||
});
|
||||
|
||||
test('didReceiveAuthenticationChallenge', () async {
|
||||
WebKitFlutterApis.instance = WebKitFlutterApis(
|
||||
instanceManager: instanceManager,
|
||||
);
|
||||
|
||||
const int credentialIdentifier = 3;
|
||||
final NSUrlCredential credential = NSUrlCredential.detached(
|
||||
instanceManager: instanceManager,
|
||||
);
|
||||
instanceManager.addHostCreatedInstance(
|
||||
credential,
|
||||
credentialIdentifier,
|
||||
);
|
||||
|
||||
navigationDelegate = WKNavigationDelegate(
|
||||
instanceManager: instanceManager,
|
||||
didReceiveAuthenticationChallenge: (
|
||||
WKWebView webView,
|
||||
NSUrlAuthenticationChallenge challenge,
|
||||
void Function(
|
||||
NSUrlSessionAuthChallengeDisposition disposition,
|
||||
NSUrlCredential? credential,
|
||||
) completionHandler,
|
||||
) {
|
||||
completionHandler(
|
||||
NSUrlSessionAuthChallengeDisposition.useCredential,
|
||||
credential,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
const int challengeIdentifier = 27;
|
||||
instanceManager.addHostCreatedInstance(
|
||||
NSUrlAuthenticationChallenge.detached(
|
||||
protectionSpace: NSUrlProtectionSpace.detached(
|
||||
host: null,
|
||||
realm: null,
|
||||
authenticationMethod: null,
|
||||
),
|
||||
instanceManager: instanceManager,
|
||||
),
|
||||
challengeIdentifier,
|
||||
);
|
||||
|
||||
final AuthenticationChallengeResponse response = await WebKitFlutterApis
|
||||
.instance.navigationDelegate
|
||||
.didReceiveAuthenticationChallenge(
|
||||
instanceManager.getIdentifier(navigationDelegate)!,
|
||||
instanceManager.getIdentifier(webView)!,
|
||||
challengeIdentifier,
|
||||
);
|
||||
|
||||
expect(response.disposition,
|
||||
NSUrlSessionAuthChallengeDisposition.useCredential);
|
||||
expect(response.credentialIdentifier, credentialIdentifier);
|
||||
});
|
||||
});
|
||||
|
||||
group('WKWebView', () {
|
||||
|
@ -7,6 +7,7 @@ import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
|
||||
import 'package:webview_flutter_wkwebview/src/common/web_kit.g.dart';
|
||||
import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart';
|
||||
import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart';
|
||||
import 'package:webview_flutter_wkwebview/src/webkit_proxy.dart';
|
||||
@ -214,6 +215,44 @@ void main() {
|
||||
expect(callbackRequest.url, 'https://www.google.com');
|
||||
expect(callbackRequest.isMainFrame, isFalse);
|
||||
});
|
||||
|
||||
test('onHttpBasicAuthRequest emits host and realm', () {
|
||||
final WebKitNavigationDelegate iosNavigationDelegate =
|
||||
WebKitNavigationDelegate(
|
||||
const WebKitNavigationDelegateCreationParams(
|
||||
webKitProxy: WebKitProxy(
|
||||
createNavigationDelegate: CapturingNavigationDelegate.new,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
String? callbackHost;
|
||||
String? callbackRealm;
|
||||
|
||||
iosNavigationDelegate.setOnHttpAuthRequest((HttpAuthRequest request) {
|
||||
callbackHost = request.host;
|
||||
callbackRealm = request.realm;
|
||||
});
|
||||
|
||||
const String expectedHost = 'expectedHost';
|
||||
const String expectedRealm = 'expectedRealm';
|
||||
|
||||
CapturingNavigationDelegate
|
||||
.lastCreatedDelegate.didReceiveAuthenticationChallenge!(
|
||||
WKWebView.detached(),
|
||||
NSUrlAuthenticationChallenge.detached(
|
||||
protectionSpace: NSUrlProtectionSpace.detached(
|
||||
host: expectedHost,
|
||||
realm: expectedRealm,
|
||||
authenticationMethod: NSUrlAuthenticationMethod.httpBasic,
|
||||
),
|
||||
),
|
||||
(NSUrlSessionAuthChallengeDisposition disposition,
|
||||
NSUrlCredential? credential) {});
|
||||
|
||||
expect(callbackHost, expectedHost);
|
||||
expect(callbackRealm, expectedRealm);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -226,6 +265,7 @@ class CapturingNavigationDelegate extends WKNavigationDelegate {
|
||||
super.didFailProvisionalNavigation,
|
||||
super.decidePolicyForNavigationAction,
|
||||
super.webViewWebContentProcessDidTerminate,
|
||||
super.didReceiveAuthenticationChallenge,
|
||||
}) : super.detached() {
|
||||
lastCreatedDelegate = this;
|
||||
}
|
||||
|
@ -1366,6 +1366,7 @@ class CapturingNavigationDelegate extends WKNavigationDelegate {
|
||||
super.didFailProvisionalNavigation,
|
||||
super.decidePolicyForNavigationAction,
|
||||
super.webViewWebContentProcessDidTerminate,
|
||||
super.didReceiveAuthenticationChallenge,
|
||||
}) : super.detached() {
|
||||
lastCreatedDelegate = this;
|
||||
}
|
||||
|
Reference in New Issue
Block a user