Skip to content

Commit dc7bc50

Browse files
android: Added InAppWebViewController.enableSlowWholeDocumentDraw static method, Added CookieManager.flush method, Updated InAppWebViewController.takeScreenshot implementation to support screenshot out of visible viewport when InAppWebViewController.enableSlowWholeDocumentDraw is called, fix #2354
1 parent 22e492d commit dc7bc50

File tree

13 files changed

+151
-47
lines changed

13 files changed

+151
-47
lines changed

flutter_inappwebview/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
#### Platform Interface
1212
- Updated static `fromMap` implementation for some classes
1313

14+
#### Android Platform
15+
- Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method
16+
- Added `CookieManager.flush` method
17+
- Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called
18+
1419
#### iOS Platform
1520
- Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error
1621

flutter_inappwebview/lib/src/cookie_manager.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ class CookieManager {
143143

144144
///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.removeSessionCookies}
145145
Future<bool> removeSessionCookies() => platform.removeSessionCookies();
146+
147+
///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.flush}
148+
Future<void> flush() => platform.flush();
146149
}
147150

148151
///Class that contains only iOS-specific methods of [CookieManager].

flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,11 @@ class InAppWebViewController {
565565
PlatformInAppWebViewController.static()
566566
.clearAllCache(includeDiskFiles: includeDiskFiles);
567567

568+
///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.enableSlowWholeDocumentDraw}
569+
static Future<void> enableSlowWholeDocumentDraw() =>
570+
PlatformInAppWebViewController.static()
571+
.enableSlowWholeDocumentDraw();
572+
568573
///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.tRexRunnerHtml}
569574
static Future<String> get tRexRunnerHtml =>
570575
PlatformInAppWebViewController.static().tRexRunnerHtml;

flutter_inappwebview_android/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
## 1.2.0
22

33
- Updated flutter_inappwebview_platform_interface version to ^1.4.0
4+
- Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method
5+
- Added `CookieManager.flush` method
6+
- Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called
47

58
## 1.1.3
69

flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/MyCookieManager.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result
103103
case "removeSessionCookies":
104104
removeSessionCookies(result);
105105
break;
106+
case "flush":
107+
flush(result);
108+
break;
106109
default:
107110
result.notImplemented();
108111
}
@@ -423,6 +426,20 @@ else if (plugin != null) {
423426
}
424427
}
425428

429+
public void flush(MethodChannel.Result result) {
430+
cookieManager = getCookieManager();
431+
if (cookieManager == null) {
432+
result.success(false);
433+
return;
434+
}
435+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
436+
cookieManager.flush();
437+
} else if (plugin != null) {
438+
CookieSyncManager cookieSyncMngr = CookieSyncManager.createInstance(plugin.applicationContext);
439+
cookieSyncMngr.sync();
440+
}
441+
}
442+
426443
public static String getCookieExpirationDate(Long timestamp) {
427444
final SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss z", Locale.US);
428445
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));

flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,14 @@ public void onReceiveValue(Boolean value) {
162162
}
163163
result.success(true);
164164
break;
165+
case "enableSlowWholeDocumentDraw":
166+
{
167+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
168+
WebView.enableSlowWholeDocumentDraw();
169+
}
170+
}
171+
result.success(true);
172+
break;
165173
default:
166174
result.notImplemented();
167175
}

flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java

Lines changed: 57 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -215,16 +215,17 @@ public WebViewClient createWebViewClient(InAppBrowserDelegate inAppBrowserDelega
215215
}
216216

