added onCameraCaptureStateChanged and onMicrophoneCaptureStateChanged webview events

This commit is contained in:
Lorenzo Pichilli 2022-05-02 16:54:34 +02:00
parent 71c2093283
commit 17ed6c881a
8 changed files with 178 additions and 25 deletions

View File

@ -5,6 +5,7 @@
- Added `ProxyController` for Android
- Added `pauseAllMediaPlayback`, `setAllMediaPlaybackSuspended`, `closeAllMediaPresentations`, `requestMediaPlaybackState`, `isInFullscreen`, `getCameraCaptureState`, `setCameraCaptureState`, `getMicrophoneCaptureState`, `setMicrophoneCaptureState` WebView controller methods
- Added `underPageBackgroundColor`, `isTextInteractionEnabled`, `isSiteSpecificQuirksModeEnabled`, `upgradeKnownHostsToHTTPS`, `forceDarkStrategy` WebView settings
- Added `onCameraCaptureStateChanged`, `onMicrophoneCaptureStateChanged` WebView events
- Added support for `onPermissionRequest` event on iOS 15.0+
- Updated `getMetaThemeColor` on iOS 15.0+
- Deprecated `onLoadError` for `onReceivedError`. `onReceivedError` will be called also for subframes.

View File

@ -177,6 +177,7 @@
CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = PFP8UV45Y6;
LastSwiftMigration = 1020;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.BackgroundModes = {
enabled = 1;
@ -443,6 +444,8 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = PFP8UV45Y6;
ENABLE_BITCODE = NO;
@ -456,8 +459,9 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutter-inappwebview-Example";
PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterinappwebviewExample;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@ -471,6 +475,8 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = PFP8UV45Y6;
ENABLE_BITCODE = NO;
@ -484,8 +490,9 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutter-inappwebview-Example";
PRODUCT_BUNDLE_IDENTIFIER = com.pichillilorenzo.flutterinappwebviewExample;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";

View File

@ -309,6 +309,18 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
options: [.new, .old],
context: nil)
if #available(iOS 15.0, *) {
addObserver(self,
forKeyPath: #keyPath(WKWebView.cameraCaptureState),
options: [.new, .old],
context: nil)
addObserver(self,
forKeyPath: #keyPath(WKWebView.microphoneCaptureState),
options: [.new, .old],
context: nil)
}
NotificationCenter.default.addObserver(
self,
selector: #selector(onCreateContextMenu),
@ -628,18 +640,18 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
let progress = Int(estimatedProgress * 100)
onProgressChanged(progress: progress)
inAppBrowserDelegate?.didChangeProgress(progress: estimatedProgress)
} else if keyPath == #keyPath(WKWebView.url) && change?[NSKeyValueChangeKey.newKey] is URL {
} else if keyPath == #keyPath(WKWebView.url) && change?[.newKey] is URL {
initializeWindowIdJS()
let newUrl = change?[NSKeyValueChangeKey.newKey] as? URL
onUpdateVisitedHistory(url: newUrl?.absoluteString)
inAppBrowserDelegate?.didUpdateVisitedHistory(url: newUrl)
} else if keyPath == #keyPath(WKWebView.title) && change?[NSKeyValueChangeKey.newKey] is String {
let newTitle = change?[NSKeyValueChangeKey.newKey] as? String
} else if keyPath == #keyPath(WKWebView.title) && change?[.newKey] is String {
let newTitle = change?[.newKey] as? String
onTitleChanged(title: newTitle)
inAppBrowserDelegate?.didChangeTitle(title: newTitle)
} else if keyPath == #keyPath(UIScrollView.contentOffset) {
let newContentOffset = change?[NSKeyValueChangeKey.newKey] as? CGPoint
let oldContentOffset = change?[NSKeyValueChangeKey.oldKey] as? CGPoint
let newContentOffset = change?[.newKey] as? CGPoint
let oldContentOffset = change?[.oldKey] as? CGPoint
let startedByUser = scrollView.isDragging || scrollView.isDecelerating
if newContentOffset != oldContentOffset {
DispatchQueue.main.async {
@ -647,15 +659,30 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
}
}
}
// else if #available(iOS 15.0, *) {
// if keyPath == #keyPath(WKWebView.fullscreenState) {
else if #available(iOS 15.0, *) {
if keyPath == #keyPath(WKWebView.cameraCaptureState) || keyPath == #keyPath(WKWebView.microphoneCaptureState) {
var oldState: WKMediaCaptureState? = nil
if let oldValue = change?[.oldKey] as? Int {
oldState = WKMediaCaptureState.init(rawValue: oldValue)
}
var newState: WKMediaCaptureState? = nil
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)
}
}
// else if keyPath == #keyPath(WKWebView.fullscreenState) {
// if fullscreenState == .enteringFullscreen {
// onEnterFullscreen()
// } else if fullscreenState == .exitingFullscreen {
// onExitFullscreen()
// }
// }
// }
}
replaceGestureHandlerIfNeeded()
}
@ -2756,6 +2783,18 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
channel?.invokeMethod("onExitFullscreen", arguments: [])
}
@available(iOS 15.0, *)
public func onCameraCaptureStateChanged(oldState: WKMediaCaptureState?, newState: WKMediaCaptureState?) {
let arguments = ["oldState": oldState?.rawValue, "newState": newState?.rawValue]
channel?.invokeMethod("onCameraCaptureStateChanged", arguments: arguments)
}
@available(iOS 15.0, *)
public func onMicrophoneCaptureStateChanged(oldState: WKMediaCaptureState?, newState: WKMediaCaptureState?) {
let arguments = ["oldState": oldState?.rawValue, "newState": newState?.rawValue]
channel?.invokeMethod("onMicrophoneCaptureStateChanged", arguments: arguments)
}
// public func onContextMenuConfigurationForElement(linkURL: String?, result: FlutterResult?) {
// let arguments: [String: Any?] = ["linkURL": linkURL]
// channel?.invokeMethod("onContextMenuConfigurationForElement", arguments: arguments, result: result)
@ -3130,9 +3169,11 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
removeObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress))
removeObserver(self, forKeyPath: #keyPath(WKWebView.url))
removeObserver(self, forKeyPath: #keyPath(WKWebView.title))
// if #available(iOS 15.0, *) {
if #available(iOS 15.0, *) {
removeObserver(self, forKeyPath: #keyPath(WKWebView.cameraCaptureState))
removeObserver(self, forKeyPath: #keyPath(WKWebView.microphoneCaptureState))
// removeObserver(self, forKeyPath: #keyPath(WKWebView.fullscreenState))
// }
}
scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.contentOffset))
scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.zoomScale))
resumeTimers()

