Skip to content

Commit 8c23b72

Browse files
dpoguemsmtamburro
andcommitted
refactor(plugins): Add CDVPluginNavigationHandler protocol
This also adds a dictionary parameter containing the other navigation action details so that plugins can make choices based on frames. Closes apacheGH-1272. Closes apacheGH-1333. Co-Authored-By: Michael Tamburro <61243400+msmtamburro@users.noreply.github.com>
1 parent bdf99d2 commit 8c23b72

File tree

5 files changed

+120
-67
lines changed

5 files changed

+120
-67
lines changed

CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,13 @@
2020
#import <Cordova/CDVPlugin.h>
2121
#import "CDVAllowList.h"
2222

23-
#define CDVWebViewNavigationType int
24-
2523
typedef NS_ENUM(NSInteger, CDVIntentAndNavigationFilterValue) {
2624
CDVIntentAndNavigationFilterValueIntentAllowed,
2725
CDVIntentAndNavigationFilterValueNavigationAllowed,
2826
CDVIntentAndNavigationFilterValueNoneAllowed
2927
};
3028

31-
@interface CDVIntentAndNavigationFilter : CDVPlugin <NSXMLParserDelegate>
29+
@interface CDVIntentAndNavigationFilter : CDVPlugin <CDVPluginNavigationHandler, NSXMLParserDelegate>
3230