217217
boolean isChromiumWebView = "com.android.webview".equals(packageInfo.packageName) ||
218-
"com.google.android.webview".equals(packageInfo.packageName) ||
219-
"com.android.chrome".equals(packageInfo.packageName);
218+
"com.google.android.webview".equals(packageInfo.packageName) ||
219+
"com.android.chrome".equals(packageInfo.packageName);
220220
boolean isChromiumWebViewBugFixed = false;
221221
if (isChromiumWebView) {
222222
String versionName = packageInfo.versionName != null ? packageInfo.versionName : "";
223223
try {
224224
int majorVersion = versionName.contains(".") ?
225225
Integer.parseInt(versionName.split("\\.")[0]) : 0;
226226
isChromiumWebViewBugFixed = majorVersion >= 73;
227-
} catch (NumberFormatException ignored) {}
227+
} catch (NumberFormatException ignored) {
228+
}
228229
}
229230

230231
if (isChromiumWebViewBugFixed || !isChromiumWebView) {
@@ -704,36 +705,21 @@ public void takeScreenshot(final @Nullable Map<String, Object> screenshotConfigu
704705
@Override
705706
public void run() {
706707
try {
707-
Bitmap screenshotBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
708-
Canvas c = new Canvas(screenshotBitmap);
709-
c.translate(-getScrollX(), -getScrollY());
710-
draw(c);
708+
int bitmapWidth = getMeasuredWidth();
709+
int bitmapHeight = getMeasuredHeight();
710+
int bitmapScrollX = getScrollX();
711+
int bitmapScrollY = getScrollY();
711712

712-
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
713713
Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.PNG;
714714
int quality = 100;
715715

716716
if (screenshotConfiguration != null) {
717717
Map<String, Double> rect = (Map<String, Double>) screenshotConfiguration.get("rect");
718718
if (rect != null) {
719-
int rectX = (int) Math.floor(rect.get("x") * pixelDensity + 0.5);
720-
int rectY = (int) Math.floor(rect.get("y") * pixelDensity + 0.5);
721-
int rectWidth = Math.min(screenshotBitmap.getWidth(), (int) Math.floor(rect.get("width") * pixelDensity + 0.5));
722-
int rectHeight = Math.min(screenshotBitmap.getHeight(), (int) Math.floor(rect.get("height") * pixelDensity + 0.5));
723-
screenshotBitmap = Bitmap.createBitmap(
724-
screenshotBitmap,
725-
rectX,
726-
rectY,
727-
rectWidth,
728-
rectHeight);
729-
}
730-
731-
Double snapshotWidth = (Double) screenshotConfiguration.get("snapshotWidth");
732-
if (snapshotWidth != null) {
733-
int dstWidth = (int) Math.floor(snapshotWidth * pixelDensity + 0.5);
734-
float ratioBitmap = (float) screenshotBitmap.getWidth() / (float) screenshotBitmap.getHeight();
735-
int dstHeight = (int) ((float) dstWidth / ratioBitmap);
736-
screenshotBitmap = Bitmap.createScaledBitmap(screenshotBitmap, dstWidth, dstHeight, true);
719+
bitmapScrollX = (int) Math.floor(rect.get("x") * pixelDensity + 0.5);
720+
bitmapScrollY = (int) Math.floor(rect.get("y") * pixelDensity + 0.5);
721+
bitmapWidth = (int) Math.floor(rect.get("width") * pixelDensity + 0.5);
722+
bitmapHeight = (int) Math.floor(rect.get("height") * pixelDensity + 0.5);
737723
}
738724

739725
try {
@@ -745,10 +731,31 @@ public void run() {
745731
quality = (Integer) screenshotConfiguration.get("quality");
746732
}
747733

748-
screenshotBitmap.compress(
734+
Bitmap screenshotBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
735+
Canvas c = new Canvas(screenshotBitmap);
736+
c.translate(-bitmapScrollX, -bitmapScrollY);
737+
draw(c);
738+
739+
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
740+
741+
if (screenshotConfiguration != null) {
742+
Double snapshotWidth = (Double) screenshotConfiguration.get("snapshotWidth");
743+
if (snapshotWidth != null) {
744+
int dstWidth = (int) Math.floor(snapshotWidth * pixelDensity + 0.5);
745+
float ratioBitmap = (float) screenshotBitmap.getWidth() / (float) screenshotBitmap.getHeight();
746+
int dstHeight = (int) ((float) dstWidth / ratioBitmap);
747+
screenshotBitmap = Bitmap.createScaledBitmap(screenshotBitmap, dstWidth, dstHeight, true);
748+
}
749+
}
750+
751+
final boolean compressed = screenshotBitmap.compress(
749752
compressFormat,
750753
quality,
751754
byteArrayOutputStream);
755+
if (!compressed) {
756+
Log.e(LOG_TAG, "Screenshot cannot be compressed using compressFormat " +
757+
compressFormat.name() + " with quality " + quality, null);
758+
}
752759

753760
try {
754761
byteArrayOutputStream.close();
@@ -932,7 +939,7 @@ else if (newSettingsMap.get("clearSessionCache") != null && newCustomSettings.cl
932939

933940
if (newSettingsMap.get("disabledActionModeMenuItems") != null &&
934941
(customSettings.disabledActionModeMenuItems == null ||
935-
!customSettings.disabledActionModeMenuItems.equals(newCustomSettings.disabledActionModeMenuItems))) {
942+
!customSettings.disabledActionModeMenuItems.equals(newCustomSettings.disabledActionModeMenuItems))) {
936943
if (WebViewFeature.isFeatureSupported(WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS))
937944
WebSettingsCompat.setDisabledActionModeMenuItems(settings, newCustomSettings.disabledActionModeMenuItems);
938945
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
@@ -1164,7 +1171,7 @@ public void injectDeferredObject(String source, @Nullable final ContentWorld con
11641171
if (resultUuid != null && resultCallback != null) {
11651172
evaluateJavaScriptContentWorldCallbacks.put(resultUuid, resultCallback);
11661173
scriptToInject = Util.replaceAll(PluginScriptsUtil.EVALUATE_JAVASCRIPT_WITH_CONTENT_WORLD_WRAPPER_JS_SOURCE,
1167-
PluginScriptsUtil.VAR_RANDOM_NAME, "_" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_" + Math.round(Math.random() * 1000000))
1174+
PluginScriptsUtil.VAR_RANDOM_NAME, "_" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_" + Math.round(Math.random() * 1000000))
11681175
.replace(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, UserContentController.escapeCode(source))
11691176
.replace(PluginScriptsUtil.VAR_RESULT_UUID, resultUuid);
11701177
}
@@ -1209,15 +1216,15 @@ public void injectJavascriptFileFromUrl(String urlFile, @Nullable Map<String, Ob
12091216
String scriptIdEscaped = idAttr.replaceAll("'", "\\\\'");
12101217
scriptAttributes += " script.id = '" + scriptIdEscaped + "'; ";
12111218
scriptAttributes += " script.onload = function() {" +
1212-
" if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + " != null) {" +
1213-
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onInjectedScriptLoaded', '" + scriptIdEscaped + "');" +
1214-
" }" +
1215-
"};";
1219+
" if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + " != null) {" +
1220+
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onInjectedScriptLoaded', '" + scriptIdEscaped + "');" +
1221+
" }" +
1222+
"};";
12161223
scriptAttributes += " script.onerror = function() {" +
1217-
" if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + " != null) {" +
1218-
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onInjectedScriptError', '" + scriptIdEscaped + "');" +
1219-
" }" +
1220-
"};";
1224+
" if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + " != null) {" +
1225+
" window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onInjectedScriptError', '" + scriptIdEscaped + "');" +
1226+
" }" +
1227+
"};";
12211228
}
12221229
Boolean asyncAttr = (Boolean) scriptHtmlTagAttributes.get("async");
12231230
if (asyncAttr != null && asyncAttr) {
@@ -1368,13 +1375,13 @@ class DownloadStartListener implements DownloadListener {
13681375
@Override
13691376
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
13701377
DownloadStartRequest downloadStartRequest = new DownloadStartRequest(
1371-
url,
1372-
userAgent,
1373-
contentDisposition,
1374-
mimeType,
1375-
contentLength,
1376-
URLUtil.guessFileName(url, contentDisposition, mimeType),
1377-
null
1378+
url,
1379+
userAgent,
1380+
contentDisposition,
1381+
mimeType,
1382+
contentLength,
1383+
URLUtil.guessFileName(url, contentDisposition, mimeType),
1384+
null
13781385
);
13791386
if (channelDelegate != null) channelDelegate.onDownloadStartRequest(downloadStartRequest);
13801387
}
@@ -1516,7 +1523,8 @@ protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolea
15161523
}
15171524

15181525
if (overScrolledHorizontally || overScrolledVertically) {
1519-
if (channelDelegate != null) channelDelegate.onOverScrolled(scrollX, scrollY, overScrolledHorizontally, overScrolledVertically);
1526+
if (channelDelegate != null)
1527+
channelDelegate.onOverScrolled(scrollX, scrollY, overScrolledHorizontally, overScrolledVertically);
15201528
}
15211529
}
15221530

@@ -1639,7 +1647,8 @@ public void onClick(View v) {
16391647
hideContextMenu();
16401648
callback.onActionItemClicked(actionMode, menuItem);
16411649

1642-
if (channelDelegate != null) channelDelegate.onContextMenuActionItemClicked(itemId, itemTitle);
1650+
if (channelDelegate != null)
1651+
channelDelegate.onContextMenuActionItemClicked(itemId, itemTitle);
16431652
}
16441653
});
16451654
if (floatingContextMenu != null) {
@@ -1659,7 +1668,8 @@ public void onClick(View v) {
16591668
public void onClick(View v) {
16601669
hideContextMenu();
16611670

1662-
if (channelDelegate != null) channelDelegate.onContextMenuActionItemClicked(itemId, itemTitle);
1671+
if (channelDelegate != null)
1672+
channelDelegate.onContextMenuActionItemClicked(itemId, itemTitle);
16631673
}
16641674
});
16651675
if (floatingContextMenu != null) {

flutter_inappwebview_android/lib/src/cookie_manager.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,12 @@ class AndroidCookieManager extends PlatformCookieManager
209209
false;
210210
}
211211

212+
@override
213+
Future<void> flush() async {
214+
Map<String, dynamic> args = <String, dynamic>{};
215+
await channel?.invokeMethod('flush', args);
216+
}
217+
212218
@override
213219
void dispose() {
214220
// empty

flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2738,6 +2738,12 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController
27382738
await _staticChannel.invokeMethod('clearAllCache', args);
27392739
}
27402740

2741+
@override
2742+
Future<void> enableSlowWholeDocumentDraw() async {
2743+
Map<String, dynamic> args = <String, dynamic>{};
2744+
await _staticChannel.invokeMethod('enableSlowWholeDocumentDraw', args);
2745+
}
2746+
27412747
@override
27422748
Future<String> get tRexRunnerHtml async => await rootBundle.loadString(
27432749
'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html');

flutter_inappwebview_platform_interface/lib/src/in_app_browser/platform_in_app_browser.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,9 @@ abstract class PlatformInAppBrowserEvents {
12181218
///The application's implementation of this callback should only attempt to clean up the WebView.
12191219
///The WebView should be removed from the view hierarchy, all references to it should be cleaned up.
12201220
///
1221+
///To cause an render process crash for test purpose, the application can call load url `"chrome://crash"` on the WebView.
1222+
///Note that multiple WebView instances may be affected if they share a render process, not just the specific WebView which loaded `"chrome://crash"`.
1223+
///
12211224
///[detail] the reason why it exited.
12221225
///
12231226
///**NOTE**: available only on Android 26+.

0 commit comments

Comments
 (0)