added isInFullscreen method

This commit is contained in:
Lorenzo Pichilli 2022-05-01 04:03:17 +02:00
parent 2a3e368780
commit 449bfd06ef
11 changed files with 110 additions and 29 deletions

View File

@ -2,7 +2,7 @@
- Deprecated old classes/properties/methods to make them eventually compatible with other Platforms and WebView engines. - Deprecated old classes/properties/methods to make them eventually compatible with other Platforms and WebView engines.
- Added Web support - Added Web support
- Added `pauseAllMediaPlayback`, `setAllMediaPlaybackSuspended`, `closeAllMediaPresentations`, `requestMediaPlaybackState` WebView controller methods - Added `pauseAllMediaPlayback`, `setAllMediaPlaybackSuspended`, `closeAllMediaPresentations`, `requestMediaPlaybackState`, `isInFullscreen` WebView controller methods
- Added `underPageBackgroundColor`, `isTextInteractionEnabled`, `isSiteSpecificQuirksModeEnabled`, `upgradeKnownHostsToHTTPS` WebView settings - Added `underPageBackgroundColor`, `isTextInteractionEnabled`, `isSiteSpecificQuirksModeEnabled`, `upgradeKnownHostsToHTTPS` WebView settings
- Added support for `onPermissionRequest` event on iOS 15.0+ - Added support for `onPermissionRequest` event on iOS 15.0+
- Updated `getMetaThemeColor` on iOS 15.0+ - Updated `getMetaThemeColor` on iOS 15.0+

View File

@ -598,6 +598,13 @@ public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandle
result.success(false); result.success(false);
} }
break; break;
case "isInFullscreen":
if (webView != null) {
result.success(webView.isInFullscreen());
} else {
result.success(false);
}
break;
default: default:
result.notImplemented(); result.notImplemented();
} }

View File

@ -121,6 +121,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
public JavaScriptBridgeInterface javaScriptBridgeInterface; public JavaScriptBridgeInterface javaScriptBridgeInterface;
public InAppWebViewSettings customSettings; public InAppWebViewSettings customSettings;
public boolean isLoading = false; public boolean isLoading = false;
private boolean inFullscreen = false;
public OkHttpClient httpClient; public OkHttpClient httpClient;
public float zoomScale = 1.0f; public float zoomScale = 1.0f;
int okHttpClientCacheSize = 10 * 1024 * 1024; // 10MB int okHttpClientCacheSize = 10 * 1024 * 1024; // 10MB
@ -187,7 +188,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
javaScriptBridgeInterface = new JavaScriptBridgeInterface(this); javaScriptBridgeInterface = new JavaScriptBridgeInterface(this);
addJavascriptInterface(javaScriptBridgeInterface, JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME); addJavascriptInterface(javaScriptBridgeInterface, JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME);
inAppWebViewChromeClient = new InAppWebViewChromeClient(plugin, channel, inAppBrowserDelegate); inAppWebViewChromeClient = new InAppWebViewChromeClient(plugin, channel, this, inAppBrowserDelegate);
setWebChromeClient(inAppWebViewChromeClient); setWebChromeClient(inAppWebViewChromeClient);
inAppWebViewClient = new InAppWebViewClient(channel, inAppBrowserDelegate); inAppWebViewClient = new InAppWebViewClient(channel, inAppBrowserDelegate);
@ -1691,6 +1692,16 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
return Looper.getMainLooper(); return Looper.getMainLooper();
} }
@Override
public boolean isInFullscreen() {
return inFullscreen;
}
@Override
public void setInFullscreen(boolean inFullscreen) {
this.inFullscreen = inFullscreen;
}
@Override @Override
public void postWebMessage(com.pichillilorenzo.flutter_inappwebview.types.WebMessage message, Uri targetOrigin, ValueCallback<String> callback) throws Exception { public void postWebMessage(com.pichillilorenzo.flutter_inappwebview.types.WebMessage message, Uri targetOrigin, ValueCallback<String> callback) throws Exception {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();

View File

@ -34,6 +34,7 @@ import android.widget.EditText;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
@ -45,6 +46,7 @@ import com.pichillilorenzo.flutter_inappwebview.in_app_browser.ActivityResultLis
import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserDelegate; import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserDelegate;
import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
import com.pichillilorenzo.flutter_inappwebview.R; import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.types.InAppWebViewInterface;
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest; import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -101,11 +103,15 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
private int mOriginalSystemUiVisibility; private int mOriginalSystemUiVisibility;
@Nullable @Nullable
public InAppWebViewFlutterPlugin plugin; public InAppWebViewFlutterPlugin plugin;
@Nullable
public InAppWebViewInterface inAppWebView;
public InAppWebViewChromeClient(final InAppWebViewFlutterPlugin plugin, MethodChannel channel, InAppBrowserDelegate inAppBrowserDelegate) { public InAppWebViewChromeClient(@NonNull final InAppWebViewFlutterPlugin plugin, MethodChannel channel,
@NonNull InAppWebViewInterface inAppWebView, InAppBrowserDelegate inAppBrowserDelegate) {
super(); super();
this.plugin = plugin; this.plugin = plugin;
this.channel = channel; this.channel = channel;
this.inAppWebView = inAppWebView;
this.inAppBrowserDelegate = inAppBrowserDelegate; this.inAppBrowserDelegate = inAppBrowserDelegate;
if (this.inAppBrowserDelegate != null) { if (this.inAppBrowserDelegate != null) {
this.inAppBrowserDelegate.getActivityResultListeners().add(this); this.inAppBrowserDelegate.getActivityResultListeners().add(this);
@ -142,6 +148,10 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onExitFullscreen", obj); channel.invokeMethod("onExitFullscreen", obj);
if (inAppWebView != null) {
inAppWebView.setInFullscreen(false);
}
} }
@Override @Override
@ -173,9 +183,13 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
} }
activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
((FrameLayout) decorView).addView(this.mCustomView, FULLSCREEN_LAYOUT_PARAMS); ((FrameLayout) decorView).addView(this.mCustomView, FULLSCREEN_LAYOUT_PARAMS);
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
channel.invokeMethod("onEnterFullscreen", obj); channel.invokeMethod("onEnterFullscreen", obj);
if (inAppWebView != null) {
inAppWebView.setInFullscreen(true);
}
} }
@Override @Override
@ -1221,5 +1235,6 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
inAppBrowserDelegate = null; inAppBrowserDelegate = null;
} }
plugin = null; plugin = null;
inAppWebView = null;
} }
} }

View File

@ -100,4 +100,6 @@ public interface InAppWebViewInterface {
void disposeWebMessageChannels(); void disposeWebMessageChannels();
void disposeWebMessageListeners(); void disposeWebMessageListeners();
Looper getWebViewLooper(); Looper getWebViewLooper();
boolean isInFullscreen();
void setInFullscreen(boolean inFullscreen);
} }

View File

@ -3,11 +3,11 @@
export "FLUTTER_ROOT=/Users/lorenzopichilli/fvm/versions/2.10.4" export "FLUTTER_ROOT=/Users/lorenzopichilli/fvm/versions/2.10.4"
export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example" export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example"
export "COCOAPODS_PARALLEL_CODE_SIGN=true" export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_TARGET=integration_test/webview_flutter_test.dart" export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/lib/main.dart"
export "FLUTTER_BUILD_DIR=build" export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=1.0.0" export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1" export "FLUTTER_BUILD_NUMBER=1"
export "DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==" export "DART_DEFINES=Zmx1dHRlci5pbnNwZWN0b3Iuc3RydWN0dXJlZEVycm9ycz10cnVl,RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
export "DART_OBFUSCATION=false" export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true" export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false" export "TREE_SHAKE_ICONS=false"

View File

@ -21,8 +21,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
mediaPlaybackRequiresUserGesture: false, mediaPlaybackRequiresUserGesture: false,
allowsInlineMediaPlayback: true, allowsInlineMediaPlayback: true,
iframeAllow: "camera; microphone", iframeAllow: "camera; microphone",
iframeAllowFullscreen: true, iframeAllowFullscreen: true
javaScriptEnabled: false
); );
PullToRefreshController? pullToRefreshController; PullToRefreshController? pullToRefreshController;
@ -115,7 +114,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
InAppWebView( InAppWebView(
key: webViewKey, key: webViewKey,
initialUrlRequest: initialUrlRequest:
URLRequest(url: Uri.parse("https://flutter.dev")), URLRequest(url: Uri.parse("https://www.youtube.com/watch?v=CylXr3AF3uU")),
// initialUrlRequest: // initialUrlRequest:
// URLRequest(url: Uri.parse(Uri.base.toString().replaceFirst("/#/", "/") + 'page.html')), // URLRequest(url: Uri.parse(Uri.base.toString().replaceFirst("/#/", "/") + 'page.html')),
// initialFile: "assets/index.html", // initialFile: "assets/index.html",
@ -218,12 +217,6 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
webViewController?.reload(); webViewController?.reload();
}, },
), ),
ElevatedButton(
child: Icon(Icons.refresh),
onPressed: () {
webViewController?.evaluateJavascript(source: "document.title='test';");
},
),
], ],
), ),
]))); ])));

View File

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

View File

@ -23,6 +23,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
var webMessageChannels: [String:WebMessageChannel] = [:] var webMessageChannels: [String:WebMessageChannel] = [:]
var webMessageListeners: [WebMessageListener] = [] var webMessageListeners: [WebMessageListener] = []
var currentOriginalUrl: URL? var currentOriginalUrl: URL?
var inFullscreen = false
static var sslCertificatesMap: [String: SslCertificate] = [:] // [URL host name : SslCertificate] static var sslCertificatesMap: [String: SslCertificate] = [:] // [URL host name : SslCertificate]
static var credentialsProposed: [URLCredential] = [] static var credentialsProposed: [URLCredential] = []
@ -320,17 +321,24 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
name: UIMenuController.didHideMenuNotification, name: UIMenuController.didHideMenuNotification,
object: nil) object: nil)
// listen for videos playing in fullscreen // if #available(iOS 15.0, *) {
NotificationCenter.default.addObserver(self, // addObserver(self,
selector: #selector(onEnterFullscreen(_:)), // forKeyPath: #keyPath(WKWebView.fullscreenState),
name: UIWindow.didBecomeVisibleNotification, // options: .new,
object: window) // context: nil)
// } else {
// listen for videos playing in fullscreen
NotificationCenter.default.addObserver(self,
selector: #selector(onEnterFullscreen(_:)),
name: UIWindow.didBecomeVisibleNotification,
object: window)
// listen for videos stopping to play in fullscreen // listen for videos stopping to play in fullscreen
NotificationCenter.default.addObserver(self, NotificationCenter.default.addObserver(self,
selector: #selector(onExitFullscreen(_:)), selector: #selector(onExitFullscreen(_:)),
name: UIWindow.didBecomeHiddenNotification, name: UIWindow.didBecomeHiddenNotification,
object: window) object: window)
// }
if let settings = settings { if let settings = settings {
if settings.transparentBackground { if settings.transparentBackground {
@ -639,6 +647,15 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
} }
} }
} }
// else if #available(iOS 15.0, *) {
// if keyPath == #keyPath(WKWebView.fullscreenState) {
// if fullscreenState == .enteringFullscreen {
// onEnterFullscreen()
// } else if fullscreenState == .exitingFullscreen {
// onExitFullscreen()
// }
// }
// }
replaceGestureHandlerIfNeeded() replaceGestureHandlerIfNeeded()
} }
@ -2676,7 +2693,9 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
public func isVideoPlayerWindow(_ notificationObject: AnyObject?) -> Bool { public func isVideoPlayerWindow(_ notificationObject: AnyObject?) -> Bool {
let nonVideoClasses = ["_UIAlertControllerShimPresenterWindow", let nonVideoClasses = ["_UIAlertControllerShimPresenterWindow",
"UITextEffectsWindow", "UITextEffectsWindow",
"UIRemoteKeyboardWindow"] "UIRemoteKeyboardWindow",
"PGHostedWindow"]
var isVideo = true var isVideo = true
if let obj = notificationObject { if let obj = notificationObject {
for nonVideoClass in nonVideoClasses { for nonVideoClass in nonVideoClasses {
@ -2690,16 +2709,26 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
@objc func onEnterFullscreen(_ notification: Notification) { @objc func onEnterFullscreen(_ notification: Notification) {
if (isVideoPlayerWindow(notification.object as AnyObject?)) { if (isVideoPlayerWindow(notification.object as AnyObject?)) {
channel?.invokeMethod("onEnterFullscreen", arguments: []) onEnterFullscreen()
inFullscreen = true
} }
} }
public func onEnterFullscreen() {
channel?.invokeMethod("onEnterFullscreen", arguments: [])
}
@objc func onExitFullscreen(_ notification: Notification) { @objc func onExitFullscreen(_ notification: Notification) {
if (isVideoPlayerWindow(notification.object as AnyObject?)) { if (isVideoPlayerWindow(notification.object as AnyObject?)) {
channel?.invokeMethod("onExitFullscreen", arguments: []) onExitFullscreen()
inFullscreen = false
} }
} }
public func onExitFullscreen() {
channel?.invokeMethod("onExitFullscreen", arguments: [])
}
// public func onContextMenuConfigurationForElement(linkURL: String?, result: FlutterResult?) { // public func onContextMenuConfigurationForElement(linkURL: String?, result: FlutterResult?) {
// let arguments: [String: Any?] = ["linkURL": linkURL] // let arguments: [String: Any?] = ["linkURL": linkURL]
// channel?.invokeMethod("onContextMenuConfigurationForElement", arguments: arguments, result: result) // channel?.invokeMethod("onContextMenuConfigurationForElement", arguments: arguments, result: result)
@ -3074,6 +3103,9 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
removeObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress)) removeObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress))
removeObserver(self, forKeyPath: #keyPath(WKWebView.url)) removeObserver(self, forKeyPath: #keyPath(WKWebView.url))
removeObserver(self, forKeyPath: #keyPath(WKWebView.title)) removeObserver(self, forKeyPath: #keyPath(WKWebView.title))
// if #available(iOS 15.0, *) {
// removeObserver(self, forKeyPath: #keyPath(WKWebView.fullscreenState))
// }
scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.contentOffset)) scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.contentOffset))
scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.zoomScale)) scrollView.removeObserver(self, forKeyPath: #keyPath(UIScrollView.zoomScale))
resumeTimers() resumeTimers()

View File

@ -592,6 +592,17 @@ public class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
result(nil) result(nil)
} }
break break
case "isInFullscreen":
// if let webView = webView, #available(iOS 15.0, *) {
// result(webView.fullscreenState == .inFullscreen)
// }
if let webView = webView {
result(webView.inFullscreen)
}
else {
result(false)
}
break
default: default:
result(FlutterMethodNotImplemented) result(FlutterMethodNotImplemented)
break break

View File

@ -3192,6 +3192,16 @@ class InAppWebViewController {
await _channel.invokeMethod('requestMediaPlaybackState', args)); await _channel.invokeMethod('requestMediaPlaybackState', args));
} }
///Returns `true` if the [WebView] is in fullscreen mode, otherwise `false`.
///
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS
Future<bool> isInFullscreen() async {
Map<String, dynamic> args = <String, dynamic>{};
return await _channel.invokeMethod('isInFullscreen', args);
}
///Returns the iframe `id` attribute used on the Web platform. ///Returns the iframe `id` attribute used on the Web platform.
/// ///
///**Supported Platforms/Implementations**: ///**Supported Platforms/Implementations**: