Skip to content

Commit 82c1767

Browse files
dpogueChristopher J. Brodymsmtamburro
authored
feat(plugins): Better define plugin behaviour protocols (#1514)
* feat(plugins): Add plugin support for auth challenge responses Closes GH-1212. Co-Authored-By: Christopher J. Brody <[email protected]> * 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 GH-1272. Closes GH-1333. Co-Authored-By: Michael Tamburro <[email protected]> * fix(scrollview): Add nullable attribute to scrollView property --------- Co-authored-by: Christopher J. Brody <[email protected]> Co-authored-by: Michael Tamburro <[email protected]>
1 parent d2db6e6 commit 82c1767

File tree

7 files changed

+151
-36
lines changed

7 files changed

+151
-36
lines changed

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

+1-3
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

+1-1
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

+65-30
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ - (CDVWebViewPermissionGrantType)parsePermissionGrantType:(NSString*)optionStrin
477477
return result;
478478
}
479479

480-
#pragma mark WKScriptMessageHandler implementation
480+
#pragma mark - WKScriptMessageHandler implementation
481481

482482
- (void)userContentController:(WKUserContentController*)userContentController didReceiveScriptMessage:(WKScriptMessage*)message
483483
{
@@ -513,7 +513,7 @@ - (void)userContentController:(WKUserContentController*)userContentController di
513513
}
514514
}
515515

516-
#pragma mark WKNavigationDelegate implementation
516+
#pragma mark - WKNavigationDelegate implementation
517517

518518
- (void)webView:(WKWebView*)webView didStartProvisionalNavigation:(WKNavigation*)navigation
519519
{
@@ -561,45 +561,80 @@ - (BOOL)defaultResourcePolicyForURL:(NSURL*)url
561561
return NO;
562562
}
563563

