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
@@ -1,3 +1,7 @@
## 2.3.0

* Support new `onUrlChanged` event in platform interface.

## 2.2.1

* Fix `NullPointerException` from a race condition when changing focus. This only affects `WebView`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ void onLoadingProgress(int progress) {
}
}

private void onUrlChanged(WebView view, String url) {
Map<String, Object> args = new HashMap<>();
args.put("url", url);
methodChannel.invokeMethod("onUrlChanged", args);
}

private void onWebResourceError(
final int errorCode, final String description, final String failingUrl) {
final Map<String, Object> args = new HashMap<>();
Expand Down Expand Up @@ -205,6 +211,11 @@ public void onPageFinished(WebView view, String url) {
FlutterWebViewClient.this.onPageFinished(view, url);
}

@Override
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
FlutterWebViewClient.this.onUrlChanged(view, url);
}

@TargetApi(Build.VERSION_CODES.M)
@Override
public void onReceivedError(
Expand Down Expand Up @@ -252,6 +263,11 @@ public void onPageFinished(WebView view, String url) {
FlutterWebViewClient.this.onPageFinished(view, url);
}

@Override
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
FlutterWebViewClient.this.onUrlChanged(view, url);
}

// This method is only called when the WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR feature is
// enabled. The deprecated method is called when a device doesn't support this.
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Autogenerated from Pigeon (v1.0.9), do not edit directly.
// Autogenerated from Pigeon (v1.0.10), do not edit directly.
// See also: https://pub.dev/packages/pigeon

package io.flutter.plugins.webviewflutter;
Expand Down Expand Up @@ -1546,6 +1542,20 @@ public void onPageFinished(
});
}

public void onUrlChanged(
Long instanceIdArg, Long webViewInstanceIdArg, String urlArg, Reply<Void> callback) {
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.WebViewClientFlutterApi.onUrlChanged",
getCodec());
channel.send(
new ArrayList<Object>(Arrays.asList(instanceIdArg, webViewInstanceIdArg, urlArg)),
channelReply -> {
callback.reply(null);
});
}

public void onReceivedRequestError(
Long instanceIdArg,
Long webViewInstanceIdArg,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ public void onPageFinished(
callback);
}

/** Passes arguments from {@link WebViewClient#onUrlChanged} to Dart. */
public void onUrlChanged(
WebViewClient webViewClient, WebView webView, String urlArg, Reply<Void> callback) {
onUrlChanged(
instanceManager.getInstanceId(webViewClient),
instanceManager.getInstanceId(webView),
urlArg,
callback);
}