View File

@ -1047,6 +1047,28 @@ class InAppBrowser {
Future<ShouldAllowDeprecatedTLSAction?>? shouldAllowDeprecatedTLS(
URLAuthenticationChallenge challenge) {}
///Event fired when a change in the camera capture state occurred.
///
///**NOTE**: available only on iOS 15.0+.
///
///**Supported Platforms/Implementations**:
///- iOS
void onCameraCaptureStateChanged(
MediaCaptureState? oldState,
MediaCaptureState? newState,
) {}
///Event fired when a change in the microphone capture state occurred.
///
///**NOTE**: available only on iOS 15.0+.
///
///**Supported Platforms/Implementations**:
///- iOS
void onMicrophoneCaptureStateChanged(
MediaCaptureState? oldState,
MediaCaptureState? newState,
) {}
void throwIfAlreadyOpened({String message = ''}) {
if (this.isOpened()) {
throw InAppBrowserAlreadyOpenedException([

View File

@ -147,6 +147,8 @@ class HeadlessInAppWebView implements WebView {
@Deprecated('Use shouldAllowDeprecatedTLS instead')
this.iosShouldAllowDeprecatedTLS,
this.shouldAllowDeprecatedTLS,
this.onCameraCaptureStateChanged,
this.onMicrophoneCaptureStateChanged,
}) {
id = IdGenerator.generate();
webViewController = new InAppWebViewController(id, this);
@ -401,11 +403,10 @@ class HeadlessInAppWebView implements WebView {
///Use [onDownloadStartRequest] instead
@Deprecated('Use onDownloadStartRequest instead')
@override
final void Function(InAppWebViewController controller, Uri url)?
onDownloadStart;
void Function(InAppWebViewController controller, Uri url)? onDownloadStart;
@override
final void Function(InAppWebViewController controller,
void Function(InAppWebViewController controller,
DownloadStartRequest downloadStartRequest)? onDownloadStartRequest;
@override
@ -430,12 +431,12 @@ class HeadlessInAppWebView implements WebView {
///Use [onReceivedError] instead.
@Deprecated("Use onReceivedError instead")
@override
final void Function(InAppWebViewController controller, Uri? url, int code,
void Function(InAppWebViewController controller, Uri? url, int code,
String message)? onLoadError;
@override
final void Function(InAppWebViewController controller,
WebResourceRequest request, WebResourceError error)? onReceivedError;
void Function(InAppWebViewController controller, WebResourceRequest request,
WebResourceError error)? onReceivedError;
///Use [onReceivedHttpError] instead.
@Deprecated("Use onReceivedHttpError instead")
@ -443,9 +444,7 @@ class HeadlessInAppWebView implements WebView {
void Function(InAppWebViewController controller, Uri? url, int statusCode,
String description)? onLoadHttpError;
final void Function(
InAppWebViewController controller,
WebResourceRequest request,
void Function(InAppWebViewController controller, WebResourceRequest request,
WebResourceResponse errorResponse)? onReceivedHttpError;
@override
@ -662,4 +661,18 @@ class HeadlessInAppWebView implements WebView {
Future<WebResourceResponse?> Function(
InAppWebViewController controller, WebResourceRequest request)?
shouldInterceptRequest;
@override
Future<void> Function(
InAppWebViewController controller,
MediaCaptureState? oldState,
MediaCaptureState? newState,
)? onCameraCaptureStateChanged;
@override
Future<void> Function(
InAppWebViewController controller,
MediaCaptureState? oldState,
MediaCaptureState? newState,
)? onMicrophoneCaptureStateChanged;
}

View File

@ -139,6 +139,8 @@ class InAppWebView extends StatefulWidget implements WebView {
@Deprecated('Use shouldAllowDeprecatedTLS instead')
this.iosShouldAllowDeprecatedTLS,
this.shouldAllowDeprecatedTLS,
this.onCameraCaptureStateChanged,
this.onMicrophoneCaptureStateChanged,
this.gestureRecognizers,
}) : super(key: key);
@ -542,6 +544,20 @@ class InAppWebView extends StatefulWidget implements WebView {
final Future<WebResourceResponse?> Function(
InAppWebViewController controller, WebResourceRequest request)?
shouldInterceptRequest;
@override
final Future<void> Function(
InAppWebViewController controller,
MediaCaptureState? oldState,
MediaCaptureState? newState,
)? onCameraCaptureStateChanged;
@override
final Future<void> Function(
InAppWebViewController controller,
MediaCaptureState? oldState,
MediaCaptureState? newState,
)? onMicrophoneCaptureStateChanged;
}
class _InAppWebViewState extends State<InAppWebView> {
@ -680,7 +696,9 @@ class _InAppWebViewState extends State<InAppWebView> {
@override
void dispose() {
dynamic viewId = _controller?.getViewId();
if (viewId != null && kIsWeb && WebPlatformManager.webViews.containsKey(viewId)) {
if (viewId != null &&
kIsWeb &&
WebPlatformManager.webViews.containsKey(viewId)) {
WebPlatformManager.webViews.remove(viewId);
}
super.dispose();

View File

@ -1081,7 +1081,7 @@ class InAppWebViewController {
onLoadCallback != null) {
onLoadCallback();
}
return null;
break;
case "onInjectedScriptError":
String id = call.arguments[0];
var onErrorCallback = _injectedScriptsFromURL[id]?.onError;
@ -1089,7 +1089,31 @@ class InAppWebViewController {
onErrorCallback != null) {
onErrorCallback();
}
return null;
break;
case "onCameraCaptureStateChanged":
if ((_webview != null && _webview!.onCameraCaptureStateChanged != null) ||
_inAppBrowser != null) {
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);
else
_inAppBrowser!.onCameraCaptureStateChanged(oldState, newState);
}
break;
case "onMicrophoneCaptureStateChanged":
if ((_webview != null && _webview!.onMicrophoneCaptureStateChanged != null) ||
_inAppBrowser != null) {
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);
else
_inAppBrowser!.onMicrophoneCaptureStateChanged(oldState, newState);
}
break;
case "onCallJsHandler":
String handlerName = call.arguments["handlerName"];
// decode args to json

View File

@ -848,6 +848,30 @@ abstract class WebView {
InAppWebViewController controller,
URLAuthenticationChallenge challenge)? shouldAllowDeprecatedTLS;
///Event fired when a change in the camera capture state occurred.
///
///**NOTE**: available only on iOS 15.0+.
///
///**Supported Platforms/Implementations**:
///- iOS
final Future<void> Function(
InAppWebViewController controller,
MediaCaptureState? oldState,
MediaCaptureState? newState,
)? onCameraCaptureStateChanged;
///Event fired when a change in the microphone capture state occurred.
///
///**NOTE**: available only on iOS 15.0+.
///
///**Supported Platforms/Implementations**:
///- iOS
final Future<void> Function(
InAppWebViewController controller,
MediaCaptureState? oldState,
MediaCaptureState? newState,
)? onMicrophoneCaptureStateChanged;
///Initial url request that will be loaded.
///
///**NOTE for Android**: when loading an URL Request using "POST" method, headers are ignored.
@ -927,7 +951,8 @@ abstract class WebView {
@Deprecated('Use onReceivedError instead')
this.onLoadError,
this.onReceivedError,
@Deprecated("Use onReceivedHttpError instead") this.onLoadHttpError,
@Deprecated("Use onReceivedHttpError instead")
this.onLoadHttpError,
this.onReceivedHttpError,
this.onProgressChanged,
this.onConsoleMessage,
@ -1015,6 +1040,8 @@ abstract class WebView {
@Deprecated('Use shouldAllowDeprecatedTLS instead')
this.iosShouldAllowDeprecatedTLS,
this.shouldAllowDeprecatedTLS,
this.onCameraCaptureStateChanged,
this.onMicrophoneCaptureStateChanged,
this.initialUrlRequest,
this.initialFile,
this.initialData,