564-
- (void) webView: (WKWebView *) webView decidePolicyForNavigationAction: (WKNavigationAction*) navigationAction decisionHandler: (void (^)(WKNavigationActionPolicy)) decisionHandler
564+
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
565565
{
566-
NSURL* url = [navigationAction.request URL];
567-
CDVViewController* vc = (CDVViewController*)self.viewController;
566+
CDVViewController *vc = (CDVViewController *)self.viewController;
568567

569-
/*
570-
* Give plugins the chance to handle the url
571-
*/
572-
BOOL anyPluginsResponded = NO;
573-
BOOL shouldAllowRequest = NO;
568+
NSURLRequest *request = navigationAction.request;
569+
CDVWebViewNavigationType navType = (CDVWebViewNavigationType)navigationAction.navigationType;
570+
NSMutableDictionary *info = [NSMutableDictionary dictionary];
571+
info[@"sourceFrame"] = navigationAction.sourceFrame;
572+
info[@"targetFrame"] = navigationAction.targetFrame;
573+
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140500
574+
if (@available(iOS 14.5, *)) {
575+
info[@"shouldPerformDownload"] = [NSNumber numberWithBool:navigationAction.shouldPerformDownload];
576+
}
577+
#endif
574578

575-
for (CDVPlugin *plugin in vc.enumerablePlugins) {
576-
SEL selector = NSSelectorFromString(@"shouldOverrideLoadWithRequest:navigationType:");
577-
if ([plugin respondsToSelector:selector]) {
578-
anyPluginsResponded = YES;
579-
// https://issues.apache.org/jira/browse/CB-12497
580-
int navType = (int)navigationAction.navigationType;
581-
shouldAllowRequest = (((BOOL (*)(id, SEL, id, int))objc_msgSend)(plugin, selector, navigationAction.request, navType));
582-
if (!shouldAllowRequest) {
583-
break;
579+
// Give plugins the chance to handle the url, as long as this WebViewEngine is still the WKNavigationDelegate.
580+
// This allows custom delegates to choose to call this method for `default` cordova behavior without querying all plugins.
581+
if (webView.navigationDelegate == self) {
582+
BOOL anyPluginsResponded = NO;
583+
BOOL shouldAllowRequest = NO;
584+
585+
for (CDVPlugin *plugin in vc.enumerablePlugins) {
586+
if ([plugin respondsToSelector:@selector(shouldOverrideLoadWithRequest:navigationType:info:)] || [plugin respondsToSelector:@selector(shouldOverrideLoadWithRequest:navigationType:)]) {
587+
CDVPlugin <CDVPluginNavigationHandler> *navPlugin = (CDVPlugin <CDVPluginNavigationHandler> *)plugin;
588+
anyPluginsResponded = YES;
589+
590+
if ([navPlugin respondsToSelector:@selector(shouldOverrideLoadWithRequest:navigationType:info:)]) {
591+
shouldAllowRequest = [navPlugin shouldOverrideLoadWithRequest:request navigationType:navType info:info];
592+
} else {
593+
#pragma clang diagnostic push
594+
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
595+
shouldAllowRequest = [navPlugin shouldOverrideLoadWithRequest:request navigationType:navType];
596+
#pragma clang diagnostic pop
597+
}
598+
599+
if (!shouldAllowRequest) {
600+
break;
601+
}
584602
}
585603
}
604+
605+
if (anyPluginsResponded) {
606+
return decisionHandler(shouldAllowRequest ? WKNavigationActionPolicyAllow : WKNavigationActionPolicyCancel);
607+
}
608+
} else {
609+
CDVPlugin <CDVPluginNavigationHandler> *intentAndNavFilter = (CDVPlugin <CDVPluginNavigationHandler> *)[vc getCommandInstance:@"IntentAndNavigationFilter"];
610+
if (intentAndNavFilter) {
611+
BOOL shouldAllowRequest = [intentAndNavFilter shouldOverrideLoadWithRequest:request navigationType:navType info:info];
612+
return decisionHandler(shouldAllowRequest ? WKNavigationActionPolicyAllow : WKNavigationActionPolicyCancel);
613+
}
586614
}
587615

588-
if (anyPluginsResponded) {
589-
return decisionHandler(shouldAllowRequest);
616+
// Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview.
617+
BOOL shouldAllowNavigation = [self defaultResourcePolicyForURL:request.URL];
618+
if (!shouldAllowNavigation) {
619+
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:request.URL userInfo:@{}]];
590620
}
621+
return decisionHandler(shouldAllowNavigation ? WKNavigationActionPolicyAllow : WKNavigationActionPolicyCancel);
622+
}
591623

592-
/*
593-
* Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview.
594-
*/
595-
BOOL shouldAllowNavigation = [self defaultResourcePolicyForURL:url];
596-
if (shouldAllowNavigation) {
597-
return decisionHandler(YES);
598-
} else {
599-
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];
624+
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
625+
{
626+
CDVViewController* vc = (CDVViewController*)self.viewController;
627+
628+
for (CDVPlugin *plugin in vc.enumerablePlugins) {
629+
if ([plugin respondsToSelector:@selector(willHandleAuthenticationChallenge:completionHandler:)]) {
630+
CDVPlugin <CDVPluginAuthenticationHandler> *challengePlugin = (CDVPlugin <CDVPluginAuthenticationHandler> *)plugin;
631+
if ([challengePlugin willHandleAuthenticationChallenge:challenge completionHandler:completionHandler]) {
632+
return;
633+
}
634+
}
600635
}
601636

602-
return decisionHandler(NO);
637+
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
603638
}
604639

605640
#pragma mark - Plugin interface

CordovaLib/Classes/Public/CDVPlugin.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ - (void)handleOpenURL:(NSNotification*)notification
142142
/*
143143
NOTE: calls into JavaScript must not call or trigger any blocking UI, like alerts
144144
*/
145-
- (void)handleOpenURLWithApplicationSourceAndAnnotation: (NSNotification*)notification
145+
- (void)handleOpenURLWithApplicationSourceAndAnnotation:(NSNotification*)notification
146146
{
147147

148148
// override to handle urls sent to your app

CordovaLib/CordovaLib.docc/CordovaLib.md

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

3838
- ``CDVPlugin``
39+
- ``CDVPluginAuthenticationHandler``
40+
- ``CDVPluginNavigationHandler``
3941
- ``CDVPluginSchemeHandler``
4042

4143
### Plugin communication

CordovaLib/CordovaLib.docc/upgrading-8.md

+6
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,12 @@ The following headers are deprecated due to adding global category extensions to
259259
* The ``CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification`` notification is now deprecated.
260260
The existing ``CDVPluginHandleOpenURLNotification`` notification now includes the source and annotation in its `userInfo` dictionary.
261261

262+
* ``CDVPluginAuthenticationHandler``
263+
* Newly added protocol for plugins wishing to handle server authentication requests.
264+
265+
* ``CDVPluginNavigationHandler``
266+
* Newly added protocol for plugins wishing to handle navigation request permitting or denying within the webview.
267+
262268
* ``CDVPluginSchemeHandler``
263269
* Newly added protocol for plugins wishing to override WebKit scheme handling for web requests.
264270

CordovaLib/include/Cordova/CDVPlugin.h

+75-1
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,20 @@
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
3638
// the exposed Swift API and marking it as deprecated
3739
// TODO: Remove in Cordova 9
3840
@interface UIView (org_apache_cordova_UIView_Extension)
39-
@property (nonatomic, weak) UIScrollView* scrollView CDV_DEPRECATED(8, "Check for a scrollView property on the view object at runtime and invoke it dynamically.");
41+
@property (nonatomic, weak, nullable) UIScrollView* scrollView CDV_DEPRECATED(8, "Check for a scrollView property on the view object at runtime and invoke it dynamically.");
4042
@end
4143
#endif
4244

45+
NS_ASSUME_NONNULL_BEGIN
46+
4347
extern const NSNotificationName CDVPageDidLoadNotification;
4448
extern const NSNotificationName CDVPluginHandleOpenURLNotification;
4549
extern const NSNotificationName CDVPluginHandleOpenURLWithAppSourceAndAnnotationNotification CDV_DEPRECATED(8, "Find sourceApplication and annotations in the userInfo of the CDVPluginHandleOpenURLNotification notification.");
@@ -85,6 +89,74 @@ extern const NSNotificationName CDVViewWillTransitionToSizeNotification;
8589

8690
#pragma mark - Plugin protocols
8791

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

0 commit comments

Comments
 (0)