/**
* Passes arguments from {@link WebViewClient#onReceivedError(WebView, WebResourceRequest,
* WebResourceError)} to Dart.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ public void onPageFinished(WebView view, String url) {
}
}

@Override
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
if (flutterApi != null) {
flutterApi.onUrlChanged(this, view, url, reply -> {});
}
}

@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
if (flutterApi != null) {
Expand Down Expand Up @@ -142,6 +149,13 @@ public void onPageFinished(WebView view, String url) {
}
}

@Override
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
if (flutterApi != null) {
flutterApi.onUrlChanged(this, view, url, reply -> {});
}
}

// This method is only called when the WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR feature is
// enabled. The deprecated method is called when a device doesn't support this.
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;

import android.os.Build;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.webkit.WebViewClientCompat;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.webviewflutter.utils.TestUtils;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
Expand All @@ -30,7 +36,7 @@ public void before() {
}

@Test
public void notify_download_should_notifyOnNavigationRequest_when_navigationDelegate_is_set() {
public void notifyDownload_shouldNotifyOnNavigationRequestWhenNavigationDelegateIsSet() {
final String url = "testurl.com";

FlutterWebViewClient client = new FlutterWebViewClient(mockMethodChannel);
Expand All @@ -47,8 +53,7 @@ public void notify_download_should_notifyOnNavigationRequest_when_navigationDele
}

@Test
public void
notify_download_should_not_notifyOnNavigationRequest_when_navigationDelegate_is_not_set() {
public void notifyDownload_shouldNotNotifyOnNavigationRequestWhenNavigationDelegateIsNotSet() {
final String url = "testurl.com";

FlutterWebViewClient client = new FlutterWebViewClient(mockMethodChannel);
Expand All @@ -57,4 +62,44 @@ public void notify_download_should_notifyOnNavigationRequest_when_navigationDele
client.notifyDownload(mockWebView, url);
verifyNoInteractions(mockMethodChannel);
}

@Test
public void WebViewClient_doUpdateVisitedHistory_shouldCallOnUrlChangedEvent() {
// Setup
FlutterWebViewClient fltClient = new FlutterWebViewClient(mockMethodChannel);
WebViewClient client =
fltClient.createWebViewClient(
false // Force creation of internal WebViewClient.
);
WebView mockView = mock(WebView.class);
Map<String, Object> methodChannelData = new HashMap<>();
methodChannelData.put("url", "https://flutter.dev/");

//Run
client.doUpdateVisitedHistory(mockView, "https://flutter.dev/", false);

// Verify
Assert.assertFalse(client instanceof WebViewClientCompat);
verify(mockMethodChannel).invokeMethod(eq("onUrlChanged"), eq(methodChannelData));
}

@Test
public void WebViewClientCompat_doUpdateVisitedHistory_shouldCallOnUrlChangedEvent() {
// Setup
FlutterWebViewClient fltClient = new FlutterWebViewClient(mockMethodChannel);
// Force creation of internal WebViewClientCompat (< Android N).
TestUtils.setFinalStatic(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.M);
WebViewClient client = fltClient.createWebViewClient(true);

WebView mockView = mock(WebView.class);
Map<String, Object> methodChannelData = new HashMap<>();
methodChannelData.put("url", "https://flutter.dev/");

//Run
client.doUpdateVisitedHistory(mockView, "https://flutter.dev/", false);

// Verify
Assert.assertTrue(client instanceof WebViewClientCompat);
verify(mockMethodChannel).invokeMethod(eq("onUrlChanged"), eq(methodChannelData));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.webviewflutter;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import org.junit.Test;

public class WebViewClientHostApiImplTest {

@Test
public void WebViewClientImpl_doUpdateVisitedHistory_shouldCallOnUrlChangedEvent() {
WebViewClientFlutterApiImpl mockFlutterApi = mock(WebViewClientFlutterApiImpl.class);
WebViewClientHostApiImpl.WebViewClientImpl webViewClient =
new WebViewClientHostApiImpl.WebViewClientImpl(mockFlutterApi, false);

webViewClient.doUpdateVisitedHistory(null, "https://flutter.dev/", false);

verify(mockFlutterApi)
.onUrlChanged(eq(webViewClient), any(), eq("https://flutter.dev/"), any());
}

@Test
public void WebViewClientCompatImpl_doUpdateVisitedHistory_shouldCallOnUrlChangedEvent() {
WebViewClientFlutterApiImpl mockFlutterApi = mock(WebViewClientFlutterApiImpl.class);
WebViewClientHostApiImpl.WebViewClientCompatImpl webViewClient =
new WebViewClientHostApiImpl.WebViewClientCompatImpl(mockFlutterApi, false);

webViewClient.doUpdateVisitedHistory(null, "https://flutter.dev/", false);

verify(mockFlutterApi)
.onUrlChanged(eq(webViewClient), any(), eq("https://flutter.dev/"), any());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.webviewflutter.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.junit.Assert;

public class TestUtils {
public static <T> void setFinalStatic(Class<T> classToModify, String fieldName, Object newValue) {
try {
Field field = classToModify.getField(fieldName);
field.setAccessible(true);

Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

field.set(null, newValue);
} catch (Exception e) {
Assert.fail("Unable to mock static field: " + fieldName);
}
}

public static <T> void setPrivateField(T instance, String fieldName, Object newValue) {
try {
Field field = instance.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(instance, newValue);
} catch (Exception e) {
Assert.fail("Unable to mock private field: " + fieldName);
}
}

public static <T> Object getPrivateField(T instance, String fieldName) {
try {
Field field = instance.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(instance);
} catch (Exception e) {
Assert.fail("Unable to mock private field: " + fieldName);
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#Fri Jun 23 08:50:38 CEST 2017
#Mon Nov 15 16:20:35 CET 2021
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ typedef void PageFinishedCallback(String url);
/// Signature for when a [WebView] is loading a page.
typedef void PageLoadingCallback(int progress);

/// Signature for when a [WebView] changed its current URL.
typedef void UrlChangedCallback(String url);

/// Signature for when a [WebView] has failed to load a resource.
typedef void WebResourceErrorCallback(WebResourceError error);

Expand Down Expand Up @@ -68,6 +71,7 @@ class WebView extends StatefulWidget {
this.onPageStarted,
this.onPageFinished,
this.onProgress,
this.onUrlChanged,
this.onWebResourceError,
this.debuggingEnabled = false,
this.gestureNavigationEnabled = false,
Expand Down Expand Up @@ -197,6 +201,9 @@ class WebView extends StatefulWidget {
/// Invoked when a page is loading.
final PageLoadingCallback? onProgress;

/// Invoked when a webview's URL has changed.
final UrlChangedCallback? onUrlChanged;

/// Invoked when a web resource has failed to load.
///
/// This callback is only called for the main page.
Expand Down Expand Up @@ -345,6 +352,13 @@ class _PlatformCallbacksHandler implements WebViewPlatformCallbacksHandler {
}
}

@override
void onUrlChanged(String url) {
if (_webView.onUrlChanged != null) {
_webView.onUrlChanged!(url);
}
}

void onWebResourceError(WebResourceError error) {
if (_webView.onWebResourceError != null) {
_webView.onWebResourceError!(error);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

flutter pub run build_runner build
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,13 @@ abstract class WebViewClient {
/// reflect the state of the DOM at this point.
void onPageFinished(WebView webView, String url) {}

/// Notify the host application that a webview's URL has changed.
///
/// Unlike [onPageStarted], [onProgress], and [onPageFinished],
/// [onUrlChanged] also fires when navigating without a full page load
/// e.g. when using a single page application.
void onUrlChanged(WebView webView, String url) {}

/// Report web resource loading error to the host application.
///
/// These errors usually indicate inability to connect to the server. Note
Expand Down
Loading