diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Flutter/AppFrameworkInfo.plist b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Flutter/AppFrameworkInfo.plist index 8d4492f977ad..9625e105df39 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Flutter/AppFrameworkInfo.plist +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 9.0 + 11.0 diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Podfile b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Podfile index 66509fcae284..d01e899e347b 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Podfile +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj index e7519af18e7c..4ed8769ea518 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj @@ -614,7 +614,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -664,7 +664,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner/Info.plist b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner/Info.plist index a810c5a172c0..bea41604e8aa 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner/Info.plist +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner/Info.plist @@ -41,5 +41,7 @@ UIViewControllerBasedStatusBarAppearance + CADisableMinimumFrameDurationOnPhone + diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFDataConvertersTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFDataConvertersTests.m index 57d90f6c6814..1fc5a95398bd 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFDataConvertersTests.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFDataConvertersTests.m @@ -6,6 +6,8 @@ @import XCTest; @import webview_flutter_wkwebview; +#import + @interface FWFDataConvertersTests : XCTestCase @end @@ -43,4 +45,63 @@ - (void)testFWFWKUserScriptFromScriptData { XCTAssertEqual(userScript.injectionTime, WKUserScriptInjectionTimeAtDocumentStart); XCTAssertEqual(userScript.isForMainFrameOnly, NO); } + +- (void)testFWFWKNavigationActionDataFromNavigationAction { + WKNavigationAction *mockNavigationAction = OCMClassMock([WKNavigationAction class]); + + NSURLRequest *request = + [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.flutter.dev/"]]; + OCMStub([mockNavigationAction request]).andReturn(request); + + WKFrameInfo *mockFrameInfo = OCMClassMock([WKFrameInfo class]); + OCMStub([mockFrameInfo isMainFrame]).andReturn(YES); + OCMStub([mockNavigationAction targetFrame]).andReturn(mockFrameInfo); + + FWFWKNavigationActionData *data = + FWFWKNavigationActionDataFromNavigationAction(mockNavigationAction); + XCTAssertNotNil(data); +} + +- (void)testFWFNSUrlRequestDataFromNSURLRequest { + NSMutableURLRequest *request = + [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://www.flutter.dev/"]]; + request.HTTPMethod = @"POST"; + request.HTTPBody = [@"aString" dataUsingEncoding:NSUTF8StringEncoding]; + request.allHTTPHeaderFields = @{@"a" : @"field"}; + + FWFNSUrlRequestData *data = FWFNSUrlRequestDataFromNSURLRequest(request); + XCTAssertEqualObjects(data.url, @"https://www.flutter.dev/"); + XCTAssertEqualObjects(data.httpMethod, @"POST"); + XCTAssertEqualObjects(data.httpBody.data, [@"aString" dataUsingEncoding:NSUTF8StringEncoding]); + XCTAssertEqualObjects(data.allHttpHeaderFields, @{@"a" : @"field"}); +} + +- (void)testFWFWKFrameInfoDataFromWKFrameInfo { + WKFrameInfo *mockFrameInfo = OCMClassMock([WKFrameInfo class]); + OCMStub([mockFrameInfo isMainFrame]).andReturn(YES); + + FWFWKFrameInfoData *targetFrameData = FWFWKFrameInfoDataFromWKFrameInfo(mockFrameInfo); + XCTAssertEqualObjects(targetFrameData.isMainFrame, @YES); +} + +- (void)testFWFNSErrorDataFromNSError { + NSError *error = [NSError errorWithDomain:@"domain" + code:23 + userInfo:@{NSLocalizedDescriptionKey : @"description"}]; + + FWFNSErrorData *data = FWFNSErrorDataFromNSError(error); + XCTAssertEqualObjects(data.code, @23); + XCTAssertEqualObjects(data.domain, @"domain"); + XCTAssertEqualObjects(data.localizedDescription, @"description"); +} + +- (void)testFWFWKScriptMessageDataFromWKScriptMessage { + WKScriptMessage *mockScriptMessage = OCMClassMock([WKScriptMessage class]); + OCMStub([mockScriptMessage name]).andReturn(@"name"); + OCMStub([mockScriptMessage body]).andReturn(@"message"); + + FWFWKScriptMessageData *data = FWFWKScriptMessageDataFromWKScriptMessage(mockScriptMessage); + XCTAssertEqualObjects(data.name, @"name"); + XCTAssertEqualObjects(data.body, @"message"); +} @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFNavigationDelegateHostApiTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFNavigationDelegateHostApiTests.m index 206137e301f5..570a1f73ad9b 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFNavigationDelegateHostApiTests.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFNavigationDelegateHostApiTests.m @@ -12,6 +12,38 @@ @interface FWFNavigationDelegateHostApiTests : XCTestCase @end @implementation FWFNavigationDelegateHostApiTests +/** + * Creates a partially mocked FWFNavigationDelegate and adds it to instanceManager. + * + * @param instanceManager Instance manager to add the delegate to. + * @param identifier Identifier for the delegate added to the instanceManager. + * + * @return A mock FWFNavigationDelegate. + */ +- (id)mockNavigationDelegateWithManager:(FWFInstanceManager *)instanceManager + identifier:(long)identifier { + FWFNavigationDelegate *navigationDelegate = [[FWFNavigationDelegate alloc] + initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger)) + instanceManager:instanceManager]; + + [instanceManager addDartCreatedInstance:navigationDelegate withIdentifier:0]; + return OCMPartialMock(navigationDelegate); +} + +/** + * Creates a mock FWFNavigationDelegateFlutterApiImpl with instanceManager. + * + * @param instanceManager Instance manager passed to the Flutter API. + * + * @return A mock FWFNavigationDelegateFlutterApiImpl. + */ +- (id)mockFlutterApiWithManager:(FWFInstanceManager *)instanceManager { + FWFNavigationDelegateFlutterApiImpl *flutterAPI = [[FWFNavigationDelegateFlutterApiImpl alloc] + initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger)) + instanceManager:instanceManager]; + return OCMPartialMock(flutterAPI); +} + - (void)testCreateWithIdentifier { FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init]; FWFNavigationDelegateHostApiImpl *hostAPI = [[FWFNavigationDelegateHostApiImpl alloc] @@ -29,31 +61,156 @@ - (void)testCreateWithIdentifier { - (void)testDidFinishNavigation { FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init]; - FWFNavigationDelegateHostApiImpl *hostAPI = [[FWFNavigationDelegateHostApiImpl alloc] - initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger)) - instanceManager:instanceManager]; - FlutterError *error; - [hostAPI createWithIdentifier:@0 error:&error]; - FWFNavigationDelegate *navigationDelegate = - (FWFNavigationDelegate *)[instanceManager instanceForIdentifier:0]; - id mockDelegate = OCMPartialMock(navigationDelegate); + FWFNavigationDelegate *mockDelegate = [self mockNavigationDelegateWithManager:instanceManager + identifier:0]; + FWFNavigationDelegateFlutterApiImpl *mockFlutterAPI = + [self mockFlutterApiWithManager:instanceManager]; - FWFNavigationDelegateFlutterApiImpl *flutterAPI = [[FWFNavigationDelegateFlutterApiImpl alloc] - initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger)) - instanceManager:instanceManager]; - id mockFlutterApi = OCMPartialMock(flutterAPI); - - OCMStub([mockDelegate navigationDelegateAPI]).andReturn(mockFlutterApi); + OCMStub([mockDelegate navigationDelegateAPI]).andReturn(mockFlutterAPI); WKWebView *mockWebView = OCMClassMock([WKWebView class]); OCMStub([mockWebView URL]).andReturn([NSURL URLWithString:@"https://flutter.dev/"]); [instanceManager addDartCreatedInstance:mockWebView withIdentifier:1]; [mockDelegate webView:mockWebView didFinishNavigation:OCMClassMock([WKNavigation class])]; - OCMVerify([mockFlutterApi didFinishNavigationForDelegateWithIdentifier:@0 + OCMVerify([mockFlutterAPI didFinishNavigationForDelegateWithIdentifier:@0 webViewIdentifier:@1 URL:@"https://flutter.dev/" completion:OCMOCK_ANY]); } + +- (void)testDidStartProvisionalNavigation { + 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]); + OCMStub([mockWebView URL]).andReturn([NSURL URLWithString:@"https://flutter.dev/"]); + [instanceManager addDartCreatedInstance:mockWebView withIdentifier:1]; + + [mockDelegate webView:mockWebView + didStartProvisionalNavigation:OCMClassMock([WKNavigation class])]; + OCMVerify([mockFlutterAPI + didStartProvisionalNavigationForDelegateWithIdentifier:@0 + webViewIdentifier:@1 + URL:@"https://flutter.dev/" + completion:OCMOCK_ANY]); +} + +- (void)testDecidePolicyForNavigationAction { + 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]; + + WKNavigationAction *mockNavigationAction = OCMClassMock([WKNavigationAction class]); + OCMStub([mockNavigationAction request]) + .andReturn([NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.flutter.dev"]]); + + WKFrameInfo *mockFrameInfo = OCMClassMock([WKFrameInfo class]); + OCMStub([mockFrameInfo isMainFrame]).andReturn(YES); + OCMStub([mockNavigationAction targetFrame]).andReturn(mockFrameInfo); + + OCMStub([mockFlutterAPI + decidePolicyForNavigationActionForDelegateWithIdentifier:@0 + webViewIdentifier:@1 + navigationAction: + [OCMArg isKindOfClass:[FWFWKNavigationActionData + class]] + completion: + ([OCMArg + invokeBlockWithArgs: + [FWFWKNavigationActionPolicyEnumData + makeWithValue: + FWFWKNavigationActionPolicyEnumCancel], + [NSNull null], nil])]); + + WKNavigationActionPolicy __block callbackPolicy = -1; + [mockDelegate webView:mockWebView + decidePolicyForNavigationAction:mockNavigationAction + decisionHandler:^(WKNavigationActionPolicy policy) { + callbackPolicy = policy; + }]; + XCTAssertEqual(callbackPolicy, WKNavigationActionPolicyCancel); +} + +- (void)testDidFailNavigation { + 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]; + + [mockDelegate webView:mockWebView + didFailNavigation:OCMClassMock([WKNavigation class]) + withError:[NSError errorWithDomain:@"domain" code:0 userInfo:nil]]; + OCMVerify([mockFlutterAPI + didFailNavigationForDelegateWithIdentifier:@0 + webViewIdentifier:@1 + error:[OCMArg isKindOfClass:[FWFNSErrorData class]] + completion:OCMOCK_ANY]); +} + +- (void)testDidFailProvisionalNavigation { + 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]; + + [mockDelegate webView:mockWebView + didFailProvisionalNavigation:OCMClassMock([WKNavigation class]) + withError:[NSError errorWithDomain:@"domain" code:0 userInfo:nil]]; + OCMVerify([mockFlutterAPI + didFailProvisionalNavigationForDelegateWithIdentifier:@0 + webViewIdentifier:@1 + error:[OCMArg isKindOfClass:[FWFNSErrorData + class]] + completion:OCMOCK_ANY]); +} + +- (void)testWebViewWebContentProcessDidTerminate { + 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]; + + [mockDelegate webViewWebContentProcessDidTerminate:mockWebView]; + OCMVerify([mockFlutterAPI + webViewWebContentProcessDidTerminateForDelegateWithIdentifier:@0 + webViewIdentifier:@1 + completion:OCMOCK_ANY]); +} @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFObjectHostApiTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFObjectHostApiTests.m index bdaeae4c09dc..b8e41d142331 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFObjectHostApiTests.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFObjectHostApiTests.m @@ -12,6 +12,37 @@ @interface FWFObjectHostApiTests : XCTestCase @end @implementation FWFObjectHostApiTests +/** + * Creates a partially mocked FWFObject and adds it to instanceManager. + * + * @param instanceManager Instance manager to add the delegate to. + * @param identifier Identifier for the delegate added to the instanceManager. + * + * @return A mock FWFObject. + */ +- (id)mockObjectWithManager:(FWFInstanceManager *)instanceManager identifier:(long)identifier { + FWFObject *object = + [[FWFObject alloc] initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger)) + instanceManager:instanceManager]; + + [instanceManager addDartCreatedInstance:object withIdentifier:0]; + return OCMPartialMock(object); +} + +/** + * Creates a mock FWFObjectFlutterApiImpl with instanceManager. + * + * @param instanceManager Instance manager passed to the Flutter API. + * + * @return A mock FWFObjectFlutterApiImpl. + */ +- (id)mockFlutterApiWithManager:(FWFInstanceManager *)instanceManager { + FWFObjectFlutterApiImpl *flutterAPI = [[FWFObjectFlutterApiImpl alloc] + initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger)) + instanceManager:instanceManager]; + return OCMPartialMock(flutterAPI); +} + - (void)testAddObserver { NSObject *mockObject = OCMClassMock([NSObject class]); @@ -82,4 +113,34 @@ - (void)testDispose { XCTAssertFalse([instanceManager containsInstance:object]); XCTAssertNil(error); } + +- (void)testObserveValueForKeyPath { + FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init]; + + FWFObject *mockObject = [self mockObjectWithManager:instanceManager identifier:0]; + FWFObjectFlutterApiImpl *mockFlutterAPI = [self mockFlutterApiWithManager:instanceManager]; + + OCMStub([mockObject objectApi]).andReturn(mockFlutterAPI); + + NSObject *object = [[NSObject alloc] init]; + [instanceManager addDartCreatedInstance:object withIdentifier:1]; + + [mockObject observeValueForKeyPath:@"keyPath" + ofObject:object + change:@{NSKeyValueChangeOldKey : @"key"} + context:nil]; + OCMVerify([mockFlutterAPI + observeValueForObjectWithIdentifier:@0 + keyPath:@"keyPath" + objectIdentifier:@1 + changeKeys:[OCMArg checkWithBlock:^BOOL( + NSArray + *value) { + return value[0].value == FWFNSKeyValueChangeKeyEnumOldValue; + }] + changeValues:[OCMArg checkWithBlock:^BOOL(id value) { + return [@"key" isEqual:value[0]]; + }] + completion:OCMOCK_ANY]); +} @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFScriptMessageHandlerHostApiTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFScriptMessageHandlerHostApiTests.m index b74d21114cc4..5a51e7b980f8 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFScriptMessageHandlerHostApiTests.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFScriptMessageHandlerHostApiTests.m @@ -12,6 +12,37 @@ @interface FWFScriptMessageHandlerHostApiTests : XCTestCase @end @implementation FWFScriptMessageHandlerHostApiTests +/** + * Creates a partially mocked FWFScriptMessageHandler and adds it to instanceManager. + * + * @param instanceManager Instance manager to add the delegate to. + * @param identifier Identifier for the delegate added to the instanceManager. + * + * @return A mock FWFScriptMessageHandler. + */ +- (id)mockHandlerWithManager:(FWFInstanceManager *)instanceManager identifier:(long)identifier { + FWFScriptMessageHandler *handler = [[FWFScriptMessageHandler alloc] + initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger)) + instanceManager:instanceManager]; + + [instanceManager addDartCreatedInstance:handler withIdentifier:0]; + return OCMPartialMock(handler); +} + +/** + * Creates a mock FWFScriptMessageHandlerFlutterApiImpl with instanceManager. + * + * @param instanceManager Instance manager passed to the Flutter API. + * + * @return A mock FWFScriptMessageHandlerFlutterApiImpl. + */ +- (id)mockFlutterApiWithManager:(FWFInstanceManager *)instanceManager { + FWFScriptMessageHandlerFlutterApiImpl *flutterAPI = [[FWFScriptMessageHandlerFlutterApiImpl alloc] + initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger)) + instanceManager:instanceManager]; + return OCMPartialMock(flutterAPI); +} + - (void)testCreateWithIdentifier { FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init]; FWFScriptMessageHandlerHostApiImpl *hostAPI = @@ -26,4 +57,30 @@ - (void)testCreateWithIdentifier { XCTAssertTrue([scriptMessageHandler conformsToProtocol:@protocol(WKScriptMessageHandler)]); XCTAssertNil(error); } + +- (void)testDidReceiveScriptMessageForHandler { + FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init]; + + FWFScriptMessageHandler *mockHandler = [self mockHandlerWithManager:instanceManager identifier:0]; + FWFScriptMessageHandlerFlutterApiImpl *mockFlutterAPI = + [self mockFlutterApiWithManager:instanceManager]; + + OCMStub([mockHandler scriptMessageHandlerAPI]).andReturn(mockFlutterAPI); + + WKUserContentController *userContentController = [[WKUserContentController alloc] init]; + [instanceManager addDartCreatedInstance:userContentController withIdentifier:1]; + + WKScriptMessage *mockScriptMessage = OCMClassMock([WKScriptMessage class]); + OCMStub([mockScriptMessage name]).andReturn(@"name"); + OCMStub([mockScriptMessage body]).andReturn(@"message"); + + [mockHandler userContentController:userContentController + didReceiveScriptMessage:mockScriptMessage]; + OCMVerify([mockFlutterAPI + didReceiveScriptMessageForHandlerWithIdentifier:@0 + userContentControllerIdentifier:@1 + message:[OCMArg isKindOfClass:[FWFWKScriptMessageData + class]] + completion:OCMOCK_ANY]); +} @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFUIDelegateHostApiTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFUIDelegateHostApiTests.m index 4ee36ae7c492..17cb4367b3aa 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFUIDelegateHostApiTests.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFUIDelegateHostApiTests.m @@ -12,6 +12,37 @@ @interface FWFUIDelegateHostApiTests : XCTestCase @end @implementation FWFUIDelegateHostApiTests +/** + * Creates a partially mocked FWFUIDelegate and adds it to instanceManager. + * + * @param instanceManager Instance manager to add the delegate to. + * @param identifier Identifier for the delegate added to the instanceManager. + * + * @return A mock FWFUIDelegate. + */ +- (id)mockDelegateWithManager:(FWFInstanceManager *)instanceManager identifier:(long)identifier { + FWFUIDelegate *delegate = [[FWFUIDelegate alloc] + initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger)) + instanceManager:instanceManager]; + + [instanceManager addDartCreatedInstance:delegate withIdentifier:0]; + return OCMPartialMock(delegate); +} + +/** + * Creates a mock FWFUIDelegateFlutterApiImpl with instanceManager. + * + * @param instanceManager Instance manager passed to the Flutter API. + * + * @return A mock FWFUIDelegateFlutterApiImpl. + */ +- (id)mockFlutterApiWithManager:(FWFInstanceManager *)instanceManager { + FWFUIDelegateFlutterApiImpl *flutterAPI = [[FWFUIDelegateFlutterApiImpl alloc] + initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger)) + instanceManager:instanceManager]; + return OCMPartialMock(flutterAPI); +} + - (void)testCreateWithIdentifier { FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init]; FWFUIDelegateHostApiImpl *hostAPI = @@ -24,4 +55,39 @@ - (void)testCreateWithIdentifier { XCTAssertTrue([delegate conformsToProtocol:@protocol(WKUIDelegate)]); XCTAssertNil(error); } + +- (void)testOnCreateWebViewForDelegateWithIdentifier { + FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init]; + + FWFUIDelegate *mockDelegate = [self mockDelegateWithManager:instanceManager identifier:0]; + FWFUIDelegateFlutterApiImpl *mockFlutterAPI = [self mockFlutterApiWithManager:instanceManager]; + + OCMStub([mockDelegate UIDelegateAPI]).andReturn(mockFlutterAPI); + + WKWebView *mockWebView = OCMClassMock([WKWebView class]); + [instanceManager addDartCreatedInstance:mockWebView withIdentifier:1]; + + WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; + [instanceManager addDartCreatedInstance:configuration withIdentifier:2]; + + WKNavigationAction *mockNavigationAction = OCMClassMock([WKNavigationAction class]); + OCMStub([mockNavigationAction request]) + .andReturn([NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.flutter.dev"]]); + + WKFrameInfo *mockFrameInfo = OCMClassMock([WKFrameInfo class]); + OCMStub([mockFrameInfo isMainFrame]).andReturn(YES); + OCMStub([mockNavigationAction targetFrame]).andReturn(mockFrameInfo); + + [mockDelegate webView:mockWebView + createWebViewWithConfiguration:configuration + forNavigationAction:mockNavigationAction + windowFeatures:OCMClassMock([WKWindowFeatures class])]; + OCMVerify([mockFlutterAPI + onCreateWebViewForDelegateWithIdentifier:@0 + webViewIdentifier:@1 + configurationIdentifier:@2 + navigationAction:[OCMArg + isKindOfClass:[FWFWKNavigationActionData class]] + completion:OCMOCK_ANY]); +} @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.h index 4cf24c67ac95..2863048726a9 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.h +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.h @@ -85,4 +85,70 @@ extern WKAudiovisualMediaTypes FWFWKAudiovisualMediaTypeFromEnumData( */ extern NSString *_Nullable FWFWKWebsiteDataTypeFromEnumData(FWFWKWebsiteDataTypeEnumData *data); +/** + * Converts a WKNavigationAction to an FWFWKNavigationActionData. + * + * @param action The object containing information to create a WKNavigationActionData. + * + * @return A FWFWKNavigationActionData. + */ +extern FWFWKNavigationActionData *FWFWKNavigationActionDataFromNavigationAction( + WKNavigationAction *action); + +/** + * Converts a NSURLRequest to an FWFNSUrlRequestData. + * + * @param request The object containing information to create a WKNavigationActionData. + * + * @return A FWFNSUrlRequestData. + */ +extern FWFNSUrlRequestData *FWFNSUrlRequestDataFromNSURLRequest(NSURLRequest *request); + +/** + * Converts a WKFrameInfo to an FWFWKFrameInfoData. + * + * @param info The object containing information to create a FWFWKFrameInfoData. + * + * @return A FWFWKFrameInfoData. + */ +extern FWFWKFrameInfoData *FWFWKFrameInfoDataFromWKFrameInfo(WKFrameInfo *info); + +/** + * Converts an FWFWKNavigationActionPolicyEnumData to a WKNavigationActionPolicy. + * + * @param data The data object containing information to create a WKNavigationActionPolicy. + * + * @return A WKNavigationActionPolicy or -1 if data could not be converted. + */ +extern WKNavigationActionPolicy FWFWKNavigationActionPolicyFromEnumData( + FWFWKNavigationActionPolicyEnumData *data); + +/** + * Converts a NSError to an FWFNSErrorData. + * + * @param error The object containing information to create a FWFNSErrorData. + * + * @return A FWFNSErrorData. + */ +extern FWFNSErrorData *FWFNSErrorDataFromNSError(NSError *error); + +/** + * Converts an NSKeyValueChangeKey to a FWFNSKeyValueChangeKeyEnumData. + * + * @param key The data object containing information to create a FWFNSKeyValueChangeKeyEnumData. + * + * @return A FWFNSKeyValueChangeKeyEnumData or nil if data could not be converted. + */ +extern FWFNSKeyValueChangeKeyEnumData *FWFNSKeyValueChangeKeyEnumDataFromNSKeyValueChangeKey( + NSKeyValueChangeKey key); + +/** + * Converts a WKScriptMessage to an FWFWKScriptMessageData. + * + * @param message The object containing information to create a FWFWKScriptMessageData. + * + * @return A FWFWKScriptMessageData. + */ +extern FWFWKScriptMessageData *FWFWKScriptMessageDataFromWKScriptMessage(WKScriptMessage *message); + NS_ASSUME_NONNULL_END diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.m index a06b3d79b38c..759bfedc1621 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.m @@ -153,3 +153,64 @@ WKAudiovisualMediaTypes FWFWKAudiovisualMediaTypeFromEnumData( return nil; } + +FWFWKNavigationActionData *FWFWKNavigationActionDataFromNavigationAction( + WKNavigationAction *action) { + return [FWFWKNavigationActionData + makeWithRequest:FWFNSUrlRequestDataFromNSURLRequest(action.request) + targetFrame:FWFWKFrameInfoDataFromWKFrameInfo(action.targetFrame)]; +} + +FWFNSUrlRequestData *FWFNSUrlRequestDataFromNSURLRequest(NSURLRequest *request) { + return [FWFNSUrlRequestData + makeWithUrl:request.URL.absoluteString + httpMethod:request.HTTPMethod + httpBody:request.HTTPBody + ? [FlutterStandardTypedData typedDataWithBytes:request.HTTPBody] + : nil + allHttpHeaderFields:request.allHTTPHeaderFields ? request.allHTTPHeaderFields : @{}]; +} + +FWFWKFrameInfoData *FWFWKFrameInfoDataFromWKFrameInfo(WKFrameInfo *info) { + return [FWFWKFrameInfoData makeWithIsMainFrame:@(info.isMainFrame)]; +} + +WKNavigationActionPolicy FWFWKNavigationActionPolicyFromEnumData( + FWFWKNavigationActionPolicyEnumData *data) { + switch (data.value) { + case FWFWKNavigationActionPolicyEnumAllow: + return WKNavigationActionPolicyAllow; + case FWFWKNavigationActionPolicyEnumCancel: + return WKNavigationActionPolicyCancel; + } + + return -1; +} + +FWFNSErrorData *FWFNSErrorDataFromNSError(NSError *error) { + return [FWFNSErrorData makeWithCode:@(error.code) + domain:error.domain + localizedDescription:error.localizedDescription]; +} + +FWFNSKeyValueChangeKeyEnumData *FWFNSKeyValueChangeKeyEnumDataFromNSKeyValueChangeKey( + NSKeyValueChangeKey key) { + if ([key isEqualToString:NSKeyValueChangeIndexesKey]) { + return [FWFNSKeyValueChangeKeyEnumData makeWithValue:FWFNSKeyValueChangeKeyEnumIndexes]; + } else if ([key isEqualToString:NSKeyValueChangeKindKey]) { + return [FWFNSKeyValueChangeKeyEnumData makeWithValue:FWFNSKeyValueChangeKeyEnumKind]; + } else if ([key isEqualToString:NSKeyValueChangeNewKey]) { + return [FWFNSKeyValueChangeKeyEnumData makeWithValue:FWFNSKeyValueChangeKeyEnumNewValue]; + } else if ([key isEqualToString:NSKeyValueChangeNotificationIsPriorKey]) { + return [FWFNSKeyValueChangeKeyEnumData + makeWithValue:FWFNSKeyValueChangeKeyEnumNotificationIsPrior]; + } else if ([key isEqualToString:NSKeyValueChangeOldKey]) { + return [FWFNSKeyValueChangeKeyEnumData makeWithValue:FWFNSKeyValueChangeKeyEnumOldValue]; + } + + return nil; +} + +FWFWKScriptMessageData *FWFWKScriptMessageDataFromWKScriptMessage(WKScriptMessage *message) { + return [FWFWKScriptMessageData makeWithName:message.name body:message.body]; +} diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h index b291f4167725..ebd29f5cacad 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h @@ -1,7 +1,7 @@ // 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. -// Autogenerated from Pigeon (v3.1.2), do not edit directly. +// Autogenerated from Pigeon (v3.1.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #import @protocol FlutterBinaryMessenger; @@ -79,12 +79,18 @@ typedef NS_ENUM(NSUInteger, FWFNSHttpCookiePropertyKeyEnum) { }; @class FWFNSKeyValueObservingOptionsEnumData; +@class FWFNSKeyValueChangeKeyEnumData; @class FWFWKUserScriptInjectionTimeEnumData; @class FWFWKAudiovisualMediaTypeEnumData; @class FWFWKWebsiteDataTypeEnumData; +@class FWFWKNavigationActionPolicyEnumData; @class FWFNSHttpCookiePropertyKeyEnumData; @class FWFNSUrlRequestData; @class FWFWKUserScriptData; +@class FWFWKNavigationActionData; +@class FWFWKFrameInfoData; +@class FWFNSErrorData; +@class FWFWKScriptMessageData; @class FWFNSHttpCookieData; @interface FWFNSKeyValueObservingOptionsEnumData : NSObject @@ -94,6 +100,13 @@ typedef NS_ENUM(NSUInteger, FWFNSHttpCookiePropertyKeyEnum) { @property(nonatomic, assign) FWFNSKeyValueObservingOptionsEnum value; @end +@interface FWFNSKeyValueChangeKeyEnumData : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithValue:(FWFNSKeyValueChangeKeyEnum)value; +@property(nonatomic, assign) FWFNSKeyValueChangeKeyEnum value; +@end + @interface FWFWKUserScriptInjectionTimeEnumData : NSObject /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; @@ -115,6 +128,13 @@ typedef NS_ENUM(NSUInteger, FWFNSHttpCookiePropertyKeyEnum) { @property(nonatomic, assign) FWFWKWebsiteDataTypeEnum value; @end +@interface FWFWKNavigationActionPolicyEnumData : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithValue:(FWFWKNavigationActionPolicyEnum)value; +@property(nonatomic, assign) FWFWKNavigationActionPolicyEnum value; +@end + @interface FWFNSHttpCookiePropertyKeyEnumData : NSObject /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; @@ -146,6 +166,41 @@ typedef NS_ENUM(NSUInteger, FWFNSHttpCookiePropertyKeyEnum) { @property(nonatomic, strong) NSNumber *isMainFrameOnly; @end +@interface FWFWKNavigationActionData : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithRequest:(FWFNSUrlRequestData *)request + targetFrame:(FWFWKFrameInfoData *)targetFrame; +@property(nonatomic, strong) FWFNSUrlRequestData *request; +@property(nonatomic, strong) FWFWKFrameInfoData *targetFrame; +@end + +@interface FWFWKFrameInfoData : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithIsMainFrame:(NSNumber *)isMainFrame; +@property(nonatomic, strong) NSNumber *isMainFrame; +@end + +@interface FWFNSErrorData : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithCode:(NSNumber *)code + domain:(NSString *)domain + localizedDescription:(NSString *)localizedDescription; +@property(nonatomic, strong) NSNumber *code; +@property(nonatomic, copy) NSString *domain; +@property(nonatomic, copy) NSString *localizedDescription; +@end + +@interface FWFWKScriptMessageData : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithName:(NSString *)name body:(id)body; +@property(nonatomic, copy) NSString *name; +@property(nonatomic, strong) id body; +@end + @interface FWFNSHttpCookieData : NSObject /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; @@ -298,6 +353,16 @@ extern void FWFWKScriptMessageHandlerHostApiSetup( id binaryMessenger, NSObject *_Nullable api); +/// The codec used by FWFWKScriptMessageHandlerFlutterApi. +NSObject *FWFWKScriptMessageHandlerFlutterApiGetCodec(void); + +@interface FWFWKScriptMessageHandlerFlutterApi : NSObject +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger; +- (void)didReceiveScriptMessageForHandlerWithIdentifier:(NSNumber *)identifier + userContentControllerIdentifier:(NSNumber *)userContentControllerIdentifier + message:(FWFWKScriptMessageData *)message + completion:(void (^)(NSError *_Nullable))completion; +@end /// The codec used by FWFWKNavigationDelegateHostApi. NSObject *FWFWKNavigationDelegateHostApiGetCodec(void); @@ -318,6 +383,33 @@ NSObject *FWFWKNavigationDelegateFlutterApiGetCodec(void); webViewIdentifier:(NSNumber *)webViewIdentifier URL:(nullable NSString *)url completion:(void (^)(NSError *_Nullable))completion; +- (void)didStartProvisionalNavigationForDelegateWithIdentifier:(NSNumber *)identifier + webViewIdentifier:(NSNumber *)webViewIdentifier + URL:(nullable NSString *)url + completion: + (void (^)(NSError *_Nullable))completion; +- (void) + decidePolicyForNavigationActionForDelegateWithIdentifier:(NSNumber *)identifier + webViewIdentifier:(NSNumber *)webViewIdentifier + navigationAction: + (FWFWKNavigationActionData *)navigationAction + completion: + (void (^)(FWFWKNavigationActionPolicyEnumData + *_Nullable, + NSError *_Nullable))completion; +- (void)didFailNavigationForDelegateWithIdentifier:(NSNumber *)identifier + webViewIdentifier:(NSNumber *)webViewIdentifier + error:(FWFNSErrorData *)error + completion:(void (^)(NSError *_Nullable))completion; +- (void)didFailProvisionalNavigationForDelegateWithIdentifier:(NSNumber *)identifier + webViewIdentifier:(NSNumber *)webViewIdentifier + error:(FWFNSErrorData *)error + completion: + (void (^)(NSError *_Nullable))completion; +- (void)webViewWebContentProcessDidTerminateForDelegateWithIdentifier:(NSNumber *)identifier + webViewIdentifier:(NSNumber *)webViewIdentifier + completion:(void (^)(NSError *_Nullable)) + completion; @end /// The codec used by FWFNSObjectHostApi. NSObject *FWFNSObjectHostApiGetCodec(void); @@ -345,6 +437,12 @@ NSObject *FWFNSObjectFlutterApiGetCodec(void); @interface FWFNSObjectFlutterApi : NSObject - (instancetype)initWithBinaryMessenger:(id)binaryMessenger; +- (void)observeValueForObjectWithIdentifier:(NSNumber *)identifier + keyPath:(NSString *)keyPath + objectIdentifier:(NSNumber *)objectIdentifier + changeKeys:(NSArray *)changeKeys + changeValues:(NSArray *)changeValues + completion:(void (^)(NSError *_Nullable))completion; @end /// The codec used by FWFWKWebViewHostApi. NSObject *FWFWKWebViewHostApiGetCodec(void); @@ -420,6 +518,17 @@ NSObject *FWFWKUIDelegateHostApiGetCodec(void); extern void FWFWKUIDelegateHostApiSetup(id binaryMessenger, NSObject *_Nullable api); +/// The codec used by FWFWKUIDelegateFlutterApi. +NSObject *FWFWKUIDelegateFlutterApiGetCodec(void); + +@interface FWFWKUIDelegateFlutterApi : NSObject +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger; +- (void)onCreateWebViewForDelegateWithIdentifier:(NSNumber *)identifier + webViewIdentifier:(NSNumber *)webViewIdentifier + configurationIdentifier:(NSNumber *)configurationIdentifier + navigationAction:(FWFWKNavigationActionData *)navigationAction + completion:(void (^)(NSError *_Nullable))completion; +@end /// The codec used by FWFWKHttpCookieStoreHostApi. NSObject *FWFWKHttpCookieStoreHostApiGetCodec(void); diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m index f936d151ddd3..592fa87ac9d1 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m @@ -1,7 +1,7 @@ // 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. -// Autogenerated from Pigeon (v3.1.2), do not edit directly. +// Autogenerated from Pigeon (v3.1.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #import "FWFGeneratedWebKitApis.h" #import @@ -37,6 +37,10 @@ @interface FWFNSKeyValueObservingOptionsEnumData () + (FWFNSKeyValueObservingOptionsEnumData *)fromMap:(NSDictionary *)dict; - (NSDictionary *)toMap; @end +@interface FWFNSKeyValueChangeKeyEnumData () ++ (FWFNSKeyValueChangeKeyEnumData *)fromMap:(NSDictionary *)dict; +- (NSDictionary *)toMap; +@end @interface FWFWKUserScriptInjectionTimeEnumData () + (FWFWKUserScriptInjectionTimeEnumData *)fromMap:(NSDictionary *)dict; - (NSDictionary *)toMap; @@ -49,6 +53,10 @@ @interface FWFWKWebsiteDataTypeEnumData () + (FWFWKWebsiteDataTypeEnumData *)fromMap:(NSDictionary *)dict; - (NSDictionary *)toMap; @end +@interface FWFWKNavigationActionPolicyEnumData () ++ (FWFWKNavigationActionPolicyEnumData *)fromMap:(NSDictionary *)dict; +- (NSDictionary *)toMap; +@end @interface FWFNSHttpCookiePropertyKeyEnumData () + (FWFNSHttpCookiePropertyKeyEnumData *)fromMap:(NSDictionary *)dict; - (NSDictionary *)toMap; @@ -61,6 +69,22 @@ @interface FWFWKUserScriptData () + (FWFWKUserScriptData *)fromMap:(NSDictionary *)dict; - (NSDictionary *)toMap; @end +@interface FWFWKNavigationActionData () ++ (FWFWKNavigationActionData *)fromMap:(NSDictionary *)dict; +- (NSDictionary *)toMap; +@end +@interface FWFWKFrameInfoData () ++ (FWFWKFrameInfoData *)fromMap:(NSDictionary *)dict; +- (NSDictionary *)toMap; +@end +@interface FWFNSErrorData () ++ (FWFNSErrorData *)fromMap:(NSDictionary *)dict; +- (NSDictionary *)toMap; +@end +@interface FWFWKScriptMessageData () ++ (FWFWKScriptMessageData *)fromMap:(NSDictionary *)dict; +- (NSDictionary *)toMap; +@end @interface FWFNSHttpCookieData () + (FWFNSHttpCookieData *)fromMap:(NSDictionary *)dict; - (NSDictionary *)toMap; @@ -86,6 +110,24 @@ - (NSDictionary *)toMap { } @end +@implementation FWFNSKeyValueChangeKeyEnumData ++ (instancetype)makeWithValue:(FWFNSKeyValueChangeKeyEnum)value { + FWFNSKeyValueChangeKeyEnumData *pigeonResult = [[FWFNSKeyValueChangeKeyEnumData alloc] init]; + pigeonResult.value = value; + return pigeonResult; +} ++ (FWFNSKeyValueChangeKeyEnumData *)fromMap:(NSDictionary *)dict { + FWFNSKeyValueChangeKeyEnumData *pigeonResult = [[FWFNSKeyValueChangeKeyEnumData alloc] init]; + pigeonResult.value = [GetNullableObject(dict, @"value") integerValue]; + return pigeonResult; +} +- (NSDictionary *)toMap { + return @{ + @"value" : @(self.value), + }; +} +@end + @implementation FWFWKUserScriptInjectionTimeEnumData + (instancetype)makeWithValue:(FWFWKUserScriptInjectionTimeEnum)value { FWFWKUserScriptInjectionTimeEnumData *pigeonResult = @@ -144,6 +186,26 @@ - (NSDictionary *)toMap { } @end +@implementation FWFWKNavigationActionPolicyEnumData ++ (instancetype)makeWithValue:(FWFWKNavigationActionPolicyEnum)value { + FWFWKNavigationActionPolicyEnumData *pigeonResult = + [[FWFWKNavigationActionPolicyEnumData alloc] init]; + pigeonResult.value = value; + return pigeonResult; +} ++ (FWFWKNavigationActionPolicyEnumData *)fromMap:(NSDictionary *)dict { + FWFWKNavigationActionPolicyEnumData *pigeonResult = + [[FWFWKNavigationActionPolicyEnumData alloc] init]; + pigeonResult.value = [GetNullableObject(dict, @"value") integerValue]; + return pigeonResult; +} +- (NSDictionary *)toMap { + return @{ + @"value" : @(self.value), + }; +} +@end + @implementation FWFNSHttpCookiePropertyKeyEnumData + (instancetype)makeWithValue:(FWFNSHttpCookiePropertyKeyEnum)value { FWFNSHttpCookiePropertyKeyEnumData *pigeonResult = @@ -225,6 +287,100 @@ - (NSDictionary *)toMap { } @end +@implementation FWFWKNavigationActionData ++ (instancetype)makeWithRequest:(FWFNSUrlRequestData *)request + targetFrame:(FWFWKFrameInfoData *)targetFrame { + FWFWKNavigationActionData *pigeonResult = [[FWFWKNavigationActionData alloc] init]; + pigeonResult.request = request; + pigeonResult.targetFrame = targetFrame; + return pigeonResult; +} ++ (FWFWKNavigationActionData *)fromMap:(NSDictionary *)dict { + FWFWKNavigationActionData *pigeonResult = [[FWFWKNavigationActionData alloc] init]; + pigeonResult.request = [FWFNSUrlRequestData fromMap:GetNullableObject(dict, @"request")]; + NSAssert(pigeonResult.request != nil, @""); + pigeonResult.targetFrame = [FWFWKFrameInfoData fromMap:GetNullableObject(dict, @"targetFrame")]; + NSAssert(pigeonResult.targetFrame != nil, @""); + return pigeonResult; +} +- (NSDictionary *)toMap { + return @{ + @"request" : (self.request ? [self.request toMap] : [NSNull null]), + @"targetFrame" : (self.targetFrame ? [self.targetFrame toMap] : [NSNull null]), + }; +} +@end + +@implementation FWFWKFrameInfoData ++ (instancetype)makeWithIsMainFrame:(NSNumber *)isMainFrame { + FWFWKFrameInfoData *pigeonResult = [[FWFWKFrameInfoData alloc] init]; + pigeonResult.isMainFrame = isMainFrame; + return pigeonResult; +} ++ (FWFWKFrameInfoData *)fromMap:(NSDictionary *)dict { + FWFWKFrameInfoData *pigeonResult = [[FWFWKFrameInfoData alloc] init]; + pigeonResult.isMainFrame = GetNullableObject(dict, @"isMainFrame"); + NSAssert(pigeonResult.isMainFrame != nil, @""); + return pigeonResult; +} +- (NSDictionary *)toMap { + return @{ + @"isMainFrame" : (self.isMainFrame ?: [NSNull null]), + }; +} +@end + +@implementation FWFNSErrorData ++ (instancetype)makeWithCode:(NSNumber *)code + domain:(NSString *)domain + localizedDescription:(NSString *)localizedDescription { + FWFNSErrorData *pigeonResult = [[FWFNSErrorData alloc] init]; + pigeonResult.code = code; + pigeonResult.domain = domain; + pigeonResult.localizedDescription = localizedDescription; + return pigeonResult; +} ++ (FWFNSErrorData *)fromMap:(NSDictionary *)dict { + FWFNSErrorData *pigeonResult = [[FWFNSErrorData alloc] init]; + pigeonResult.code = GetNullableObject(dict, @"code"); + NSAssert(pigeonResult.code != nil, @""); + pigeonResult.domain = GetNullableObject(dict, @"domain"); + NSAssert(pigeonResult.domain != nil, @""); + pigeonResult.localizedDescription = GetNullableObject(dict, @"localizedDescription"); + NSAssert(pigeonResult.localizedDescription != nil, @""); + return pigeonResult; +} +- (NSDictionary *)toMap { + return @{ + @"code" : (self.code ?: [NSNull null]), + @"domain" : (self.domain ?: [NSNull null]), + @"localizedDescription" : (self.localizedDescription ?: [NSNull null]), + }; +} +@end + +@implementation FWFWKScriptMessageData ++ (instancetype)makeWithName:(NSString *)name body:(id)body { + FWFWKScriptMessageData *pigeonResult = [[FWFWKScriptMessageData alloc] init]; + pigeonResult.name = name; + pigeonResult.body = body; + return pigeonResult; +} ++ (FWFWKScriptMessageData *)fromMap:(NSDictionary *)dict { + FWFWKScriptMessageData *pigeonResult = [[FWFWKScriptMessageData alloc] init]; + pigeonResult.name = GetNullableObject(dict, @"name"); + NSAssert(pigeonResult.name != nil, @""); + pigeonResult.body = GetNullableObject(dict, @"body"); + return pigeonResult; +} +- (NSDictionary *)toMap { + return @{ + @"name" : (self.name ?: [NSNull null]), + @"body" : (self.body ?: [NSNull null]), + }; +} +@end + @implementation FWFNSHttpCookieData + (instancetype)makeWithPropertyKeys:(NSArray *)propertyKeys propertyValues:(NSArray *)propertyValues { @@ -1095,6 +1251,87 @@ void FWFWKScriptMessageHandlerHostApiSetup(id binaryMess } } } +@interface FWFWKScriptMessageHandlerFlutterApiCodecReader : FlutterStandardReader +@end +@implementation FWFWKScriptMessageHandlerFlutterApiCodecReader +- (nullable id)readValueOfType:(UInt8)type { + switch (type) { + case 128: + return [FWFWKScriptMessageData fromMap:[self readValue]]; + + default: + return [super readValueOfType:type]; + } +} +@end + +@interface FWFWKScriptMessageHandlerFlutterApiCodecWriter : FlutterStandardWriter +@end +@implementation FWFWKScriptMessageHandlerFlutterApiCodecWriter +- (void)writeValue:(id)value { + if ([value isKindOfClass:[FWFWKScriptMessageData class]]) { + [self writeByte:128]; + [self writeValue:[value toMap]]; + } else { + [super writeValue:value]; + } +} +@end + +@interface FWFWKScriptMessageHandlerFlutterApiCodecReaderWriter : FlutterStandardReaderWriter +@end +@implementation FWFWKScriptMessageHandlerFlutterApiCodecReaderWriter +- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data { + return [[FWFWKScriptMessageHandlerFlutterApiCodecWriter alloc] initWithData:data]; +} +- (FlutterStandardReader *)readerWithData:(NSData *)data { + return [[FWFWKScriptMessageHandlerFlutterApiCodecReader alloc] initWithData:data]; +} +@end + +NSObject *FWFWKScriptMessageHandlerFlutterApiGetCodec() { + static dispatch_once_t sPred = 0; + static FlutterStandardMessageCodec *sSharedObject = nil; + dispatch_once(&sPred, ^{ + FWFWKScriptMessageHandlerFlutterApiCodecReaderWriter *readerWriter = + [[FWFWKScriptMessageHandlerFlutterApiCodecReaderWriter alloc] init]; + sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; + }); + return sSharedObject; +} + +@interface FWFWKScriptMessageHandlerFlutterApi () +@property(nonatomic, strong) NSObject *binaryMessenger; +@end + +@implementation FWFWKScriptMessageHandlerFlutterApi + +- (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger { + self = [super init]; + if (self) { + _binaryMessenger = binaryMessenger; + } + return self; +} +- (void)didReceiveScriptMessageForHandlerWithIdentifier:(NSNumber *)arg_identifier + userContentControllerIdentifier: + (NSNumber *)arg_userContentControllerIdentifier + message:(FWFWKScriptMessageData *)arg_message + completion:(void (^)(NSError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName: + @"dev.flutter.pigeon.WKScriptMessageHandlerFlutterApi.didReceiveScriptMessage" + binaryMessenger:self.binaryMessenger + codec:FWFWKScriptMessageHandlerFlutterApiGetCodec()]; + [channel sendMessage:@[ + arg_identifier ?: [NSNull null], arg_userContentControllerIdentifier ?: [NSNull null], + arg_message ?: [NSNull null] + ] + reply:^(id reply) { + completion(nil); + }]; +} +@end @interface FWFWKNavigationDelegateHostApiCodecReader : FlutterStandardReader @end @implementation FWFWKNavigationDelegateHostApiCodecReader @@ -1154,11 +1391,52 @@ void FWFWKNavigationDelegateHostApiSetup(id binaryMessen @interface FWFWKNavigationDelegateFlutterApiCodecReader : FlutterStandardReader @end @implementation FWFWKNavigationDelegateFlutterApiCodecReader +- (nullable id)readValueOfType:(UInt8)type { + switch (type) { + case 128: + return [FWFNSErrorData fromMap:[self readValue]]; + + case 129: + return [FWFNSUrlRequestData fromMap:[self readValue]]; + + case 130: + return [FWFWKFrameInfoData fromMap:[self readValue]]; + + case 131: + return [FWFWKNavigationActionData fromMap:[self readValue]]; + + case 132: + return [FWFWKNavigationActionPolicyEnumData fromMap:[self readValue]]; + + default: + return [super readValueOfType:type]; + } +} @end @interface FWFWKNavigationDelegateFlutterApiCodecWriter : FlutterStandardWriter @end @implementation FWFWKNavigationDelegateFlutterApiCodecWriter +- (void)writeValue:(id)value { + if ([value isKindOfClass:[FWFNSErrorData class]]) { + [self writeByte:128]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) { + [self writeByte:129]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) { + [self writeByte:130]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) { + [self writeByte:131]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) { + [self writeByte:132]; + [self writeValue:[value toMap]]; + } else { + [super writeValue:value]; + } +} @end @interface FWFWKNavigationDelegateFlutterApiCodecReaderWriter : FlutterStandardReaderWriter @@ -1213,6 +1491,96 @@ - (void)didFinishNavigationForDelegateWithIdentifier:(NSNumber *)arg_identifier completion(nil); }]; } +- (void)didStartProvisionalNavigationForDelegateWithIdentifier:(NSNumber *)arg_identifier + webViewIdentifier:(NSNumber *)arg_webViewIdentifier + URL:(nullable NSString *)arg_url + completion: + (void (^)(NSError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName: + @"dev.flutter.pigeon.WKNavigationDelegateFlutterApi.didStartProvisionalNavigation" + binaryMessenger:self.binaryMessenger + codec:FWFWKNavigationDelegateFlutterApiGetCodec()]; + [channel sendMessage:@[ + arg_identifier ?: [NSNull null], arg_webViewIdentifier ?: [NSNull null], + arg_url ?: [NSNull null] + ] + reply:^(id reply) { + completion(nil); + }]; +} +- (void) + decidePolicyForNavigationActionForDelegateWithIdentifier:(NSNumber *)arg_identifier + webViewIdentifier:(NSNumber *)arg_webViewIdentifier + navigationAction: + (FWFWKNavigationActionData *)arg_navigationAction + completion: + (void (^)(FWFWKNavigationActionPolicyEnumData + *_Nullable, + NSError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName: + @"dev.flutter.pigeon.WKNavigationDelegateFlutterApi.decidePolicyForNavigationAction" + binaryMessenger:self.binaryMessenger + codec:FWFWKNavigationDelegateFlutterApiGetCodec()]; + [channel sendMessage:@[ + arg_identifier ?: [NSNull null], arg_webViewIdentifier ?: [NSNull null], + arg_navigationAction ?: [NSNull null] + ] + reply:^(id reply) { + FWFWKNavigationActionPolicyEnumData *output = reply; + completion(output, nil); + }]; +} +- (void)didFailNavigationForDelegateWithIdentifier:(NSNumber *)arg_identifier + webViewIdentifier:(NSNumber *)arg_webViewIdentifier + error:(FWFNSErrorData *)arg_error + completion:(void (^)(NSError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:@"dev.flutter.pigeon.WKNavigationDelegateFlutterApi.didFailNavigation" + binaryMessenger:self.binaryMessenger + codec:FWFWKNavigationDelegateFlutterApiGetCodec()]; + [channel sendMessage:@[ + arg_identifier ?: [NSNull null], arg_webViewIdentifier ?: [NSNull null], + arg_error ?: [NSNull null] + ] + reply:^(id reply) { + completion(nil); + }]; +} +- (void)didFailProvisionalNavigationForDelegateWithIdentifier:(NSNumber *)arg_identifier + webViewIdentifier:(NSNumber *)arg_webViewIdentifier + error:(FWFNSErrorData *)arg_error + completion: + (void (^)(NSError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName: + @"dev.flutter.pigeon.WKNavigationDelegateFlutterApi.didFailProvisionalNavigation" + binaryMessenger:self.binaryMessenger + codec:FWFWKNavigationDelegateFlutterApiGetCodec()]; + [channel sendMessage:@[ + arg_identifier ?: [NSNull null], arg_webViewIdentifier ?: [NSNull null], + arg_error ?: [NSNull null] + ] + reply:^(id reply) { + completion(nil); + }]; +} +- (void)webViewWebContentProcessDidTerminateForDelegateWithIdentifier:(NSNumber *)arg_identifier + webViewIdentifier: + (NSNumber *)arg_webViewIdentifier + completion:(void (^)(NSError *_Nullable)) + completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName: + @"dev.flutter.pigeon.WKNavigationDelegateFlutterApi.webViewWebContentProcessDidTerminate" + binaryMessenger:self.binaryMessenger + codec:FWFWKNavigationDelegateFlutterApiGetCodec()]; + [channel sendMessage:@[ arg_identifier ?: [NSNull null], arg_webViewIdentifier ?: [NSNull null] ] + reply:^(id reply) { + completion(nil); + }]; +} @end @interface FWFNSObjectHostApiCodecReader : FlutterStandardReader @end @@ -1350,11 +1718,106 @@ void FWFNSObjectHostApiSetup(id binaryMessenger, @interface FWFNSObjectFlutterApiCodecReader : FlutterStandardReader @end @implementation FWFNSObjectFlutterApiCodecReader +- (nullable id)readValueOfType:(UInt8)type { + switch (type) { + case 128: + return [FWFNSErrorData fromMap:[self readValue]]; + + case 129: + return [FWFNSHttpCookieData fromMap:[self readValue]]; + + case 130: + return [FWFNSHttpCookiePropertyKeyEnumData fromMap:[self readValue]]; + + case 131: + return [FWFNSKeyValueChangeKeyEnumData fromMap:[self readValue]]; + + case 132: + return [FWFNSKeyValueObservingOptionsEnumData fromMap:[self readValue]]; + + case 133: + return [FWFNSUrlRequestData fromMap:[self readValue]]; + + case 134: + return [FWFWKAudiovisualMediaTypeEnumData fromMap:[self readValue]]; + + case 135: + return [FWFWKFrameInfoData fromMap:[self readValue]]; + + case 136: + return [FWFWKNavigationActionData fromMap:[self readValue]]; + + case 137: + return [FWFWKNavigationActionPolicyEnumData fromMap:[self readValue]]; + + case 138: + return [FWFWKScriptMessageData fromMap:[self readValue]]; + + case 139: + return [FWFWKUserScriptData fromMap:[self readValue]]; + + case 140: + return [FWFWKUserScriptInjectionTimeEnumData fromMap:[self readValue]]; + + case 141: + return [FWFWKWebsiteDataTypeEnumData fromMap:[self readValue]]; + + default: + return [super readValueOfType:type]; + } +} @end @interface FWFNSObjectFlutterApiCodecWriter : FlutterStandardWriter @end @implementation FWFNSObjectFlutterApiCodecWriter +- (void)writeValue:(id)value { + if ([value isKindOfClass:[FWFNSErrorData class]]) { + [self writeByte:128]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFNSHttpCookieData class]]) { + [self writeByte:129]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFNSHttpCookiePropertyKeyEnumData class]]) { + [self writeByte:130]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFNSKeyValueChangeKeyEnumData class]]) { + [self writeByte:131]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFNSKeyValueObservingOptionsEnumData class]]) { + [self writeByte:132]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) { + [self writeByte:133]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKAudiovisualMediaTypeEnumData class]]) { + [self writeByte:134]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) { + [self writeByte:135]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) { + [self writeByte:136]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) { + [self writeByte:137]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKScriptMessageData class]]) { + [self writeByte:138]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKUserScriptData class]]) { + [self writeByte:139]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKUserScriptInjectionTimeEnumData class]]) { + [self writeByte:140]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKWebsiteDataTypeEnumData class]]) { + [self writeByte:141]; + [self writeValue:[value toMap]]; + } else { + [super writeValue:value]; + } +} @end @interface FWFNSObjectFlutterApiCodecReaderWriter : FlutterStandardReaderWriter @@ -1392,6 +1855,26 @@ - (instancetype)initWithBinaryMessenger:(NSObject *)bina } return self; } +- (void)observeValueForObjectWithIdentifier:(NSNumber *)arg_identifier + keyPath:(NSString *)arg_keyPath + objectIdentifier:(NSNumber *)arg_objectIdentifier + changeKeys: + (NSArray *)arg_changeKeys + changeValues:(NSArray *)arg_changeValues + completion:(void (^)(NSError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:@"dev.flutter.pigeon.NSObjectFlutterApi.observeValue" + binaryMessenger:self.binaryMessenger + codec:FWFNSObjectFlutterApiGetCodec()]; + [channel sendMessage:@[ + arg_identifier ?: [NSNull null], arg_keyPath ?: [NSNull null], + arg_objectIdentifier ?: [NSNull null], arg_changeKeys ?: [NSNull null], + arg_changeValues ?: [NSNull null] + ] + reply:^(id reply) { + completion(nil); + }]; +} @end @interface FWFWKWebViewHostApiCodecReader : FlutterStandardReader @end @@ -1399,27 +1882,45 @@ @implementation FWFWKWebViewHostApiCodecReader - (nullable id)readValueOfType:(UInt8)type { switch (type) { case 128: - return [FWFNSHttpCookieData fromMap:[self readValue]]; + return [FWFNSErrorData fromMap:[self readValue]]; case 129: - return [FWFNSHttpCookiePropertyKeyEnumData fromMap:[self readValue]]; + return [FWFNSHttpCookieData fromMap:[self readValue]]; case 130: - return [FWFNSKeyValueObservingOptionsEnumData fromMap:[self readValue]]; + return [FWFNSHttpCookiePropertyKeyEnumData fromMap:[self readValue]]; case 131: - return [FWFNSUrlRequestData fromMap:[self readValue]]; + return [FWFNSKeyValueChangeKeyEnumData fromMap:[self readValue]]; case 132: - return [FWFWKAudiovisualMediaTypeEnumData fromMap:[self readValue]]; + return [FWFNSKeyValueObservingOptionsEnumData fromMap:[self readValue]]; case 133: - return [FWFWKUserScriptData fromMap:[self readValue]]; + return [FWFNSUrlRequestData fromMap:[self readValue]]; case 134: - return [FWFWKUserScriptInjectionTimeEnumData fromMap:[self readValue]]; + return [FWFWKAudiovisualMediaTypeEnumData fromMap:[self readValue]]; case 135: + return [FWFWKFrameInfoData fromMap:[self readValue]]; + + case 136: + return [FWFWKNavigationActionData fromMap:[self readValue]]; + + case 137: + return [FWFWKNavigationActionPolicyEnumData fromMap:[self readValue]]; + + case 138: + return [FWFWKScriptMessageData fromMap:[self readValue]]; + + case 139: + return [FWFWKUserScriptData fromMap:[self readValue]]; + + case 140: + return [FWFWKUserScriptInjectionTimeEnumData fromMap:[self readValue]]; + + case 141: return [FWFWKWebsiteDataTypeEnumData fromMap:[self readValue]]; default: @@ -1432,30 +1933,48 @@ @interface FWFWKWebViewHostApiCodecWriter : FlutterStandardWriter @end @implementation FWFWKWebViewHostApiCodecWriter - (void)writeValue:(id)value { - if ([value isKindOfClass:[FWFNSHttpCookieData class]]) { + if ([value isKindOfClass:[FWFNSErrorData class]]) { [self writeByte:128]; [self writeValue:[value toMap]]; - } else if ([value isKindOfClass:[FWFNSHttpCookiePropertyKeyEnumData class]]) { + } else if ([value isKindOfClass:[FWFNSHttpCookieData class]]) { [self writeByte:129]; [self writeValue:[value toMap]]; - } else if ([value isKindOfClass:[FWFNSKeyValueObservingOptionsEnumData class]]) { + } else if ([value isKindOfClass:[FWFNSHttpCookiePropertyKeyEnumData class]]) { [self writeByte:130]; [self writeValue:[value toMap]]; - } else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) { + } else if ([value isKindOfClass:[FWFNSKeyValueChangeKeyEnumData class]]) { [self writeByte:131]; [self writeValue:[value toMap]]; - } else if ([value isKindOfClass:[FWFWKAudiovisualMediaTypeEnumData class]]) { + } else if ([value isKindOfClass:[FWFNSKeyValueObservingOptionsEnumData class]]) { [self writeByte:132]; [self writeValue:[value toMap]]; - } else if ([value isKindOfClass:[FWFWKUserScriptData class]]) { + } else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) { [self writeByte:133]; [self writeValue:[value toMap]]; - } else if ([value isKindOfClass:[FWFWKUserScriptInjectionTimeEnumData class]]) { + } else if ([value isKindOfClass:[FWFWKAudiovisualMediaTypeEnumData class]]) { [self writeByte:134]; [self writeValue:[value toMap]]; - } else if ([value isKindOfClass:[FWFWKWebsiteDataTypeEnumData class]]) { + } else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) { [self writeByte:135]; [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) { + [self writeByte:136]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) { + [self writeByte:137]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKScriptMessageData class]]) { + [self writeByte:138]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKUserScriptData class]]) { + [self writeByte:139]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKUserScriptInjectionTimeEnumData class]]) { + [self writeByte:140]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKWebsiteDataTypeEnumData class]]) { + [self writeByte:141]; + [self writeValue:[value toMap]]; } else { [super writeValue:value]; } @@ -1967,6 +2486,98 @@ void FWFWKUIDelegateHostApiSetup(id binaryMessenger, } } } +@interface FWFWKUIDelegateFlutterApiCodecReader : FlutterStandardReader +@end +@implementation FWFWKUIDelegateFlutterApiCodecReader +- (nullable id)readValueOfType:(UInt8)type { + switch (type) { + case 128: + return [FWFNSUrlRequestData fromMap:[self readValue]]; + + case 129: + return [FWFWKFrameInfoData fromMap:[self readValue]]; + + case 130: + return [FWFWKNavigationActionData fromMap:[self readValue]]; + + default: + return [super readValueOfType:type]; + } +} +@end + +@interface FWFWKUIDelegateFlutterApiCodecWriter : FlutterStandardWriter +@end +@implementation FWFWKUIDelegateFlutterApiCodecWriter +- (void)writeValue:(id)value { + if ([value isKindOfClass:[FWFNSUrlRequestData class]]) { + [self writeByte:128]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) { + [self writeByte:129]; + [self writeValue:[value toMap]]; + } else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) { + [self writeByte:130]; + [self writeValue:[value toMap]]; + } else { + [super writeValue:value]; + } +} +@end + +@interface FWFWKUIDelegateFlutterApiCodecReaderWriter : FlutterStandardReaderWriter +@end +@implementation FWFWKUIDelegateFlutterApiCodecReaderWriter +- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data { + return [[FWFWKUIDelegateFlutterApiCodecWriter alloc] initWithData:data]; +} +- (FlutterStandardReader *)readerWithData:(NSData *)data { + return [[FWFWKUIDelegateFlutterApiCodecReader alloc] initWithData:data]; +} +@end + +NSObject *FWFWKUIDelegateFlutterApiGetCodec() { + static dispatch_once_t sPred = 0; + static FlutterStandardMessageCodec *sSharedObject = nil; + dispatch_once(&sPred, ^{ + FWFWKUIDelegateFlutterApiCodecReaderWriter *readerWriter = + [[FWFWKUIDelegateFlutterApiCodecReaderWriter alloc] init]; + sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; + }); + return sSharedObject; +} + +@interface FWFWKUIDelegateFlutterApi () +@property(nonatomic, strong) NSObject *binaryMessenger; +@end + +@implementation FWFWKUIDelegateFlutterApi + +- (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger { + self = [super init]; + if (self) { + _binaryMessenger = binaryMessenger; + } + return self; +} +- (void)onCreateWebViewForDelegateWithIdentifier:(NSNumber *)arg_identifier + webViewIdentifier:(NSNumber *)arg_webViewIdentifier + configurationIdentifier:(NSNumber *)arg_configurationIdentifier + navigationAction:(FWFWKNavigationActionData *)arg_navigationAction + completion:(void (^)(NSError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:@"dev.flutter.pigeon.WKUIDelegateFlutterApi.onCreateWebView" + binaryMessenger:self.binaryMessenger + codec:FWFWKUIDelegateFlutterApiGetCodec()]; + [channel sendMessage:@[ + arg_identifier ?: [NSNull null], arg_webViewIdentifier ?: [NSNull null], + arg_configurationIdentifier ?: [NSNull null], arg_navigationAction ?: [NSNull null] + ] + reply:^(id reply) { + completion(nil); + }]; +} +@end @interface FWFWKHttpCookieStoreHostApiCodecReader : FlutterStandardReader @end @implementation FWFWKHttpCookieStoreHostApiCodecReader diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFNavigationDelegateHostApi.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFNavigationDelegateHostApi.h index 2ac599603152..da5939a3abed 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFNavigationDelegateHostApi.h +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFNavigationDelegateHostApi.h @@ -26,7 +26,9 @@ NS_ASSUME_NONNULL_BEGIN * Implementation of WKNavigationDelegate for FWFNavigationDelegateHostApiImpl. */ @interface FWFNavigationDelegate : FWFObject -@property(readonly, nonnull) FWFNavigationDelegateFlutterApiImpl *navigationDelegateAPI; +@property(readonly, nonnull, nonatomic) FWFNavigationDelegateFlutterApiImpl *navigationDelegateAPI; +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger + instanceManager:(FWFInstanceManager *)instanceManager; @end /** diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFNavigationDelegateHostApi.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFNavigationDelegateHostApi.m index be651c942c0e..6946783088d5 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFNavigationDelegateHostApi.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFNavigationDelegateHostApi.m @@ -3,6 +3,7 @@ // found in the LICENSE file. #import "FWFNavigationDelegateHostApi.h" +#import "FWFDataConverters.h" #import "FWFWebViewConfigurationHostApi.h" @interface FWFNavigationDelegateFlutterApiImpl () @@ -26,15 +27,82 @@ - (long)identifierForDelegate:(FWFNavigationDelegate *)instance { - (void)didFinishNavigationForDelegate:(FWFNavigationDelegate *)instance webView:(WKWebView *)webView - URL:(NSString *)URL { + URL:(NSString *)URL + completion:(void (^)(NSError *_Nullable))completion { + NSNumber *webViewIdentifier = + @([self.instanceManager identifierWithStrongReferenceForInstance:webView]); [self didFinishNavigationForDelegateWithIdentifier:@([self identifierForDelegate:instance]) - webViewIdentifier: - @([self.instanceManager - identifierWithStrongReferenceForInstance:webView]) + webViewIdentifier:webViewIdentifier URL:URL - completion:^(NSError *error) { - NSAssert(!error, @"%@", error); - }]; + completion:completion]; +} + +- (void)didStartProvisionalNavigationForDelegate:(FWFNavigationDelegate *)instance + webView:(WKWebView *)webView + URL:(NSString *)URL + completion:(void (^)(NSError *_Nullable))completion { + NSNumber *webViewIdentifier = + @([self.instanceManager identifierWithStrongReferenceForInstance:webView]); + [self didStartProvisionalNavigationForDelegateWithIdentifier:@([self + identifierForDelegate:instance]) + webViewIdentifier:webViewIdentifier + URL:URL + completion:completion]; +} + +- (void) + decidePolicyForNavigationActionForDelegate:(FWFNavigationDelegate *)instance + webView:(WKWebView *)webView + navigationAction:(WKNavigationAction *)navigationAction + completion: + (void (^)(FWFWKNavigationActionPolicyEnumData *_Nullable, + NSError *_Nullable))completion { + NSNumber *webViewIdentifier = + @([self.instanceManager identifierWithStrongReferenceForInstance:webView]); + FWFWKNavigationActionData *navigationActionData = + FWFWKNavigationActionDataFromNavigationAction(navigationAction); + [self + decidePolicyForNavigationActionForDelegateWithIdentifier:@([self + identifierForDelegate:instance]) + webViewIdentifier:webViewIdentifier + navigationAction:navigationActionData + completion:completion]; +} + +- (void)didFailNavigationForDelegate:(FWFNavigationDelegate *)instance + webView:(WKWebView *)webView + error:(NSError *)error + completion:(void (^)(NSError *_Nullable))completion { + NSNumber *webViewIdentifier = + @([self.instanceManager identifierWithStrongReferenceForInstance:webView]); + [self didFailNavigationForDelegateWithIdentifier:@([self identifierForDelegate:instance]) + webViewIdentifier:webViewIdentifier + error:FWFNSErrorDataFromNSError(error) + completion:completion]; +} + +- (void)didFailProvisionalNavigationForDelegate:(FWFNavigationDelegate *)instance + webView:(WKWebView *)webView + error:(NSError *)error + completion:(void (^)(NSError *_Nullable))completion { + NSNumber *webViewIdentifier = + @([self.instanceManager identifierWithStrongReferenceForInstance:webView]); + [self + didFailProvisionalNavigationForDelegateWithIdentifier:@([self identifierForDelegate:instance]) + webViewIdentifier:webViewIdentifier + error:FWFNSErrorDataFromNSError(error) + completion:completion]; +} + +- (void)webViewWebContentProcessDidTerminateForDelegate:(FWFNavigationDelegate *)instance + webView:(WKWebView *)webView + completion:(void (^)(NSError *_Nullable))completion { + NSNumber *webViewIdentifier = + @([self.instanceManager identifierWithStrongReferenceForInstance:webView]); + [self webViewWebContentProcessDidTerminateForDelegateWithIdentifier: + @([self identifierForDelegate:instance]) + webViewIdentifier:webViewIdentifier + completion:completion]; } @end @@ -53,7 +121,64 @@ - (instancetype)initWithBinaryMessenger:(id)binaryMessen - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { [self.navigationDelegateAPI didFinishNavigationForDelegate:self webView:webView - URL:webView.URL.absoluteString]; + URL:webView.URL.absoluteString + completion:^(NSError *error) { + NSAssert(!error, @"%@", error); + }]; +} + +- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { + [self.navigationDelegateAPI didStartProvisionalNavigationForDelegate:self + webView:webView + URL:webView.URL.absoluteString + completion:^(NSError *error) { + NSAssert(!error, @"%@", error); + }]; +} + +- (void)webView:(WKWebView *)webView + decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction + decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { + [self.navigationDelegateAPI + decidePolicyForNavigationActionForDelegate:self + webView:webView + navigationAction:navigationAction + completion:^(FWFWKNavigationActionPolicyEnumData *policy, + NSError *error) { + NSAssert(!error, @"%@", error); + decisionHandler( + FWFWKNavigationActionPolicyFromEnumData(policy)); + }]; +} + +- (void)webView:(WKWebView *)webView + didFailNavigation:(WKNavigation *)navigation + withError:(NSError *)error { + [self.navigationDelegateAPI didFailNavigationForDelegate:self + webView:webView + error:error + completion:^(NSError *error) { + NSAssert(!error, @"%@", error); + }]; +} + +- (void)webView:(WKWebView *)webView + didFailProvisionalNavigation:(WKNavigation *)navigation + withError:(NSError *)error { + [self.navigationDelegateAPI didFailProvisionalNavigationForDelegate:self + webView:webView + error:error + completion:^(NSError *error) { + NSAssert(!error, @"%@", error); + }]; +} + +- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView { + [self.navigationDelegateAPI webViewWebContentProcessDidTerminateForDelegate:self + webView:webView + completion:^(NSError *error) { + NSAssert(!error, @"%@", error); + }]; } @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFObjectHostApi.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFObjectHostApi.h index f1dbdbb20776..1f7b2943974e 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFObjectHostApi.h +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFObjectHostApi.h @@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN * * Handles making callbacks to Dart for an NSObject. */ -@interface FWFObjectFlutterApi : FWFNSObjectFlutterApi +@interface FWFObjectFlutterApiImpl : FWFNSObjectFlutterApi - (instancetype)initWithBinaryMessenger:(id)binaryMessenger instanceManager:(FWFInstanceManager *)instanceManager; @end @@ -23,7 +23,7 @@ NS_ASSUME_NONNULL_BEGIN * Implementation of NSObject for FWFObjectHostApiImpl. */ @interface FWFObject : NSObject -@property(readonly, nonnull) FWFObjectFlutterApi *objectApi; +@property(readonly, nonnull, nonatomic) FWFObjectFlutterApiImpl *objectApi; - (instancetype)initWithBinaryMessenger:(id)binaryMessenger instanceManager:(FWFInstanceManager *)instanceManager; @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFObjectHostApi.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFObjectHostApi.m index 0cc4c5693342..f88b91750493 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFObjectHostApi.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFObjectHostApi.m @@ -5,12 +5,12 @@ #import "FWFObjectHostApi.h" #import "FWFDataConverters.h" -@interface FWFObjectFlutterApi () +@interface FWFObjectFlutterApiImpl () // This reference must be weak to prevent a circular reference with the objects it stores. @property(nonatomic, weak) FWFInstanceManager *instanceManager; @end -@implementation FWFObjectFlutterApi +@implementation FWFObjectFlutterApiImpl - (instancetype)initWithBinaryMessenger:(id)binaryMessenger instanceManager:(FWFInstanceManager *)instanceManager { self = [self initWithBinaryMessenger:binaryMessenger]; @@ -19,6 +19,33 @@ - (instancetype)initWithBinaryMessenger:(id)binaryMessen } return self; } + +- (long)identifierForObject:(NSObject *)instance { + return [self.instanceManager identifierWithStrongReferenceForInstance:instance]; +} + +- (void)observeValueForObject:(NSObject *)instance + keyPath:(NSString *)keyPath + object:(NSObject *)object + change:(NSDictionary *)change + completion:(void (^)(NSError *_Nullable))completion { + NSMutableArray *changeKeys = [NSMutableArray array]; + NSMutableArray *changeValues = [NSMutableArray array]; + + [change enumerateKeysAndObjectsUsingBlock:^(NSKeyValueChangeKey key, id value, BOOL *stop) { + [changeKeys addObject:FWFNSKeyValueChangeKeyEnumDataFromNSKeyValueChangeKey(key)]; + [changeValues addObject:value]; + }]; + + NSNumber *objectIdentifier = + @([self.instanceManager identifierWithStrongReferenceForInstance:object]); + [self observeValueForObjectWithIdentifier:@([self identifierForObject:instance]) + keyPath:keyPath + objectIdentifier:objectIdentifier + changeKeys:changeKeys + changeValues:changeValues + completion:completion]; +} @end @implementation FWFObject @@ -26,11 +53,24 @@ - (instancetype)initWithBinaryMessenger:(id)binaryMessen instanceManager:(FWFInstanceManager *)instanceManager { self = [self init]; if (self) { - _objectApi = [[FWFObjectFlutterApi alloc] initWithBinaryMessenger:binaryMessenger - instanceManager:instanceManager]; + _objectApi = [[FWFObjectFlutterApiImpl alloc] initWithBinaryMessenger:binaryMessenger + instanceManager:instanceManager]; } return self; } + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + [self.objectApi observeValueForObject:self + keyPath:keyPath + object:object + change:change + completion:^(NSError *error) { + NSAssert(!error, @"%@", error); + }]; +} @end @interface FWFObjectHostApiImpl () diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFScriptMessageHandlerHostApi.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFScriptMessageHandlerHostApi.h index 7440862ce4e4..36f12feac3fe 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFScriptMessageHandlerHostApi.h +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFScriptMessageHandlerHostApi.h @@ -7,13 +7,28 @@ #import "FWFGeneratedWebKitApis.h" #import "FWFInstanceManager.h" +#import "FWFObjectHostApi.h" NS_ASSUME_NONNULL_BEGIN +/** + * Flutter api implementation for WKScriptMessageHandler. + * + * Handles making callbacks to Dart for a WKScriptMessageHandler. + */ +@interface FWFScriptMessageHandlerFlutterApiImpl : FWFWKScriptMessageHandlerFlutterApi +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger + instanceManager:(FWFInstanceManager *)instanceManager; +@end + /** * Implementation of WKScriptMessageHandler for FWFScriptMessageHandlerHostApiImpl. */ -@interface FWFScriptMessageHandler : NSObject +@interface FWFScriptMessageHandler : FWFObject +@property(readonly, nonnull, nonatomic) + FWFScriptMessageHandlerFlutterApiImpl *scriptMessageHandlerAPI; +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger + instanceManager:(FWFInstanceManager *)instanceManager; @end /** diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFScriptMessageHandlerHostApi.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFScriptMessageHandlerHostApi.m index 9e4b5f003abc..69ace0202824 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFScriptMessageHandlerHostApi.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFScriptMessageHandlerHostApi.m @@ -5,14 +5,64 @@ #import "FWFScriptMessageHandlerHostApi.h" #import "FWFDataConverters.h" +@interface FWFScriptMessageHandlerFlutterApiImpl () +// This reference must be weak to prevent a circular reference with the objects it stores. +@property(nonatomic, weak) FWFInstanceManager *instanceManager; +@end + +@implementation FWFScriptMessageHandlerFlutterApiImpl +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger + instanceManager:(FWFInstanceManager *)instanceManager { + self = [self initWithBinaryMessenger:binaryMessenger]; + if (self) { + _instanceManager = instanceManager; + } + return self; +} + +- (long)identifierForHandler:(FWFScriptMessageHandler *)instance { + return [self.instanceManager identifierWithStrongReferenceForInstance:instance]; +} + +- (void)didReceiveScriptMessageForHandler:(FWFScriptMessageHandler *)instance + userContentController:(WKUserContentController *)userContentController + message:(WKScriptMessage *)message + completion:(void (^)(NSError *_Nullable))completion { + NSNumber *userContentControllerIdentifier = + @([self.instanceManager identifierWithStrongReferenceForInstance:userContentController]); + FWFWKScriptMessageData *messageData = FWFWKScriptMessageDataFromWKScriptMessage(message); + [self didReceiveScriptMessageForHandlerWithIdentifier:@([self identifierForHandler:instance]) + userContentControllerIdentifier:userContentControllerIdentifier + message:messageData + completion:completion]; +} +@end + @implementation FWFScriptMessageHandler +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger + instanceManager:(FWFInstanceManager *)instanceManager { + self = [super initWithBinaryMessenger:binaryMessenger instanceManager:instanceManager]; + if (self) { + _scriptMessageHandlerAPI = + [[FWFScriptMessageHandlerFlutterApiImpl alloc] initWithBinaryMessenger:binaryMessenger + instanceManager:instanceManager]; + } + return self; +} + - (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message { + [self.scriptMessageHandlerAPI didReceiveScriptMessageForHandler:self + userContentController:userContentController + message:message + completion:^(NSError *error) { + NSAssert(!error, @"%@", error); + }]; } @end @interface FWFScriptMessageHandlerHostApiImpl () -@property(nonatomic) FWFInstanceManager *instanceManager; +@property(nonatomic, weak) FWFInstanceManager *instanceManager; @end @implementation FWFScriptMessageHandlerHostApiImpl diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFUIDelegateHostApi.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFUIDelegateHostApi.h index 8795b00e9001..65c148e6b0b1 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFUIDelegateHostApi.h +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFUIDelegateHostApi.h @@ -7,13 +7,27 @@ #import "FWFGeneratedWebKitApis.h" #import "FWFInstanceManager.h" +#import "FWFObjectHostApi.h" NS_ASSUME_NONNULL_BEGIN +/** + * Flutter api implementation for WKUIDelegate. + * + * Handles making callbacks to Dart for a WKUIDelegate. + */ +@interface FWFUIDelegateFlutterApiImpl : FWFWKUIDelegateFlutterApi +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger + instanceManager:(FWFInstanceManager *)instanceManager; +@end + /** * Implementation of WKUIDelegate for FWFUIDelegateHostApiImpl. */ -@interface FWFUIDelegate : NSObject +@interface FWFUIDelegate : FWFObject +@property(readonly, nonnull, nonatomic) FWFUIDelegateFlutterApiImpl *UIDelegateAPI; +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger + instanceManager:(FWFInstanceManager *)instanceManager; @end /** diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFUIDelegateHostApi.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFUIDelegateHostApi.m index 28d0ab53aaad..4ec8b583b1f8 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFUIDelegateHostApi.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFUIDelegateHostApi.m @@ -3,13 +3,75 @@ // found in the LICENSE file. #import "FWFUIDelegateHostApi.h" +#import "FWFDataConverters.h" #import "FWFWebViewConfigurationHostApi.h" +@interface FWFUIDelegateFlutterApiImpl () +// This reference must be weak to prevent a circular reference with the objects it stores. +@property(nonatomic, weak) FWFInstanceManager *instanceManager; +@end + +@implementation FWFUIDelegateFlutterApiImpl +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger + instanceManager:(FWFInstanceManager *)instanceManager { + self = [self initWithBinaryMessenger:binaryMessenger]; + if (self) { + _instanceManager = instanceManager; + } + return self; +} + +- (long)identifierForDelegate:(FWFUIDelegate *)instance { + return [self.instanceManager identifierWithStrongReferenceForInstance:instance]; +} + +- (void)onCreateWebViewForDelegate:(FWFUIDelegate *)instance + webView:(WKWebView *)webView + configuration:(WKWebViewConfiguration *)configuration + navigationAction:(WKNavigationAction *)navigationAction + completion:(void (^)(NSError *_Nullable))completion { + NSNumber *configurationIdentifier = + @([self.instanceManager identifierWithStrongReferenceForInstance:configuration]); + FWFWKNavigationActionData *navigationActionData = + FWFWKNavigationActionDataFromNavigationAction(navigationAction); + [self onCreateWebViewForDelegateWithIdentifier:@([self identifierForDelegate:instance]) + webViewIdentifier: + @([self.instanceManager + identifierWithStrongReferenceForInstance:webView]) + configurationIdentifier:configurationIdentifier + navigationAction:navigationActionData + completion:completion]; +} +@end + @implementation FWFUIDelegate +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger + instanceManager:(FWFInstanceManager *)instanceManager { + self = [super initWithBinaryMessenger:binaryMessenger instanceManager:instanceManager]; + if (self) { + _UIDelegateAPI = [[FWFUIDelegateFlutterApiImpl alloc] initWithBinaryMessenger:binaryMessenger + instanceManager:instanceManager]; + } + return self; +} + +- (WKWebView *)webView:(WKWebView *)webView + createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration + forNavigationAction:(WKNavigationAction *)navigationAction + windowFeatures:(WKWindowFeatures *)windowFeatures { + [self.UIDelegateAPI onCreateWebViewForDelegate:self + webView:webView + configuration:configuration + navigationAction:navigationAction + completion:^(NSError *error) { + NSAssert(!error, @"%@", error); + }]; + return nil; +} @end @interface FWFUIDelegateHostApiImpl () -@property(nonatomic) FWFInstanceManager *instanceManager; +@property(nonatomic, weak) FWFInstanceManager *instanceManager; @end @implementation FWFUIDelegateHostApiImpl pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy