Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebStorage;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
Expand Down Expand Up @@ -371,6 +372,10 @@ private void applySettings(Map<String, Object> settings) {
Integer mode = (Integer) settings.get(key);
if (mode != null) updateJsMode(mode);
break;
case "mixedContentMode":
Integer mode = (Integer) settings.get(key);
if (mode != null) updateMixedContentMode(mode);
break;
case "hasNavigationDelegate":
final boolean hasNavigationDelegate = (boolean) settings.get(key);

Expand Down Expand Up @@ -416,6 +421,24 @@ private void updateJsMode(int mode) {
}
}

private void updateMixedContentMode(int mode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
switch (mode) {
case 0:
webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
break;
case 1:
webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_NEVER_ALLOW);
break;
case 2:
webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
break;
default:
throw new IllegalArgumentException("Trying to set unknown MixedContent mode: " + mode);
}
}
}

private void updateAutoMediaPlaybackPolicy(int mode) {
// This is the index of the AutoMediaPlaybackPolicy enum, index 1 is always_allow, for all
// other values we require a user gesture.
Expand Down
4 changes: 4 additions & 0 deletions packages/webview_flutter/lib/platform_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ class WebSettings {
/// The `userAgent` parameter must not be null.
WebSettings({
this.javascriptMode,
this.mixedContentMode,
this.hasNavigationDelegate,
this.hasProgressTracking,
this.debuggingEnabled,
Expand All @@ -402,6 +403,9 @@ class WebSettings {
/// The JavaScript execution mode to be used by the webview.
final JavascriptMode? javascriptMode;

///mixedContentMode in WebSettings
final MixedContentMode? mixedContentMode;

/// Whether the [WebView] has a [NavigationDelegate] set.
final bool? hasNavigationDelegate;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController {
}

_addIfNonNull('jsMode', settings!.javascriptMode?.index);
_addIfNonNull('mixedContentMode', settings!.mixedContentMode?.index);
_addIfNonNull('hasNavigationDelegate', settings.hasNavigationDelegate);
_addIfNonNull('hasProgressTracking', settings.hasProgressTracking);
_addIfNonNull('debuggingEnabled', settings.debuggingEnabled);
Expand Down
87 changes: 46 additions & 41 deletions packages/webview_flutter/lib/webview_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ enum JavascriptMode {
unrestricted,
}

/// Describes the state of MixedContent support in webSettings.
enum MixedContentMode {
/// WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
MIXED_CONTENT_ALWAYS_ALLOW,

/// WebSettings.MIXED_CONTENT_NEVER_ALLOW
MIXED_CONTENT_NEVER_ALLOW,

/// WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE
MIXED_CONTENT_COMPATIBILITY_MODE,
}

/// A message that was sent by JavaScript code running in a [WebView].
class JavascriptMessage {
/// Constructs a JavaScript message object.
Expand Down Expand Up @@ -96,8 +108,7 @@ class SurfaceAndroidWebView extends AndroidWebView {
) {
return AndroidViewSurface(
controller: controller as AndroidViewController,
gestureRecognizers: gestureRecognizers ??
const <Factory<OneSequenceGestureRecognizer>>{},
gestureRecognizers: gestureRecognizers ?? const <Factory<OneSequenceGestureRecognizer>>{},
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
);
},
Expand Down Expand Up @@ -136,8 +147,7 @@ class SurfaceAndroidWebView extends AndroidWebView {
/// `navigation` should be handled.
///
/// See also: [WebView.navigationDelegate].
typedef FutureOr<NavigationDecision> NavigationDelegate(
NavigationRequest navigation);
typedef FutureOr<NavigationDecision> NavigationDelegate(NavigationRequest navigation);

/// Signature for when a [WebView] has started loading a page.
typedef void PageStartedCallback(String url);
Expand Down Expand Up @@ -180,7 +190,7 @@ class JavascriptChannel {
JavascriptChannel({
required this.name,
required this.onMessageReceived,
}) : assert(name != null),
}) : assert(name != null),
assert(onMessageReceived != null),
assert(_validChannelNames.hasMatch(name));

Expand Down Expand Up @@ -218,6 +228,7 @@ class WebView extends StatefulWidget {
this.onWebViewCreated,
this.initialUrl,
this.javascriptMode = JavascriptMode.disabled,
this.mixedContentMode = MixedContentMode.MIXED_CONTENT_NEVER_ALLOW,
this.javascriptChannels,
this.navigationDelegate,
this.gestureRecognizers,
Expand All @@ -228,8 +239,7 @@ class WebView extends StatefulWidget {
this.debuggingEnabled = false,
this.gestureNavigationEnabled = false,
this.userAgent,
this.initialMediaPlaybackPolicy =
AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
this.initialMediaPlaybackPolicy = AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
this.allowsInlineMediaPlayback = false,
}) : assert(javascriptMode != null),
assert(initialMediaPlaybackPolicy != null),
Expand Down Expand Up @@ -289,6 +299,9 @@ class WebView extends StatefulWidget {
/// Whether Javascript execution is enabled.
final JavascriptMode javascriptMode;

/// MixedContentMode in WebSettings
final MixedContentMode mixedContentMode;

/// The set of [JavascriptChannel]s available to JavaScript code running in the web view.
///
/// For each [JavascriptChannel] in the set, a channel object is made available for the
Expand Down Expand Up @@ -420,8 +433,7 @@ class WebView extends StatefulWidget {
}

class _WebViewState extends State<WebView> {
final Completer<WebViewController> _controller =
Completer<WebViewController>();
final Completer<WebViewController> _controller = Completer<WebViewController>();

late _PlatformCallbacksHandler _platformCallbacksHandler;

Expand Down Expand Up @@ -454,21 +466,18 @@ class _WebViewState extends State<WebView> {
}

void _onWebViewPlatformCreated(WebViewPlatformController? webViewPlatform) {
final WebViewController controller = WebViewController._(
widget, webViewPlatform!, _platformCallbacksHandler);
final WebViewController controller = WebViewController._(widget, webViewPlatform!, _platformCallbacksHandler);
_controller.complete(controller);
if (widget.onWebViewCreated != null) {
widget.onWebViewCreated!(controller);
}
}

void _assertJavascriptChannelNamesAreUnique() {
if (widget.javascriptChannels == null ||
widget.javascriptChannels!.isEmpty) {
if (widget.javascriptChannels == null || widget.javascriptChannels!.isEmpty) {
return;
}
assert(_extractChannelNames(widget.javascriptChannels).length ==
widget.javascriptChannels!.length);
assert(_extractChannelNames(widget.javascriptChannels).length == widget.javascriptChannels!.length);
}
}

Expand All @@ -485,6 +494,7 @@ CreationParams _creationParamsfromWidget(WebView widget) {
WebSettings _webSettingsFromWidget(WebView widget) {
return WebSettings(
javascriptMode: widget.javascriptMode,
mixedContentMode: widget.mixedContentMode,
hasNavigationDelegate: widget.navigationDelegate != null,
hasProgressTracking: widget.onProgress != null,
debuggingEnabled: widget.debuggingEnabled,
Expand All @@ -495,9 +505,9 @@ WebSettings _webSettingsFromWidget(WebView widget) {
}

// This method assumes that no fields in `currentValue` are null.
WebSettings _clearUnchangedWebSettings(
WebSettings currentValue, WebSettings newValue) {
WebSettings _clearUnchangedWebSettings(WebSettings currentValue, WebSettings newValue) {
assert(currentValue.javascriptMode != null);
assert(currentValue.mixedContentMode != null);
assert(currentValue.hasNavigationDelegate != null);
assert(currentValue.hasProgressTracking != null);
assert(currentValue.debuggingEnabled != null);
Expand All @@ -508,13 +518,17 @@ WebSettings _clearUnchangedWebSettings(
assert(newValue.userAgent != null);

JavascriptMode? javascriptMode;
MixedContentMode? mixedContentMode;
bool? hasNavigationDelegate;
bool? hasProgressTracking;
bool? debuggingEnabled;
WebSetting<String?> userAgent = WebSetting.absent();
if (currentValue.javascriptMode != newValue.javascriptMode) {
javascriptMode = newValue.javascriptMode;
}
if (currentValue.mixedContentMode != newValue.mixedContentMode) {
mixedContentMode = newValue.mixedContentMode;
}
if (currentValue.hasNavigationDelegate != newValue.hasNavigationDelegate) {
hasNavigationDelegate = newValue.hasNavigationDelegate;
}
Expand All @@ -530,6 +544,7 @@ WebSettings _clearUnchangedWebSettings(

return WebSettings(
javascriptMode: javascriptMode,
mixedContentMode: mixedContentMode,
hasNavigationDelegate: hasNavigationDelegate,
hasProgressTracking: hasProgressTracking,
debuggingEnabled: debuggingEnabled,
Expand All @@ -538,9 +553,8 @@ WebSettings _clearUnchangedWebSettings(
}

Set<String> _extractChannelNames(Set<JavascriptChannel>? channels) {
final Set<String> channelNames = channels == null
? <String>{}
: channels.map((JavascriptChannel channel) => channel.name).toSet();
final Set<String> channelNames =
channels == null ? <String>{} : channels.map((JavascriptChannel channel) => channel.name).toSet();
return channelNames;
}

Expand All @@ -552,8 +566,7 @@ class _PlatformCallbacksHandler implements WebViewPlatformCallbacksHandler {
WebView _widget;

// Maps a channel name to a channel.
final Map<String, JavascriptChannel> _javascriptChannels =
<String, JavascriptChannel>{};
final Map<String, JavascriptChannel> _javascriptChannels = <String, JavascriptChannel>{};

@override
void onJavaScriptChannelMessage(String channel, String message) {
Expand All @@ -565,11 +578,9 @@ class _PlatformCallbacksHandler implements WebViewPlatformCallbacksHandler {
required String url,
required bool isForMainFrame,
}) async {
final NavigationRequest request =
NavigationRequest._(url: url, isForMainFrame: isForMainFrame);
final bool allowNavigation = _widget.navigationDelegate == null ||
await _widget.navigationDelegate!(request) ==
NavigationDecision.navigate;
final NavigationRequest request = NavigationRequest._(url: url, isForMainFrame: isForMainFrame);
final bool allowNavigation =
_widget.navigationDelegate == null || await _widget.navigationDelegate!(request) == NavigationDecision.navigate;
return allowNavigation;
}

Expand Down Expand Up @@ -717,24 +728,18 @@ class WebViewController {
}

Future<void> _updateSettings(WebSettings newSettings) {
final WebSettings update =
_clearUnchangedWebSettings(_settings, newSettings);
final WebSettings update = _clearUnchangedWebSettings(_settings, newSettings);
_settings = newSettings;
return _webViewPlatformController.updateSettings(update);
}

Future<void> _updateJavascriptChannels(
Set<JavascriptChannel>? newChannels) async {
final Set<String> currentChannels =
_platformCallbacksHandler._javascriptChannels.keys.toSet();
Future<void> _updateJavascriptChannels(Set<JavascriptChannel>? newChannels) async {
final Set<String> currentChannels = _platformCallbacksHandler._javascriptChannels.keys.toSet();
final Set<String> newChannelNames = _extractChannelNames(newChannels);
final Set<String> channelsToAdd =
newChannelNames.difference(currentChannels);
final Set<String> channelsToRemove =
currentChannels.difference(newChannelNames);
final Set<String> channelsToAdd = newChannelNames.difference(currentChannels);
final Set<String> channelsToRemove = currentChannels.difference(newChannelNames);
if (channelsToRemove.isNotEmpty) {
await _webViewPlatformController
.removeJavascriptChannels(channelsToRemove);
await _webViewPlatformController.removeJavascriptChannels(channelsToRemove);
}
if (channelsToAdd.isNotEmpty) {
await _webViewPlatformController.addJavascriptChannels(channelsToAdd);
Expand All @@ -760,8 +765,8 @@ class WebViewController {
/// embedded in the main frame HTML has been loaded.
Future<String> evaluateJavascript(String javascriptString) {
if (_settings.javascriptMode == JavascriptMode.disabled) {
return Future<String>.error(FlutterError(
'JavaScript mode must be enabled/unrestricted when calling evaluateJavascript.'));
return Future<String>.error(
FlutterError('JavaScript mode must be enabled/unrestricted when calling evaluateJavascript.'));
}
// TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter.
// https://github.com/flutter/flutter/issues/26431
Expand Down