Added isRunning method to the HeadlessInAppWebView class, Fixed iOS WebMessageListener javascript implementation not calling event listeners when onmessage is set, Fixed onCreateContextMenu event on Android where hitTestResult has always null values, fix #742

This commit is contained in:
Lorenzo Pichilli 2021-03-23 17:13:40 +01:00
parent 01f2108304
commit a3e4da3e61
8 changed files with 94 additions and 70 deletions

View File

@ -1,3 +1,10 @@
## 5.2.1
- Added `isRunning` method to the `HeadlessInAppWebView` class
- Fixed iOS `WebMessageListener` javascript implementation not calling event listeners when `onmessage` is set
- Fixed `onCreateContextMenu` event on Android where `hitTestResult` has always `null` values
- Fixed "java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.SearchView.setQuery(java.lang.CharSequence, boolean)' on a null object reference" [#742](https://github.com/pichillilorenzo/flutter_inappwebview/issues/742)
## 5.2.0
- Added `WebMessageChannel` and `WebMessageListener` features

View File

@ -401,43 +401,57 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
@Override
public void didChangeTitle(String title) {
if (options.toolbarTopFixedTitle == null || options.toolbarTopFixedTitle.isEmpty()) {
if (actionBar != null && (options.toolbarTopFixedTitle == null || options.toolbarTopFixedTitle.isEmpty())) {
actionBar.setTitle(title);
}
}
@Override
public void didStartNavigation(String url) {
progressBar.setProgress(0);
searchView.setQuery(url, false);
if (progressBar != null) {
progressBar.setProgress(0);
}
if (searchView != null) {
searchView.setQuery(url, false);
}
}
@Override
public void didUpdateVisitedHistory(String url) {
searchView.setQuery(url, false);
if (searchView != null) {
searchView.setQuery(url, false);
}
}
@Override
public void didFinishNavigation(String url) {
searchView.setQuery(url, false);
progressBar.setProgress(0);
if (searchView != null) {
searchView.setQuery(url, false);
}
if (progressBar != null) {
progressBar.setProgress(0);
}
}
@Override
public void didFailNavigation(String url, int errorCode, String description) {
progressBar.setProgress(0);
if (progressBar != null) {
progressBar.setProgress(0);
}
}
@Override
public void didChangeProgress(int progress) {
progressBar.setVisibility(View.VISIBLE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
progressBar.setProgress(progress, true);
} else {
progressBar.setProgress(progress);
}
if (progress == 100) {
progressBar.setVisibility(View.GONE);
if (progressBar != null) {
progressBar.setVisibility(View.VISIBLE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
progressBar.setProgress(progress, true);
} else {
progressBar.setProgress(progress);
}
if (progress == 100) {
progressBar.setVisibility(View.GONE);
}
}
}

View File

@ -232,11 +232,11 @@ final public class InAppWebView extends InputAwareWebView {
if (options.userAgent != null && !options.userAgent.isEmpty())
settings.setUserAgentString(options.userAgent);
else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
settings.setUserAgentString(WebSettings.getDefaultUserAgent(getContext()));
if (options.applicationNameForUserAgent != null && !options.applicationNameForUserAgent.isEmpty()) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
String userAgent = (options.userAgent != null && !options.userAgent.isEmpty()) ? options.userAgent : WebSettings.getDefaultUserAgent(getContext());
String userAgentWithApplicationName = userAgent + " " + options.applicationNameForUserAgent;
settings.setUserAgentString(userAgentWithApplicationName);
@ -390,7 +390,7 @@ final public class InAppWebView extends InputAwareWebView {
@Override
public void run() {
int newPosition = getScrollY();
if(initialPositionScrollStoppedTask - newPosition == 0){
if (initialPositionScrollStoppedTask - newPosition == 0) {
// has stopped
onScrollStopped();
} else {
@ -436,8 +436,7 @@ final public class InAppWebView extends InputAwareWebView {
if (options.disableHorizontalScroll && options.disableVerticalScroll) {
return (event.getAction() == MotionEvent.ACTION_MOVE);
}
else if (options.disableHorizontalScroll || options.disableVerticalScroll) {
} else if (options.disableHorizontalScroll || options.disableVerticalScroll) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
// save the x
@ -512,8 +511,7 @@ final public class InAppWebView extends InputAwareWebView {
clearFormData();
settings.setSavePassword(false);
settings.setSaveFormData(false);
}
else {
} else {
settings.setCacheMode(WebSettings.LOAD_DEFAULT);
settings.setAppCacheEnabled(true);
settings.setSavePassword(true);
@ -703,7 +701,7 @@ final public class InAppWebView extends InputAwareWebView {
settings.setUserAgentString(newOptions.userAgent);
if (newOptionsMap.get("applicationNameForUserAgent") != null && !options.applicationNameForUserAgent.equals(newOptions.applicationNameForUserAgent) && !newOptions.applicationNameForUserAgent.isEmpty()) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
String userAgent = (newOptions.userAgent != null && !newOptions.userAgent.isEmpty()) ? newOptions.userAgent : WebSettings.getDefaultUserAgent(getContext());
String userAgentWithApplicationName = userAgent + " " + options.applicationNameForUserAgent;
settings.setUserAgentString(userAgentWithApplicationName);
@ -797,7 +795,7 @@ final public class InAppWebView extends InputAwareWebView {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
if (newOptionsMap.get("disabledActionModeMenuItems") != null && (options.disabledActionModeMenuItems == null ||
!options.disabledActionModeMenuItems.equals(newOptions.disabledActionModeMenuItems)))
!options.disabledActionModeMenuItems.equals(newOptions.disabledActionModeMenuItems)))
settings.setDisabledActionModeMenuItems(newOptions.disabledActionModeMenuItems);
if (newOptionsMap.get("fantasyFontFamily") != null && !options.fantasyFontFamily.equals(newOptions.fantasyFontFamily))
@ -834,7 +832,7 @@ final public class InAppWebView extends InputAwareWebView {
settings.setMinimumLogicalFontSize(newOptions.minimumLogicalFontSize);
if (newOptionsMap.get("initialScale") != null && !options.initialScale.equals(newOptions.initialScale))
setInitialScale(newOptions.initialScale);
setInitialScale(newOptions.initialScale);
if (newOptionsMap.get("needInitialFocus") != null && options.needInitialFocus != newOptions.needInitialFocus)
settings.setNeedInitialFocus(newOptions.needInitialFocus);
@ -926,7 +924,7 @@ final public class InAppWebView extends InputAwareWebView {
if (newOptionsMap.get("rendererPriorityPolicy") != null &&
(options.rendererPriorityPolicy.get("rendererRequestedPriority") != newOptions.rendererPriorityPolicy.get("rendererRequestedPriority") ||
options.rendererPriorityPolicy.get("waivedWhenNotVisible") != newOptions.rendererPriorityPolicy.get("waivedWhenNotVisible")) &&
options.rendererPriorityPolicy.get("waivedWhenNotVisible") != newOptions.rendererPriorityPolicy.get("waivedWhenNotVisible")) &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setRendererPriorityPolicy(
(int) newOptions.rendererPriorityPolicy.get("rendererRequestedPriority"),
@ -1120,7 +1118,7 @@ final public class InAppWebView extends InputAwareWebView {
List<HashMap<String, String>> history = new ArrayList<HashMap<String, String>>();
for(int i = 0; i < currentSize; i++) {
for (int i = 0; i < currentSize; i++) {
WebHistoryItem historyItem = currentList.getItemAtIndex(i);
HashMap<String, String> historyItemMap = new HashMap<>();
@ -1140,10 +1138,10 @@ final public class InAppWebView extends InputAwareWebView {
}
@Override
protected void onScrollChanged (int x,
int y,
int oldX,
int oldY) {
protected void onScrollChanged(int x,
int y,
int oldX,
int oldY) {
super.onScrollChanged(x, y, oldX, oldY);
if (floatingContextMenu != null) {
@ -1194,8 +1192,7 @@ final public class InAppWebView extends InputAwareWebView {
final String newUserAgent;
if (enabled) {
newUserAgent = webSettings.getUserAgentString().replace("Mobile", "eliboM").replace("Android", "diordnA");
}
else {
} else {
newUserAgent = webSettings.getUserAgentString().replace("eliboM", "Mobile").replace("diordnA", "Android");
}
@ -1237,12 +1234,9 @@ final public class InAppWebView extends InputAwareWebView {
private void sendOnCreateContextMenuEvent() {
HitTestResult hitTestResult = getHitTestResult();
Map<String, Object> hitTestResultMap = new HashMap<>();
hitTestResultMap.put("type", hitTestResult.getType());
hitTestResultMap.put("extra", hitTestResult.getExtra());
Map<String, Object> obj = new HashMap<>();
obj.put("hitTestResult", hitTestResultMap);
obj.put("type", hitTestResult.getType());
obj.put("extra", hitTestResult.getExtra());
channel.invokeMethod("onCreateContextMenu", obj);
}
@ -1283,21 +1277,21 @@ final public class InAppWebView extends InputAwareWebView {
// workaround to hide the Keyboard when the user click outside
// on something not focusable such as input or a textarea.
containerView
.getHandler()
.postDelayed(
new Runnable() {
@Override
public void run() {
InputMethodManager imm =
(InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
if (imm != null && !imm.isAcceptingText()) {
.getHandler()
.postDelayed(
new Runnable() {
@Override
public void run() {
InputMethodManager imm =
(InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
if (imm != null && !imm.isAcceptingText()) {
imm.hideSoftInputFromWindow(
containerView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
},
128);
imm.hideSoftInputFromWindow(
containerView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
},
128);
}
return connection;
}
@ -1353,9 +1347,9 @@ final public class InAppWebView extends InputAwareWebView {
if (contextMenu != null) {
customMenuItems = (List<Map<String, Object>>) contextMenu.get("menuItems");
Map<String, Object> contextMenuOptionsMap = (Map<String, Object>) contextMenu.get("options");
if (contextMenuOptionsMap != null) {
contextMenuOptions.parse(contextMenuOptionsMap);
}
if (contextMenuOptionsMap != null) {
contextMenuOptions.parse(contextMenuOptionsMap);
}
}
customMenuItems = customMenuItems == null ? new ArrayList<Map<String, Object>>() : customMenuItems;
@ -1604,7 +1598,7 @@ final public class InAppWebView extends InputAwareWebView {
.replace(PluginScriptsUtil.VAR_RESULT_UUID, resultUuid);
sourceToInject = userContentController.generateCodeForScriptEvaluation(sourceToInject, contentWorld);
evaluateJavascript(sourceToInject, null);
evaluateJavascript(sourceToInject, null);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@ -1621,7 +1615,7 @@ final public class InAppWebView extends InputAwareWebView {
}
});
}
public boolean canScrollVertically() {
return computeVerticalScrollRange() > computeVerticalScrollExtent();
}

View File

@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.1.0-10.0.pre/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.1.0-10.0.pre/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-03-22 16:27:21.616305","version":"2.1.0-10.0.pre"}
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.1.0-10.0.pre/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.1.0-10.0.pre/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-03-23 16:33:10.809487","version":"2.1.0-10.0.pre"}

View File

@ -136,10 +136,9 @@ public class WebMessageListener : FlutterMethodCallDelegate {
var event = {data: '\(messageEscaped)'};
if (webMessageListener.onmessage != null) {
webMessageListener.onmessage(event);
} else {
for (var listener of webMessageListener.listeners) {
listener(event);
}
}
for (var listener of webMessageListener.listeners) {
listener(event);
}
}
})();

View File

@ -7,6 +7,7 @@ import '../_static_channel.dart';
import '../../types.dart';
import '../../android/webview_feature.dart';
import '../in_app_webview_controller.dart';
///Class represents the Android controller that contains only android-specific methods for the WebView.
class AndroidInAppWebViewController {
@ -42,7 +43,7 @@ class AndroidInAppWebViewController {
}
///Does a best-effort attempt to pause any processing that can be paused safely, such as animations and geolocation. Note that this call does not pause JavaScript.
///To pause JavaScript globally, use [pauseTimers()]. To resume WebView, call [resume()].
///To pause JavaScript globally, use [InAppWebViewController.pauseTimers]. To resume WebView, call [resume].
///
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#onPause()
Future<void> pause() async {
@ -50,7 +51,7 @@ class AndroidInAppWebViewController {
await _channel.invokeMethod('pause', args);
}
///Resumes a WebView after a previous call to [pause()].
///Resumes a WebView after a previous call to [pause].
///
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#onResume()
Future<void> resume() async {

View File

@ -20,7 +20,9 @@ class HeadlessInAppWebView implements WebView {
///View ID.
late final String id;
bool _isDisposed = true;
bool _started = false;
bool _running = false;
static const MethodChannel _sharedChannel =
const MethodChannel('com.pichillilorenzo/flutter_headless_inappwebview');
@ -111,10 +113,10 @@ class HeadlessInAppWebView implements WebView {
///Runs the headless WebView.
Future<void> run() async {
if (!_isDisposed) {
if (_started) {
return;
}
_isDisposed = false;
_started = true;
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('id', () => id);
args.putIfAbsent(
@ -135,17 +137,24 @@ class HeadlessInAppWebView implements WebView {
PullToRefreshOptions(enabled: false).toMap()
});
await _sharedChannel.invokeMethod('createHeadlessWebView', args);
_running = true;
}
///Disposes the headless WebView.
Future<void> dispose() async {
if (_isDisposed) {
if (!_running) {
return;
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('id', () => id);
await _sharedChannel.invokeMethod('disposeHeadlessWebView', args);
_isDisposed = true;
_started = false;
_running = false;
}
///Indicates if the headless WebView is running or not.
bool isRunning() {
return _running;
}
@override

View File

@ -1,6 +1,6 @@
name: flutter_inappwebview
description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window.
version: 5.2.0
version: 5.2.1
homepage: https://github.com/pichillilorenzo/flutter_inappwebview
environment: