Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[webview_flutter_wkwebview][webview_flutter_android] Fixes bug where the WebViews could not be released #6996

Merged
merged 17 commits into from
Jan 31, 2023
Merged
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
@@ -1,3 +1,8 @@
## 3.2.3

* Fixes bug that prevented the web view from being garbage collected.
* Fixes bug causing a `LateInitializationError` when a `PlatformNavigationDelegate` is not provided.

## 3.2.2

* Updates example code for `use_build_context_synchronously` lint.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:webview_flutter_android/src/android_webview.dart' as android;
import 'package:webview_flutter_android/src/android_webview_api_impls.dart';
import 'package:webview_flutter_android/src/instance_manager.dart';
import 'package:webview_flutter_android/src/weak_reference_utils.dart';
import 'package:webview_flutter_android/webview_flutter_android.dart';
Expand Down Expand Up @@ -58,15 +60,13 @@ Future<void> main() async {
)
..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
),
);
await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

await pageFinished.future;

Expand Down Expand Up @@ -96,6 +96,79 @@ Future<void> main() async {
expect(gcIdentifier, 0);
}, timeout: const Timeout(Duration(seconds: 10)));

testWidgets(
'WebView is released by garbage collection',
(WidgetTester tester) async {
final Completer<void> webViewGCCompleter = Completer<void>();

late final InstanceManager instanceManager;
instanceManager =
InstanceManager(onWeakReferenceRemoved: (int identifier) {
final Copyable instance =
instanceManager.getInstanceWithWeakReference(identifier)!;
if (instance is android.WebView && !webViewGCCompleter.isCompleted) {
webViewGCCompleter.complete();
}
});

android.WebView.api = WebViewHostApiImpl(
instanceManager: instanceManager,
);
android.WebSettings.api = WebSettingsHostApiImpl(
instanceManager: instanceManager,
);
android.WebChromeClient.api = WebChromeClientHostApiImpl(
instanceManager: instanceManager,
);

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
AndroidWebViewWidgetCreationParams(
instanceManager: instanceManager,
controller: PlatformWebViewController(
const PlatformWebViewControllerCreationParams(),
),
),
).build(context);
},
),
);
await tester.pumpAndSettle();

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
AndroidWebViewWidgetCreationParams(
instanceManager: instanceManager,
controller: PlatformWebViewController(
const PlatformWebViewControllerCreationParams(),
),
),
).build(context);
},
),
);
await tester.pumpAndSettle();

// Force garbage collection.
await IntegrationTestWidgetsFlutterBinding.instance
.watchPerformance(() async {
await tester.pumpAndSettle();
});

await tester.pumpAndSettle();
await expectLater(webViewGCCompleter.future, completes);

android.WebView.api = WebViewHostApiImpl();
android.WebSettings.api = WebSettingsHostApiImpl();
android.WebChromeClient.api = WebChromeClientHostApiImpl();
},
timeout: const Timeout(Duration(seconds: 10)),
);

testWidgets('runJavaScriptReturningResult', (WidgetTester tester) async {
final Completer<void> pageFinished = Completer<void>();

Expand All @@ -110,15 +183,13 @@ Future<void> main() async {
)
..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
),
);
await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

await pageFinished.future;

Expand Down Expand Up @@ -151,15 +222,13 @@ Future<void> main() async {
),
);

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
),
);
await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

await pageLoads.stream.firstWhere((String url) => url == headersUrl);

Expand Down Expand Up @@ -195,15 +264,13 @@ Future<void> main() async {
'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
);

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
),
);
await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

await pageFinished.future;

Expand Down Expand Up @@ -258,15 +325,13 @@ Future<void> main() async {
..setUserAgent('Custom_User_Agent1')
..loadRequest(LoadRequestParams(uri: Uri.parse('about:blank')));

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
),
);
await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

await pageFinished.future;

Expand Down Expand Up @@ -335,15 +400,13 @@ Future<void> main() async {
),
);

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
),
);
await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

await pageLoaded.future;

Expand All @@ -369,15 +432,13 @@ Future<void> main() async {
),
);

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
),
);
await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

await pageLoaded.future;

Expand Down Expand Up @@ -491,15 +552,13 @@ Future<void> main() async {
),
);

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
),
);
await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

await pageLoaded.future;

Expand All @@ -525,15 +584,13 @@ Future<void> main() async {
),
);

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
),
);
await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

await pageLoaded.future;

Expand Down Expand Up @@ -573,15 +630,13 @@ Future<void> main() async {
),
);

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
),
);
await tester.pumpWidget(Builder(
builder: (BuildContext context) {
return PlatformWebViewWidget(
PlatformWebViewWidgetCreationParams(controller: controller),
).build(context);
},
));

await pageLoaded.future;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,28 +96,30 @@ class AndroidWebViewController extends PlatformWebViewController {
);

late final android_webview.WebChromeClient _webChromeClient =
withWeakReferenceTo(this,
(WeakReference<AndroidWebViewController> weakReference) {
return _androidWebViewParams.androidWebViewProxy
.createAndroidWebChromeClient(
onProgressChanged: (android_webview.WebView webView, int progress) {
if (weakReference.target?._currentNavigationDelegate._onProgress !=
_androidWebViewParams.androidWebViewProxy.createAndroidWebChromeClient(
onProgressChanged: withWeakReferenceTo(this,
(WeakReference<AndroidWebViewController> weakReference) {
return (android_webview.WebView webView, int progress) {
if (weakReference.target?._currentNavigationDelegate?._onProgress !=
null) {
weakReference
.target!._currentNavigationDelegate._onProgress!(progress);
.target!._currentNavigationDelegate!._onProgress!(progress);
}
},
onShowFileChooser: (android_webview.WebView webView,
};
}),
onShowFileChooser: withWeakReferenceTo(this,
(WeakReference<AndroidWebViewController> weakReference) {
return (android_webview.WebView webView,
android_webview.FileChooserParams params) async {
if (weakReference.target?._onShowFileSelectorCallback != null) {
return weakReference.target!._onShowFileSelectorCallback!(
FileSelectorParams._fromFileChooserParams(params),
);
}
return <String>[];
},
);
});
};
}),
);

/// The native [android_webview.FlutterAssetManager] allows managing assets.
late final android_webview.FlutterAssetManager _flutterAssetManager =
Expand All @@ -126,10 +128,7 @@ class AndroidWebViewController extends PlatformWebViewController {
final Map<String, AndroidJavaScriptChannelParams> _javaScriptChannelParams =
<String, AndroidJavaScriptChannelParams>{};

// The keeps a reference to the current NavigationDelegate so that the
// callback methods remain reachable.
// ignore: unused_field
late AndroidNavigationDelegate _currentNavigationDelegate;
AndroidNavigationDelegate? _currentNavigationDelegate;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making this nullable fixes flutter/flutter#119332


Future<List<String>> Function(FileSelectorParams)?
_onShowFileSelectorCallback;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: webview_flutter_android
description: A Flutter plugin that provides a WebView widget on Android.
repository: https://github.com/flutter/plugins/tree/main/packages/webview_flutter/webview_flutter_android
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
version: 3.2.2
version: 3.2.3

environment:
sdk: ">=2.17.0 <3.0.0"
Expand Down
Loading