feat(ios): Enhanced permissions handling to prevent repetitive prompts. (#2257)

This commit is contained in:
Franz Bruckhoff 2021-11-29 10:47:28 +01:00 committed by GitHub
parent 46ecef868a
commit cd42aa7f11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 95 additions and 0 deletions

View File

@ -9,6 +9,14 @@
#import <React/RCTDefines.h>
#import <WebKit/WebKit.h>
typedef enum RNCWebViewPermissionGrantType : NSUInteger {
RNCWebViewPermissionGrantType_GrantIfSameHost_ElsePrompt,
RNCWebViewPermissionGrantType_GrantIfSameHost_ElseDeny,
RNCWebViewPermissionGrantType_Deny,
RNCWebViewPermissionGrantType_Grant,
RNCWebViewPermissionGrantType_Prompt
} RNCWebViewPermissionGrantType;
@class RNCWebView;
@protocol RNCWebViewDelegate <NSObject>
@ -84,6 +92,10 @@
@property (nonatomic, assign) BOOL limitsNavigationsToAppBoundDomains;
#endif
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000 /* iOS 15 */
@property (nonatomic, assign) RNCWebViewPermissionGrantType mediaCapturePermissionGrantType;
#endif
+ (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential;
+ (void)setCustomCertificatesForHost:(nullable NSDictionary *)certificates;
- (void)postMessage:(NSString *_Nullable)message;

View File

@ -149,6 +149,7 @@ NSString *const CUSTOM_SELECTOR = @"_CUSTOM_SELECTOR_";
_savedAutomaticallyAdjustsScrollIndicatorInsets = NO;
#endif
_enableApplePay = NO;
_mediaCapturePermissionGrantType = RNCWebViewPermissionGrantType_Prompt;
}
#if !TARGET_OS_OSX
@ -1063,6 +1064,32 @@ NSString *const CUSTOM_SELECTOR = @"_CUSTOM_SELECTOR_";
#endif // !TARGET_OS_OSX
}
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000 /* iOS 15 */
/**
* Media capture permissions (prevent multiple prompts)
*/
- (void) webView:(WKWebView *)webView
requestMediaCapturePermissionForOrigin:(WKSecurityOrigin *)origin
initiatedByFrame:(WKFrameInfo *)frame
type:(WKMediaCaptureType)type
decisionHandler:(void (^)(WKPermissionDecision decision))decisionHandler {
if (_mediaCapturePermissionGrantType == RNCWebViewPermissionGrantType_GrantIfSameHost_ElsePrompt || _mediaCapturePermissionGrantType == RNCWebViewPermissionGrantType_GrantIfSameHost_ElseDeny) {
if ([origin.host isEqualToString:webView.URL.host]) {
decisionHandler(WKPermissionDecisionGrant);
} else {
WKPermissionDecision decision = _mediaCapturePermissionGrantType == RNCWebViewPermissionGrantType_GrantIfSameHost_ElsePrompt ? WKPermissionDecisionPrompt : WKPermissionDecisionDeny;
decisionHandler(decision);
}
} else if (_mediaCapturePermissionGrantType == RNCWebViewPermissionGrantType_Deny) {
decisionHandler(WKPermissionDecisionDeny);
} else if (_mediaCapturePermissionGrantType == RNCWebViewPermissionGrantType_Grant) {
decisionHandler(WKPermissionDecisionGrant);
} else {
decisionHandler(WKPermissionDecisionPrompt);
}
}
#endif
#if !TARGET_OS_OSX
/**
* topViewController

View File

@ -22,6 +22,16 @@ RCT_ENUM_CONVERTER(WKContentMode, (@{
@"desktop": @(WKContentModeDesktop),
}), WKContentModeRecommended, integerValue)
#endif
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000 /* iOS 15 */
RCT_ENUM_CONVERTER(RNCWebViewPermissionGrantType, (@{
@"grantIfSameHostElsePrompt": @(RNCWebViewPermissionGrantType_GrantIfSameHost_ElsePrompt),
@"grantIfSameHostElseDeny": @(RNCWebViewPermissionGrantType_GrantIfSameHost_ElseDeny),
@"deny": @(RNCWebViewPermissionGrantType_Deny),
@"grant": @(RNCWebViewPermissionGrantType_Grant),
@"prompt": @(RNCWebViewPermissionGrantType_Prompt),
}), RNCWebViewPermissionGrantType_Prompt, integerValue)
#endif
@end
@implementation RNCWebViewManager
@ -93,6 +103,10 @@ RCT_EXPORT_VIEW_PROPERTY(contentMode, WKContentMode)
RCT_EXPORT_VIEW_PROPERTY(limitsNavigationsToAppBoundDomains, BOOL)
#endif
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000 /* iOS 15 */
RCT_EXPORT_VIEW_PROPERTY(mediaCapturePermissionGrantType, RNCWebViewPermissionGrantType)
#endif
/**
* Expose methods to enable messaging the webview.
*/

