updated onPermissionRequest event for ios, added DebugSettings

This commit is contained in:
Lorenzo Pichilli 2022-05-02 18:59:29 +02:00
parent 17ed6c881a
commit 28455c696a
10 changed files with 112 additions and 53 deletions

View File

@ -7,6 +7,7 @@
- Added `underPageBackgroundColor`, `isTextInteractionEnabled`, `isSiteSpecificQuirksModeEnabled`, `upgradeKnownHostsToHTTPS`, `forceDarkStrategy` WebView settings
- Added `onCameraCaptureStateChanged`, `onMicrophoneCaptureStateChanged` WebView events
- Added support for `onPermissionRequest` event on iOS 15.0+
- Added `debugSettings` static property for WebView and ChromeSafariBrowser
- Updated `getMetaThemeColor` on iOS 15.0+
- Deprecated `onLoadError` for `onReceivedError`. `onReceivedError` will be called also for subframes.
- Deprecated `onLoadHttpError` for `onReceivedError`. `onReceivedHttpError` will be called also for subframes.

View File

@ -96,7 +96,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
TextField(
decoration: InputDecoration(prefixIcon: Icon(Icons.search)),
controller: urlController,
keyboardType: TextInputType.url,
keyboardType: TextInputType.text,
onSubmitted: (value) {
var url = Uri.parse(value);
if (url.scheme.isEmpty) {

View File

@ -19,7 +19,7 @@ Future main() async {
// await Permission.microphone.request();
// await Permission.storage.request();
WebView.debugLogging = false;
WebView.debugSettings.maxLogMessageLength = 500;
if (defaultTargetPlatform == TargetPlatform.android) {
await InAppWebViewController.setWebContentsDebuggingEnabled(true);

View File

@ -669,10 +669,12 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
if let newValue = change?[.newKey] as? Int {
newState = WKMediaCaptureState.init(rawValue: newValue)
}
if keyPath == #keyPath(WKWebView.cameraCaptureState) {
onCameraCaptureStateChanged(oldState: oldState, newState: newState)
} else {
onMicrophoneCaptureStateChanged(oldState: oldState, newState: newState)
if oldState != newState {
if keyPath == #keyPath(WKWebView.cameraCaptureState) {
onCameraCaptureStateChanged(oldState: oldState, newState: newState)
} else {
onMicrophoneCaptureStateChanged(oldState: oldState, newState: newState)
}
}
}
// else if keyPath == #keyPath(WKWebView.fullscreenState) {
@ -1552,10 +1554,10 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
onPermissionRequest(request: permissionRequest, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message ?? "")
decisionHandler(.deny)
decisionHandler(.prompt)
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
decisionHandler(.deny)
decisionHandler(.prompt)
}
else {
var response: [String: Any]
@ -1575,7 +1577,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
}
return;
}
decisionHandler(.deny)
decisionHandler(.prompt)
}
})
}
@ -1593,10 +1595,10 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
onPermissionRequest(request: permissionRequest, result: {(result) -> Void in
if result is FlutterError {
print((result as! FlutterError).message ?? "")
decisionHandler(.deny)
decisionHandler(.prompt)
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
decisionHandler(.deny)
decisionHandler(.prompt)
}
else {
var response: [String: Any]
@ -1616,7 +1618,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
}
return;
}
decisionHandler(.deny)
decisionHandler(.prompt)
}
})
}

View File

@ -6,6 +6,7 @@ import 'dart:developer' as developer;
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import '../util.dart';
import '../debug_settings.dart';
import 'chrome_safari_browser_settings.dart';
@ -44,12 +45,8 @@ class ChromeSafariBrowserNotOpenedException implements Exception {
///- Android native WebView
///- iOS
class ChromeSafariBrowser {
///Enables [ChromeSafariBrowser] debug logging info.
///
///The default value is the same value of [kDebugMode],
///so it is enabled by default when the application is compiled in debug mode
///and disabled when it is not.
static bool debugLogging = kDebugMode;
///Debug settings.
static DebugSettings debugSettings = DebugSettings();
///View ID used internally.
late final String id;
@ -70,12 +67,22 @@ class ChromeSafariBrowser {
}
_debugLog(String method, dynamic args) {
if (ChromeSafariBrowser.debugLogging) {
String message =
"ChromeSafariBrowser ID " + id + " calling \"" +
method.toString() + "\" using " + args.toString();
developer.log(message,
name: this.runtimeType.toString());
if (ChromeSafariBrowser.debugSettings.enabled) {
for (var regExp in ChromeSafariBrowser.debugSettings.excludeFilter) {
if (regExp.hasMatch(method)) return;
}
var maxLogMessageLength =
ChromeSafariBrowser.debugSettings.maxLogMessageLength;
String message = "ChromeSafariBrowser ID " +
id +
" calling \"" +
method.toString() +
"\" using " +
args.toString();
if (maxLogMessageLength >= 0 && message.length > maxLogMessageLength) {
message = message.substring(0, maxLogMessageLength) + "...";
}
developer.log(message, name: this.runtimeType.toString());
}
}

View File

@ -0,0 +1,28 @@
import 'package:flutter/foundation.dart';
import 'in_app_webview/webview.dart';
import 'chrome_safari_browser/chrome_safari_browser.dart';
///Class that represents the debug settings used by [WebView] and [ChromeSafariBrowser].
class DebugSettings {
///Enables debug logging info.
///
///The default value is the same value of [kDebugMode],
///so it is enabled by default when the application is compiled in debug mode
///and disabled when it is not.
bool enabled;
///Filters used to exclude some logs from logging.
List<RegExp> excludeFilter;
///Max length of the log message.
///Set to `-1` to indicate that the log message needs to display the full content.
///
///The default value is `-1`.
int maxLogMessageLength;
DebugSettings({
this.enabled = kDebugMode,
this.excludeFilter = const [],
this.maxLogMessageLength = -1
});
}

View File

@ -804,10 +804,13 @@ class InAppBrowser {
///
///[resources] represents the array of resources the web content wants to access.
///
///**NOTE**: available only on Android 23+.
///**NOTE for Android**: available only on Android 23+.
///
///**NOTE for iOS**: available only on iOS 15.0+. The default [PermissionResponse.action] is [PermissionResponseAction.PROMPT].
///
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - WebChromeClient.onPermissionRequest](https://developer.android.com/reference/android/webkit/WebChromeClient#onPermissionRequest(android.webkit.PermissionRequest)))
///- iOS
Future<PermissionResponse?>? onPermissionRequest(
PermissionRequest permissionRequest) {}

View File

@ -104,7 +104,11 @@ class InAppWebViewController {
}
_debugLog(String method, dynamic args) {
if (WebView.debugLogging) {
if (WebView.debugSettings.enabled) {
for (var regExp in WebView.debugSettings.excludeFilter) {
if (regExp.hasMatch(method)) return;
}
var maxLogMessageLength = WebView.debugSettings.maxLogMessageLength;
String viewId = (getViewId() ?? _inAppBrowser?.id).toString();
String message = (_inAppBrowser == null ? "WebView" : "InAppBrowser") +
" ID " +
@ -113,12 +117,15 @@ class InAppWebViewController {
method.toString() +
"\" using " +
args.toString();
if (maxLogMessageLength >= 0 && message.length > maxLogMessageLength) {
message = message.substring(0, maxLogMessageLength) + "...";
}
developer.log(message, name: this.runtimeType.toString());
}
}
Future<dynamic> handleMethod(MethodCall call) async {
if (WebView.debugLogging && call.method != "onCallJsHandler") {
if (WebView.debugSettings.enabled && call.method != "onCallJsHandler") {
_debugLog(call.method, call.arguments);
}
@ -163,15 +170,15 @@ class InAppWebViewController {
_webview!.onReceivedError!(this, request, error);
else if (isForMainFrame) {
// ignore: deprecated_member_use_from_same_package
_webview!.onLoadError!(this, request.url, error.type.toNativeValue(),
error.description);
_webview!.onLoadError!(this, request.url,
error.type.toNativeValue(), error.description);
}
} else {
if (isForMainFrame) {
_inAppBrowser!
// ignore: deprecated_member_use_from_same_package
.onLoadError(
request.url, error.type.toNativeValue(), error.description);
// ignore: deprecated_member_use_from_same_package
.onLoadError(request.url, error.type.toNativeValue(),
error.description);
}
_inAppBrowser!.onReceivedError(request, error);
}
@ -203,9 +210,9 @@ class InAppWebViewController {
} else {
if (isForMainFrame) {
_inAppBrowser!
// ignore: deprecated_member_use_from_same_package
// ignore: deprecated_member_use_from_same_package
.onLoadHttpError(request.url, errorResponse.statusCode ?? -1,
errorResponse.reasonPhrase ?? '');
errorResponse.reasonPhrase ?? '');
}
_inAppBrowser!.onReceivedHttpError(request, errorResponse);
}
@ -1091,10 +1098,13 @@ class InAppWebViewController {
}
break;
case "onCameraCaptureStateChanged":
if ((_webview != null && _webview!.onCameraCaptureStateChanged != null) ||
if ((_webview != null &&
_webview!.onCameraCaptureStateChanged != null) ||
_inAppBrowser != null) {
var oldState = MediaCaptureState.fromValue(call.arguments["oldState"]);
var newState = MediaCaptureState.fromValue(call.arguments["newState"]);
var oldState =
MediaCaptureState.fromValue(call.arguments["oldState"]);
var newState =
MediaCaptureState.fromValue(call.arguments["newState"]);
if (_webview != null && _webview!.onCameraCaptureStateChanged != null)
_webview!.onCameraCaptureStateChanged!(this, oldState, newState);
@ -1103,13 +1113,18 @@ class InAppWebViewController {
}
break;
case "onMicrophoneCaptureStateChanged":
if ((_webview != null && _webview!.onMicrophoneCaptureStateChanged != null) ||
if ((_webview != null &&
_webview!.onMicrophoneCaptureStateChanged != null) ||
_inAppBrowser != null) {
var oldState = MediaCaptureState.fromValue(call.arguments["oldState"]);
var newState = MediaCaptureState.fromValue(call.arguments["newState"]);
var oldState =
MediaCaptureState.fromValue(call.arguments["oldState"]);
var newState =
MediaCaptureState.fromValue(call.arguments["newState"]);
if (_webview != null && _webview!.onMicrophoneCaptureStateChanged != null)
_webview!.onMicrophoneCaptureStateChanged!(this, oldState, newState);
if (_webview != null &&
_webview!.onMicrophoneCaptureStateChanged != null)
_webview!.onMicrophoneCaptureStateChanged!(
this, oldState, newState);
else
_inAppBrowser!.onMicrophoneCaptureStateChanged(oldState, newState);
}
@ -3286,8 +3301,7 @@ class InAppWebViewController {
///
///**Supported Platforms/Implementations**:
///- iOS ([Official API - WKWebView.setCameraCaptureState](https://developer.apple.com/documentation/webkit/wkwebview/3763097-setcameracapturestate)).
Future<void> setCameraCaptureState(
{required MediaCaptureState state}) async {
Future<void> setCameraCaptureState({required MediaCaptureState state}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('state', () => state.toValue());
await _channel.invokeMethod('setCameraCaptureState', args);

View File

@ -1,8 +1,6 @@
import 'dart:collection';
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import '../pull_to_refresh/pull_to_refresh_controller.dart';
import '../context_menu.dart';
@ -12,14 +10,16 @@ import 'in_app_webview_controller.dart';
import 'in_app_webview_settings.dart';
import 'headless_in_app_webview.dart';
import '../debug_settings.dart';
///Abstract class that represents a WebView. Used by [InAppWebView], [HeadlessInAppWebView] and the WebView of [InAppBrowser].
abstract class WebView {
///Enables [WebView] debug logging info.
///
///The default value is the same value of [kDebugMode],
///so it is enabled by default when the application is compiled in debug mode
///and disabled when it is not.
static bool debugLogging = kDebugMode;
///Debug settings used by [InAppWebView], [HeadlessInAppWebView] and [InAppBrowser].
///The default value excludes the [WebView.onScrollChanged] and [WebView.onOverScrolled] events.
static DebugSettings debugSettings = DebugSettings(excludeFilter: [
RegExp(r"onScrollChanged"),
RegExp(r"onOverScrolled")
]);
///The window id of a [CreateWindowAction.windowId].
final int? windowId;
@ -567,10 +567,13 @@ abstract class WebView {
///
///[resources] represents the array of resources the web content wants to access.
///
///**NOTE**: available only on Android 23+.
///**NOTE for Android**: available only on Android 23+.
///
///**NOTE for iOS**: available only on iOS 15.0+. The default [PermissionResponse.action] is [PermissionResponseAction.PROMPT].
///
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - WebChromeClient.onPermissionRequest](https://developer.android.com/reference/android/webkit/WebChromeClient#onPermissionRequest(android.webkit.PermissionRequest)))
///- iOS
final Future<PermissionResponse?> Function(InAppWebViewController controller,
PermissionRequest permissionRequest)? onPermissionRequest;

View File

@ -14,3 +14,4 @@ export 'http_auth_credentials_database.dart';
export 'context_menu.dart';
export 'pull_to_refresh/main.dart';
export 'web_message/main.dart';
export 'debug_settings.dart';