3331
+ (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url allowIntentsList:(CDVAllowList*)allowIntentsList navigationsAllowList:(CDVAllowList*)navigationsAllowList;
3432
+ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue;

CordovaLib/Classes/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ + (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(CDV
143143
}
144144
}
145145

146-
- (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType
146+
- (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(CDVWebViewNavigationType)navigationType info:(NSDictionary *)navInfo
147147
{
148148
return [[self class] shouldOverrideLoadWithRequest:request navigationType:navigationType filterValue:[self filterUrl:request.URL]];
149149
}

CordovaLib/Classes/Private/Plugins/CDVWebViewEngine/CDVWebViewEngine.m

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ - (UIView*)webView
453453
return self.engineWebView;
454454
}
455455

456-
#pragma mark WKScriptMessageHandler implementation
456+
#pragma mark - WKScriptMessageHandler implementation
457457

458458
- (void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage*)message
459459
{
@@ -489,7 +489,7 @@ - (void)userContentController:(WKUserContentController*)userContentController di
489489
}
490490
}
491491

492-
#pragma mark WKNavigationDelegate implementation
492+
#pragma mark - WKNavigationDelegate implementation
493493

494494
- (void)webView:(WKWebView*)webView didStartProvisionalNavigation:(WKNavigation*)navigation
495495
{
@@ -537,45 +537,64 @@ - (BOOL)defaultResourcePolicyForURL:(NSURL*)url
537537
return NO;
538538
}
539539

540-
- (void) webView: (WKWebView *) webView decidePolicyForNavigationAction: (WKNavigationAction*) navigationAction decisionHandler: (void (^)(WKNavigationActionPolicy)) decisionHandler
540+
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
541541
{
542-
NSURL* url = [navigationAction.request URL];
543-
CDVViewController* vc = (CDVViewController*)self.viewController;
542+
CDVViewController *vc = (CDVViewController *)self.viewController;
544543

545-
/*
546-
* Give plugins the chance to handle the url
547-
*/
548-
BOOL anyPluginsResponded = NO;
549-
BOOL shouldAllowRequest = NO;
544+
NSURLRequest *request = navigationAction.request;
545+
CDVWebViewNavigationType navType = (CDVWebViewNavigationType)navigationAction.navigationType;
546+
NSMutableDictionary *info = [NSMutableDictionary dictionary];
547+
info[@"sourceFrame"] = navigationAction.sourceFrame;
548+
info[@"targetFrame"] = navigationAction.targetFrame;
549+
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140500
550+
if (@available(iOS 14.5, *)) {
551+
info[@"shouldPerformDownload"] = [NSNumber numberWithBool:navigationAction.shouldPerformDownload];
552+
}
553+
#endif
550554

551-
for (CDVPlugin *plugin in vc.enumerablePlugins) {
552-
SEL selector = NSSelectorFromString(@"shouldOverrideLoadWithRequest:navigationType:");
553-
if ([plugin respondsToSelector:selector]) {
554-
anyPluginsResponded = YES;
555-
// https://issues.apache.org/jira/browse/CB-12497
556-
int navType = (int)navigationAction.navigationType;
557-
shouldAllowRequest = (((BOOL (*)(id, SEL, id, int))objc_msgSend)(plugin, selector, navigationAction.request, navType));
558-
if (!shouldAllowRequest) {
559-
break;
555+
// Give plugins the chance to handle the url, as long as this WebViewEngine is still the WKNavigationDelegate.
556+
// This allows custom delegates to choose to call this method for `default` cordova behavior without querying all plugins.
557+
if (webView.navigationDelegate == self) {
558+
BOOL anyPluginsResponded = NO;
559+
BOOL shouldAllowRequest = NO;
560+
561+
for (CDVPlugin *plugin in vc.enumerablePlugins) {
562+
if ([plugin respondsToSelector:@selector(shouldOverrideLoadWithRequest:navigationType:info:)] || [plugin respondsToSelector:@selector(shouldOverrideLoadWithRequest:navigationType:)]) {
563+
CDVPlugin <CDVPluginNavigationHandler> *navPlugin = (CDVPlugin <CDVPluginNavigationHandler> *)plugin;
564+
anyPluginsResponded = YES;
565+
566+
if ([navPlugin respondsToSelector:@selector(shouldOverrideLoadWithRequest:navigationType:info:)]) {
567+
shouldAllowRequest = [navPlugin shouldOverrideLoadWithRequest:request navigationType:navType info:info];
568+
} else {
569+
#pragma clang diagnostic push
570+
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
571+
shouldAllowRequest = [navPlugin shouldOverrideLoadWithRequest:request navigationType:navType];
572+
#pragma clang diagnostic pop
573+
}
574+
575+
if (!shouldAllowRequest) {
576+
break;
577+
}
560578
}
561579
}
562-
}
563-
564-
if (anyPluginsResponded) {
565-
return decisionHandler(shouldAllowRequest);
566-
}
567580

568-
/*
569-
* Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview.
570-
*/
571-
BOOL shouldAllowNavigation = [self defaultResourcePolicyForURL:url];
572-
if (shouldAllowNavigation) {
573-
return decisionHandler(YES);
581+
if (anyPluginsResponded) {
582+
return decisionHandler(shouldAllowRequest ? WKNavigationActionPolicyAllow : WKNavigationActionPolicyCancel);
583+
}
574584
} else {
575-
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];
585+
CDVPlugin <CDVPluginNavigationHandler> *intentAndNavFilter = (CDVPlugin <CDVPluginNavigationHandler> *)[vc getCommandInstance:@"IntentAndNavigationFilter"];
586+
if (intentAndNavFilter) {
587+
BOOL shouldAllowRequest = [intentAndNavFilter shouldOverrideLoadWithRequest:request navigationType:navType info:info];
588+
return decisionHandler(shouldAllowRequest ? WKNavigationActionPolicyAllow : WKNavigationActionPolicyCancel);
589+
}
576590
}
577591

578-
return decisionHandler(NO);
592+
// Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview.
593+
BOOL shouldAllowNavigation = [self defaultResourcePolicyForURL:request.URL];
594+
if (!shouldAllowNavigation) {
595+
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:request.URL userInfo:@{}]];
596+
}
597+
return decisionHandler(shouldAllowNavigation ? WKNavigationActionPolicyAllow : WKNavigationActionPolicyCancel);
579598
}
580599

581600
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler

CordovaLib/CordovaLib.docc/CordovaLib.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ For more information about Apache Cordova, visit [https://cordova.apache.org](ht
3636
### Cordova plugins
3737

3838
- ``CDVPlugin``
39-
- ``CDVPluginSchemeHandler``
4039
- ``CDVPluginAuthenticationHandler``
40+
- ``CDVPluginNavigationHandler``
41+
- ``CDVPluginSchemeHandler``
4142

4243
### Plugin communication
4344
- ``CDVPluginResult``

CordovaLib/include/Cordova/CDVPlugin.h

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
// Forward declaration to avoid bringing WebKit API into public headers
3131
@protocol WKURLSchemeTask;
3232

33+
typedef int CDVWebViewNavigationType;
34+
3335
#ifndef __swift__
3436
// This global extension to the UIView class causes issues for Swift subclasses
3537
// of UIView with their own scrollView properties, so we're removing it from
@@ -87,6 +89,69 @@ extern const NSNotificationName CDVViewWillTransitionToSizeNotification;
8789

8890
#pragma mark - Plugin protocols
8991

92+
/**
93+
A protocol for Cordova plugins to intercept and respond to server
94+
authentication challenges through WebKit.
95+
96+
Your plugin should implement this protocol and the
97+
``didReceiveAuthenticationChallenge:completionHandler:`` if it wants to
98+
support responses to server-side authentication challenges, otherwise the
99+
default NSURLSession handling for authentication challenges will be used.
100+
*/
101+
@protocol CDVPluginAuthenticationHandler <NSObject>
102+
103+
/**
104+
Asks your plugin to respond to an authentication challenge.
105+
106+
- Parameters:
107+
- challenge: The authentication challenge.
108+
- completionHandler: A completion handler block to execute with the response.
109+
This handler has no return value and takes the following parameters:
110+
- disposition: The option to use to handle the challenge. For a list of
111+
options, see `NSURLSessionAuthChallengeDisposition`.
112+
- credential: The credential to use for authentication when the
113+
`disposition` parameter contains the value
114+
`NSURLSessionAuthChallengeUseCredential`. Specify `nil` to continue
115+
without a credential.
116+
*/
117+
- (void)didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler;
118+
119+
@end
120+
121+
122+
/**
123+
A protocol for Cordova plugins to manage permitting and denying of webview
124+
navigations.
125+
126+
You plugin should implement this protocol if it wants to control whether the
127+
webview is allowed to navigate to a requested URL.
128+
*/
129+
@protocol CDVPluginNavigationHandler <NSObject>
130+
131+
/**
132+
Asks your plugin to decide whether a navigation request should be permitted or
133+
denied.
134+
135+
- Parameters:
136+
- request: The navigation request.
137+
- navigationType: The type of action triggering the navigation.
138+
- navInfo: Descriptive information about the action triggering the navigation.
139+
140+
- Returns: A Boolean representing whether the navigation should be allowed or not.
141+
*/
142+
- (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest *)request navigationType:(CDVWebViewNavigationType)navigationType info:(NSDictionary *)navInfo;
143+
144+
@optional
145+
/**
146+
@DeprecationSummary {
147+
Use ``shouldOverrideLoadWithRequest:navigationType:info:`` instead.
148+
}
149+
*/
150+
- (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest *)request navigationType:(CDVWebViewNavigationType)navigationType CDV_DEPRECATED_WITH_REPLACEMENT(8, "Use shouldOverrideLoadWithRequest:navigationType:info: instead", "shouldOverrideLoadWithRequest:navigationType:info:");
151+
152+
@end
153+
154+
90155
/**
91156
A protocol for Cordova plugins to intercept handling of WebKit resource
92157
loading for a custom URL scheme.
@@ -131,34 +196,4 @@ extern const NSNotificationName CDVViewWillTransitionToSizeNotification;
131196
- (void)stopSchemeTask:(id <WKURLSchemeTask>)task;
132197
@end
133198

134-
135-
/**
136-
A protocol for Cordova plugins to intercept and respond to server
137-
authentication challenges through WebKit.
138-
139-
Your plugin should implement this protocol and the
140-
``didReceiveAuthenticationChallenge:completionHandler:`` if it wants to
141-
support responses to server-side authentication challenges, otherwise the
142-
default NSURLSession handling for authentication challenges will be used.
143-
*/
144-
@protocol CDVPluginAuthenticationHandler <NSObject>
145-
146-
/**
147-
Asks your plugin to respond to an authentication challenge.
148-
149-
- Parameters:
150-
- challenge: The authentication challenge.
151-
- completionHandler: A completion handler block to execute with the response.
152-
This handler has no return value and takes the following parameters:
153-
- disposition: The option to use to handle the challenge. For a list of
154-
options, see `NSURLSessionAuthChallengeDisposition`.
155-
- credential: The credential to use for authentication when the
156-
`disposition` parameter contains the value
157-
`NSURLSessionAuthChallengeUseCredential`. Specify `nil` to continue
158-
without a credential.
159-
*/
160-
- (void)didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler;
161-
162-
@end
163-
164199
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)