View File

@ -77,6 +77,7 @@ This document lays out the current public properties and methods for the React N
- [`ignoreSilentHardwareSwitch`](Reference.md#ignoreSilentHardwareSwitch)
- [`onFileDownload`](Reference.md#onFileDownload)
- [`limitsNavigationsToAppBoundDomains`](Reference.md#limitsNavigationsToAppBoundDomains)
- [`mediaCapturePermissionGrantType`](Reference.md#mediaCapturePermissionGrantType)
- [`autoManageStatusBarEnabled`](Reference.md#autoManageStatusBarEnabled)
- [`setSupportMultipleWindows`](Reference.md#setSupportMultipleWindows)
- [`basicAuthCredential`](Reference.md#basicAuthCredential)
@ -1375,6 +1376,32 @@ Example:
---
### `mediaCapturePermissionGrantType`
This property specifies how to handle media capture permission requests. Defaults to `prompt`, resulting in the user being prompted repeatedly. Available on iOS 15 and later.
Possible values:
- `grantIfSameHostElsePrompt`: If the security origin's host of the permission request equals the host of the WebView's current URL, the permission is granted if it has been granted before. Otherwise, the user gets prompted.
- `grantIfSameHostElseDeny`: If the security origin's host of the permission request equals the host of the WebView's current URL, the permission is granted if it has been granted before. Otherwise, it gets denied.
- `deny`
- `grant`: The permission is granted if it has been granted before.
- `prompt`
Note that a grant may still result in a prompt, for example if the user has never been prompted for the permission before.
| Type | Required | Platform |
| ------ | -------- | -------- |
| string | No | iOS |
Example:
```javascript
<WebView mediaCapturePermissionGrantType={'grantIfSameHostElsePrompt'} />
```
---
### `autoManageStatusBarEnabled`
If set to `true`, the status bar will be automatically hidden/shown by WebView, specifically when full screen video is being watched. If `false`, WebView will not manage the status bar at all. The default value is `true`.

View File

@ -335,6 +335,13 @@ export interface AndroidNativeWebViewProps extends CommonNativeWebViewProps {
export declare type ContentInsetAdjustmentBehavior = 'automatic' | 'scrollableAxes' | 'never' | 'always';
export declare type MediaCapturePermissionGrantType =
| 'grantIfSameHostElsePrompt'
| 'grantIfSameHostElseDeny'
| 'deny'
| 'grant'
| 'prompt';
export declare type ContentMode = 'recommended' | 'mobile' | 'desktop';
export interface IOSNativeWebViewProps extends CommonNativeWebViewProps {
@ -362,6 +369,7 @@ export interface IOSNativeWebViewProps extends CommonNativeWebViewProps {
injectedJavaScriptBeforeContentLoadedForMainFrameOnly?: boolean;
onFileDownload?: (event: FileDownloadEvent) => void;
limitsNavigationsToAppBoundDomains?: boolean;
mediaCapturePermissionGrantType?: MediaCapturePermissionGrantType;
}
export interface MacOSNativeWebViewProps extends CommonNativeWebViewProps {
@ -663,6 +671,13 @@ export interface IOSWebViewProps extends WebViewSharedProps {
*/
limitsNavigationsToAppBoundDomains?: boolean;
/**
* This property specifies how to handle media capture permission requests.
* Defaults to `prompt`, resulting in the user being prompted repeatedly.
* Available on iOS 15 and later.
*/
mediaCapturePermissionGrantType?: MediaCapturePermissionGrantType;
/**
* A Boolean value which, when set to `true`, WebView will be rendered with Apple Pay support.
* Once set, websites will be able to invoke apple pay from React Native Webview.