Open sofitry opened 9 months ago
👋 @sofitry
NOTE: This comment is auto-generated.
Are you sure you have already searched for the same problem?
Some people open new issues but they didn't search for something similar or for the same issue. Please, search for it using the GitHub issue search box or on the official inappwebview.dev website, or, also, using Google, StackOverflow, etc. before posting a new one. You may already find an answer to your problem!
If this is really a new issue, then thank you for raising it. I will investigate it and get back to you as soon as possible. Please, make sure you have given me as much context as possible! Also, if you didn't already, post a code example that can replicate this issue.
In the meantime, you can already search for some possible solutions online! Because this plugin uses native WebView, you can search online for the same issue adding android WebView [MY ERROR HERE]
or ios WKWebView [MY ERROR HERE]
keywords.
Following these steps can save you, me, and other people a lot of time, thanks!
@pichillilorenzo Hello, lorenzo.
I think this issue ocurred by this parts.
location.replace function is only replace current history of window. It doesn't add history.
But when shoudlOverrideUrlLoading is true and return NavigationActionPolicy.ALLOW on shouldOverrideUrlLoading
method, then webView.loadUrl is called.
So, when NavigationActionPolicy is 'ALLOW' then we should call WebViewClient's shoudlOverrideUrlLoading method
return super.shouldOverrideUrlLoading(view, request);
But, I think this is breaking changes...
@jhpung the WebViewClient.shouldOverrideUrlLoading
native event is implemented to return a boolean
in a synchronous way, that's impossible to handle on Flutter side.
This is the only possible implementation for Android.
iOS and macOS allows to handle that event asynchronously.
@pichillilorenzo Thanks, lorenzo. that make sense...
could a blocking adapter be made to work in android?
Like shouldOverrideUrlLoading calls a blocking function that starts a thread waiting for the message from Flutter? (probably with a timeout) Not sure how well the webview code would tolerate being blocked - if at all.
Alternatively - A feature request to allow passing some "rules" in that can be executed synchronously. Like a list of Patterns to be checked and if one matches, return ALLOW, otherwise BLOCK. (or something like that) would provide a reasonable workaround.
Second alternate - if there is any way to determine if the replace function was used, then either: remove it from the backstack manually, or provide a flag to shouldOverrideUrlLoading
so the implementing code can attempt to handle it.
shouldOverrideUrlLoading
we can't block that method because it is running on UiThread
unfortunately.
I have already tried to do something like that in the past.
For subframe loading, you can use InAppWebViewSettings.regexToCancelSubFramesLoading
, from the API Reference:
Regular expression used by [PlatformWebViewCreationParams.shouldOverrideUrlLoading] event to cancel navigation requests for frames that are not the main frame. If the url request of a subframe matches the regular expression, then the request of that subframe is canceled.
Officially Supported Platforms/Implementations:
- Android native WebView
Probably, this could be something possible to implement:
Alternatively - A feature request to allow passing some "rules" in that can be executed synchronously. Like a list of Patterns to be checked and if one matches, return ALLOW, otherwise BLOCK. (or something like that) would provide a reasonable workaround.
By the way, I'm trying your example code with the latest plugin version 6 and it seems to work already fine. Plugin version 6 has changed quite a bit of things on the native platform side, so it seems that is already fixed. Consider that plugin version 5 won't be updated.
This is the updated example code to support the latest version 6:
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
const String pageWithAutoRedirect = '''
<!DOCTYPE html>
<html>
<head>
<title>Back button demo</title>
<script>
function myFunction() {
setTimeout(function() { location.replace("https://developer.mozilla.org/en-US/docs/Web/API/Location/replace"); }, 1000);
}
</script>
</head>
<body onload=myFunction()>
<h1>This will auto-navigate in 1 second!</h1>
<p>If the webview functions correctly, this page should be removed from history</p>
</body>
</html>
''';
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: Column(
children: [
Expanded(child: WebViewExample()),
Divider(),
Expanded(child: WebViewExample(implementOnNavigationRequest: true)),
],
),
);
}
}
class WebViewExample extends StatefulWidget {
const WebViewExample({super.key, this.implementOnNavigationRequest = false});
final bool implementOnNavigationRequest;
@override
State<WebViewExample> createState() => _WebViewExampleState();
}
class _WebViewExampleState extends State<WebViewExample> {
late InAppWebViewController? _controller;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green,
appBar: AppBar(
title:
Text(widget.implementOnNavigationRequest ? 'Incorrect' : 'Correct'),
),
body: InAppWebView(
key: UniqueKey(),
initialData: InAppWebViewInitialData(data: pageWithAutoRedirect),
initialSettings: InAppWebViewSettings(
javaScriptEnabled: true,
useShouldOverrideUrlLoading: widget.implementOnNavigationRequest,
),
onWebViewCreated: (controller) {
_controller = controller;
},
),
floatingActionButton: backButton(),
);
}
Widget backButton() {
return FloatingActionButton(
onPressed: () async {
final canGoBack = await _controller?.canGoBack() ?? false;
if (!canGoBack) {
debugPrint('Cannot navigate back!');
} else {
_controller?.goBack();
}
},
child: const Icon(Icons.navigate_before),
);
}
@override
void dispose() {
_controller = null;
super.dispose();
}
}
Screenshot:
Console logs:
Launching lib/main.dart on sdk gphone64 x86 64 in debug mode...
Running Gradle task 'assembleDebug'...
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
Installing build/app/outputs/flutter-apk/app-debug.apk...
Debug service listening on ws://127.0.0.1:50141/sD3_LPh9eHo=/ws
Syncing files to device sdk gphone64 x86 64...
W/ziparchive(10830): Unable to open '/data/app/~~jFLGCCN07QmCpb5O4Y83TQ==/com.google.android.trichromelibrary_604506638-9EXXktfUCP0f3a0kfvUmkw==/base.dm': No such file or directory
W/ziparchive(10830): Unable to open '/data/app/~~jFLGCCN07QmCpb5O4Y83TQ==/com.google.android.trichromelibrary_604506638-9EXXktfUCP0f3a0kfvUmkw==/base.dm': No such file or directory
W/pwebviewexample(10830): Entry not found
D/nativeloader(10830): Configuring clns-7 for other apk /data/app/~~jFLGCCN07QmCpb5O4Y83TQ==/com.google.android.trichromelibrary_604506638-9EXXktfUCP0f3a0kfvUmkw==/base.apk. target_sdk_version=34, uses_libraries=ALL, library_path=/data/app/~~9F9kSkEBEvVgdmCwTD5dIw==/com.google.android.webview-Yo8awwv35yYXYMcGrNV9NA==/lib/x86_64:/data/app/~~9F9kSkEBEvVgdmCwTD5dIw==/com.google.android.webview-Yo8awwv35yYXYMcGrNV9NA==/base.apk!/lib/x86_64:/data/app/~~jFLGCCN07QmCpb5O4Y83TQ==/com.google.android.trichromelibrary_604506638-9EXXktfUCP0f3a0kfvUmkw==/base.apk!/lib/x86_64, permitted_path=/data:/mnt/expand
D/nativeloader(10830): Configuring clns-8 for other apk /data/app/~~9F9kSkEBEvVgdmCwTD5dIw==/com.google.android.webview-Yo8awwv35yYXYMcGrNV9NA==/base.apk. target_sdk_version=34, uses_libraries=, library_path=/data/app/~~9F9kSkEBEvVgdmCwTD5dIw==/com.google.android.webview-Yo8awwv35yYXYMcGrNV9NA==/lib/x86_64:/data/app/~~9F9kSkEBEvVgdmCwTD5dIw==/com.google.android.webview-Yo8awwv35yYXYMcGrNV9NA==/base.apk!/lib/x86_64:/data/app/~~jFLGCCN07QmCpb5O4Y83TQ==/com.google.android.trichromelibrary_604506638-9EXXktfUCP0f3a0kfvUmkw==/base.apk!/lib/x86_64, permitted_path=/data:/mnt/expand
I/WebViewFactory(10830): Loading com.google.android.webview version 119.0.6045.66 (code 604506638)
I/cr_WVCFactoryProvider(10830): Loaded version=119.0.6045.66 minSdkVersion=29 isBundle=true multiprocess=true packageId=2
E/chromium(10830): [1207/002933.409404:ERROR:variations_seed_loader.cc(37)] Seed missing signature.
E/chromium(10830): [1207/002933.412846:ERROR:variations_seed_loader.cc(69)] Failed to open file for reading. Errno: 2
I/cr_LibraryLoader(10830): Successfully loaded native library
I/cr_CachingUmaRecorder(10830): Flushed 7 samples from 7 histograms, 0 samples were dropped.
I/cr_CombinedPProvider(10830): #registerProvider() provider:WV.w7@f8dfb1a isPolicyCacheEnabled:false policyProvidersSize:0
I/cr_PolicyProvider(10830): #setManagerAndSource() 0
I/cr_CombinedPProvider(10830): #linkNativeInternal() 1
D/CompatibilityChangeReporter(10830): Compat change id reported: 183155436; UID 10191; state: ENABLED
I/cr_AppResProvider(10830): #getApplicationRestrictionsFromUserManager() Bundle[EMPTY_PARCEL]
I/cr_PolicyProvider(10830): #notifySettingsAvailable() 0
I/cr_CombinedPProvider(10830): #onSettingsAvailable() 0
I/cr_CombinedPProvider(10830): #flushPolicies()
D/CompatibilityChangeReporter(10830): Compat change id reported: 214741472; UID 10191; state: ENABLED
D/CompatibilityChangeReporter(10830): Compat change id reported: 171228096; UID 10191; state: ENABLED
D/InAppWebView(10830): Using InAppWebViewClientCompat implementation
W/cr_WebSettings(10830): setForceDark() is a no-op in an app with targetSdkVersion>=T
W/cr_SupportWebSettings(10830): setForceDarkBehavior() is a no-op in an app with targetSdkVersion>=T
W/cr_media(10830): BLUETOOTH_CONNECT permission is missing.
W/cr_media(10830): registerBluetoothIntentsIfNeeded: Requires BLUETOOTH permission
I/PlatformViewsController(10830): Using hybrid composition for platform view: 0
D/InAppWebView(10830): Using InAppWebViewClientCompat implementation
W/cr_WebSettings(10830): setForceDark() is a no-op in an app with targetSdkVersion>=T
W/cr_SupportWebSettings(10830): setForceDarkBehavior() is a no-op in an app with targetSdkVersion>=T
I/PlatformViewsController(10830): Using hybrid composition for platform view: 1
[AndroidInAppWebViewWidget] (android) AndroidInAppWebViewWidget ID 0 calling "onWebViewCreated" using []
[AndroidInAppWebViewWidget] (android) AndroidInAppWebViewWidget ID 1 calling "onWebViewCreated" using []
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 10}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onProgressChanged" using {progress: 10}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onLoadStart" using {url: about:blank}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onUpdateVisitedHistory" using {isReload: false, url: about:blank}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 70}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onLoadStart" using {url: about:blank}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onUpdateVisitedHistory" using {isReload: false, url: about:blank}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onProgressChanged" using {progress: 70}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onTitleChanged" using {title: Back button demo}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onTitleChanged" using {title: Back button demo}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onProgressChanged" using {progress: 80}
D/CompatibilityChangeReporter(10830): Compat change id reported: 236825255; UID 10191; state: ENABLED
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onProgressChanged" using {progress: 100}
D/CompatibilityChangeReporter(10830): Compat change id reported: 193247900; UID 10191; state: ENABLED
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onLoadStop" using {url: about:blank}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onPageCommitVisible" using {url: about:blank}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 80}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onZoomScaleChanged" using {oldScale: 2.625, newScale: 0.65625}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onLoadStop" using {url: about:blank}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onPageCommitVisible" using {url: about:blank}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onZoomScaleChanged" using {oldScale: 2.625, newScale: 0.65625}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "shouldOverrideUrlLoading" using {request: {headers: null, method: GET, networkServiceType: null, allowsConstrainedNetworkAccess: null, cachePolicy: null, body: null, url: https://developer.mozilla.org/en-US/docs/Web/API/Location/replace, allowsExpensiveNetworkAccess: null, attribution: null, assumesHTTP3Capable: null, httpShouldUsePipelining: null, allowsCellularAccess: null, httpShouldHandleCookies: null, timeoutInterval: null, mainDocumentURL: null}, sourceFrame: null, isRedirect: false, targetFrame: null, hasGesture: false, shouldPerformDownload: null, isForMainFrame: true, navigationType: null}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onProgressChanged" using {progress: 10}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onZoomScaleChanged" using {oldScale: 0.65625, newScale: 1.1042962074279785}
[AndroidInAppWebViewController] (android) WebView ID 1 calling "onZoomScaleChanged" using {oldScale: 0.65625, newScale: 1.1042962074279785}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 10}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onLoadStart" using {url: https://developer.mozilla.org/en-US/docs/Web/API/Location/replace}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onUpdateVisitedHistory" using {isReload: false, url: https://developer.mozilla.org/en-US/docs/Web/API/Location/replace}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onTitleChanged" using {title: Location: replace() method - Web APIs | MDN}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 70}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onPageCommitVisible" using {url: https://developer.mozilla.org/en-US/docs/Web/API/Location/replace}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onZoomScaleChanged" using {oldScale: 1.1042962074279785, newScale: 2.625}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 70}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 80}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onUpdateVisitedHistory" using {isReload: false, url: https://developer.mozilla.org/en-US/docs/Web/API/Location/replace}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onLoadStop" using {url: https://developer.mozilla.org/en-US/docs/Web/API/Location/replace}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 0, message: (Glean.core.metrics.String) navigator.user_agent: Value length 171 exceeds maximum of 100.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onReceivedTouchIconUrl" using {precomposed: false, url: https://developer.mozilla.org/apple-touch-icon.6803c6f0.png}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
D/EGL_emulation(10830): app_time_stats: avg=177.12ms min=5.51ms max=709.84ms count=7
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onLoadStop" using {url: https://developer.mozilla.org/en-US/docs/Web/API/Location/replace}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 0, message: (Glean.core.metrics.String) navigator.user_agent: Value length 171 exceeds maximum of 100.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 1, message: (Glean.core.Upload.PingUploadManager) Ping 67c4985a-b795-4795-9885-bd31ec728650 successfully sent 200.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 1, message: (Glean.core.Upload.PingUploadManager) Ping bbcfbeda-0451-4ed0-b104-c13b8b55044d successfully sent 200.}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 1, message: (Glean.core.Upload.PingUploadManager) Ping 1f98501e-db88-48a4-8d25-a7d927c0b39a successfully sent 200.}
D/CompatibilityChangeReporter(10830): Compat change id reported: 289878283; UID 10191; state: ENABLED
D/EGL_emulation(10830): app_time_stats: avg=1008.71ms min=2.70ms max=23970.52ms count=24
sadly version 6 does not solve the problem after the code has been adjusted:
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
void main() {
runApp(const MyApp());
}
const String pageWithAutoRedirect = '''
<!DOCTYPE html>
<html>
<head>
<title>Back button demo</title>
<script>
function myFunction() {
setTimeout(function() { location.replace("https://developer.mozilla.org/en-US/docs/Web/API/Location/replace"); }, 1000);
}
</script>
</head>
<body onload=myFunction()>
<h1>This will auto-navigate in 1 second!</h1>
<p>If the webview functions correctly, this page should be removed from history</p>
</body>
</html>
''';
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const Column(
children: [
Expanded(child: WebViewExample()),
Divider(),
Expanded(child: WebViewExample(implementOnNavigationRequest: true)),
],
),
);
}
}
class WebViewExample extends StatefulWidget {
const WebViewExample({super.key, this.implementOnNavigationRequest = false});
final bool implementOnNavigationRequest;
@override
State<WebViewExample> createState() => _WebViewExampleState();
}
class _WebViewExampleState extends State<WebViewExample> {
late final InAppWebViewController _controller;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green,
appBar: AppBar(
title:
Text(widget.implementOnNavigationRequest ? 'Incorrect' : 'Correct'),
),
body: InAppWebView(
key: UniqueKey(),
initialData: InAppWebViewInitialData(data: pageWithAutoRedirect),
initialSettings: InAppWebViewSettings(
javaScriptEnabled: true,
useShouldOverrideUrlLoading: widget.implementOnNavigationRequest,
),
onWebViewCreated: (controller) {
_controller = controller;
},
// Version 6 appears to require providing an implementation of shouldOverrideUrlLoading if useShouldOverrideUrlLoading is true. Otherwise it behaves as if navigation were canceled.
shouldOverrideUrlLoading: (controller, navAction) async {
return NavigationActionPolicy.ALLOW;
},
),
floatingActionButton: backButton(),
);
}
Widget backButton() {
return FloatingActionButton(
onPressed: () async {
if (!await _controller.canGoBack()) {
debugPrint('Cannot navigate back!');
} else {
_controller.goBack();
}
},
child: const Icon(Icons.navigate_before),
);
}
}
I'm facing the same issue. Even after trying the latest version, 6.0.0, the problem persists.
For instance, when navigating from the home screen (index.php) to a specific page (myp_main.php) that requires a session, if the session is not present on that specific page, it redirects to the login page (login.php) using location.href. However, upon pressing the back button or using history.back() on the login page, it goes back to the specific page again, leading to a situation where there's no session, and it redirects back to the login page.
On other browsers like Chrome and Safari, this website behaves correctly, going back to the previous page (index.php) when the back button is pressed. I tested the iOS app with version 6.0.0, and the back button worked correctly.
@HanCharles what is the code you are using?
@pichillilorenzo index.php
<a href="/myp_main.php">my page</a>
myp_main.php
<?
if(!$_SESSION) {
$returnUrl = $_SERVER['SCRIPT_NAME'] . ($_SERVER['QUERY_STRING'] ? '?' . $_SERVER['QUERY_STRING'] : '');
?>
<script>
top.location.href="/login.php?returnUrl='.urlencode($returnUrl)";
</script>
<?
}
// ... myp_main
?>
login.php
<?
// ... login input
?>
import 'dart:async';
import 'dart:io';
import 'package:cornermarket_flutter/constant/constants.dart';
import 'package:cornermarket_flutter/controller/notification_controller.dart';
import 'package:cornermarket_flutter/widget/loader.dart';
import 'package:facebook_app_events/facebook_app_events.dart';
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:url_launcher/url_launcher.dart';
class WebViewController extends StatefulWidget {
final String userAgent;
final FirebaseAnalytics analytics;
final FacebookAppEvents facebookAppEvents;
const WebViewController({Key? key, required this.userAgent, required this.analytics, required this.facebookAppEvents}) : super(key: key);
@override
State<WebViewController> createState() => _WebViewControllerState();
}
class _WebViewControllerState extends State<WebViewController> {
static const platform = MethodChannel('intent');
final GlobalKey webViewKey = GlobalKey();
InAppWebViewController? webViewController;
late InAppWebViewGroupOptions options;
late NotificationController notificationController;
late PullToRefreshController pullToRefreshController;
// String url = "";
double progress = 0;
String deviceToken = "";
// final urlController = TextEditingController();
WebHistory? webHistory;
@override
void initState() {
super.initState();
print('initState ------------------------');
print('widget.userAgent : ${widget.userAgent}');
InAppWebViewGroupOptions _options = InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
javaScriptEnabled: true,
javaScriptCanOpenWindowsAutomatically: true,
useShouldOverrideUrlLoading: true,
mediaPlaybackRequiresUserGesture: false,
userAgent: widget.userAgent,
cacheEnabled: true,
),
android: AndroidInAppWebViewOptions(
useHybridComposition: true,
hardwareAcceleration: true,
),
ios: IOSInAppWebViewOptions(
allowsInlineMediaPlayback: true,
)
);
options = _options;
pullToRefreshController = PullToRefreshController(
options: PullToRefreshOptions(
color: Colors.blue,
),
onRefresh: () async {
if (Platform.isAndroid) {
webViewController?.reload();
} else if (Platform.isIOS) {
webViewController?.loadUrl(
urlRequest: URLRequest(url: await webViewController?.getUrl()));
}
},
);
initialization();
}
void initialization() async {
print('ready in 3...');
await Future.delayed(const Duration(seconds: 1));
print('ready in 2...');
await Future.delayed(const Duration(seconds: 1));
print('ready in 1...');
await Future.delayed(const Duration(seconds: 1));
print('go!');
FlutterNativeSplash.remove();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: WillPopScope(
onWillPop: () => _goBack(context),
child :Stack(
children: [
InAppWebView(
key: webViewKey,
initialUrlRequest: URLRequest(
url: "/index.php",
headers: {}
),
initialOptions: options,
pullToRefreshController: pullToRefreshController,
onWebViewCreated: (controller) {
webViewController = controller;
},
onLoadStart: (controller, url) async {
setState(() {
// this.url = url.toString();
// urlController.text = this.url;
});
},
androidOnPermissionRequest: (controller, origin, resources) async {
return PermissionRequestResponse(
resources: resources,
action: PermissionRequestResponseAction.GRANT);
},
shouldOverrideUrlLoading: (controller, navigationAction) async {
var uri = navigationAction.request.url!;
if (![ "http", "https", "file", "chrome", "data", "javascript", "about"].contains(uri.scheme)) {
uri.forceToStringRawValue = true;
if(Platform.isAndroid) {
if (await canLaunchUrl(uri)) {
await launchUrl(uri,);
return NavigationActionPolicy.CANCEL;
} else {
try {
var result = await platform.invokeMethod('getAppUrl', {'url': uri.rawValue});
if(result != null) {
await controller.loadUrl(urlRequest: URLRequest(url: WebUri(result)));
}
} catch(e) {
print('url fail $e');
}
return NavigationActionPolicy.CANCEL;
}
} else if(Platform.isIOS){
if (await canLaunchUrl(uri)) {
await launchUrl(uri,);
return NavigationActionPolicy.CANCEL;
}
}
} else {
if (Platform.isAndroid || navigationAction.iosWKNavigationType == IOSWKNavigationType.LINK_ACTIVATED) {
controller.loadUrl(urlRequest: URLRequest(url: uri));
return NavigationActionPolicy.CANCEL;
}
}
return NavigationActionPolicy.ALLOW;
},
onLoadStop: (controller, url) async {
pullToRefreshController.endRefreshing();
setState(() {
// this.url = url.toString();
// urlController.text = this.url;
});
},
onLoadError: (controller, url, code, message) {
pullToRefreshController.endRefreshing();
},
onProgressChanged: (controller, progress) {
if (progress == 100) {
pullToRefreshController.endRefreshing();
}
setState(() {
this.progress = progress / 100;
// urlController.text = this.url;
});
},
onUpdateVisitedHistory: (controller, url, androidIsReload) async {
print("Visited: $url");
webHistory = await controller.getCopyBackForwardList();
// if(webHistory!.list!.last.url!.path.contains("login.php")) {
// controller.goBack();
// }
setState(() {
// this.url = url.toString();
// urlController.text = this.url;
});
},
onConsoleMessage: (controller, consoleMessage) {
print('consoleMessage : $consoleMessage');
},
),
progress < 1.0 ? Loader() : Container(),
],
),
),
),
);
}
Future<bool> _goBack(BuildContext context) async{
if(await webViewController!.canGoBack()){
webViewController!.goBack();
return Future.value(false);
}else{
return Future.value(true);
}
}
@override
void dispose() {
// TODO: implement dispose
webViewController = null;
super.dispose();
}
}
The code above is a condensed form provided for explanation purposes. Was there an issue in the code?
There doesn't seem to be a problem on Flutter iOS or the web, but it arises only on Android. In an attempt to address this issue, I tried implementing the following code within the shouldOverrideUrlLoading function, but it didn't resolve the problem :(
if (Platform.isAndroid) {
print("WebHistory : ${webHistory}");
print("webHistory!.list!.length : ${webHistory!.list!.length}");
print("webHistory!.currentIndex : ${webHistory!.currentIndex}");
if (webHistory!.list!.length > 2 &&
// webHistory!.list!.length-1 > webHistory!.currentIndex) &&
webHistory!.list!.length-2 == webHistory!.currentIndex! &&
webHistory!.list!.last.url.toString().contains("login.php")) {
controller.loadUrl(urlRequest: URLRequest(url: webHistory!.list!.elementAt(webHistory!.list!.length - 3).url));
return NavigationActionPolicy.CANCEL;
}
}
is there any solutions? 😭
not yet
@pichillilorenzo
Hi, i soluted this issue by add a setting regexToCancelOverrideUrlLoading
for exp: regexToCancelOverrideUrlLoading: '^(?!http://|https://).*'
, it worked for me!!
@lyb5834 thanks for the PR, I was already planning to add something like that. It should be almost ok. I will review the code changes and merge it as soon as possible!
any updates?
Environment
Device information:
Description
When navigating to a webpage which contains a redirect using
window.location.replace(...)
the page remains in the history/back stack ifuseShouldOverrideUrlLoading
istrue
. This causes serious problems when the page is simply a loading/routing page. In this situation, the user presses the back button, and is immediately returned forward again. In some cases double or triple clicking the back button quickly can overcome this, but from the user's perspective the back button is non-functional.Functionally this is the same buggy behavior as: https://github.com/flutter/flutter/issues/137737 And this is technically a duplicate of: https://github.com/pichillilorenzo/flutter_inappwebview/issues/1732 with additional information and reproducible code.
Expected behavior: https://developer.mozilla.org/en-US/docs/Web/API/Location/replace states that webpage which calls this should be removed from the history stack and not accessible by back navigation. Choosing to inspect a url and decide to overload or not should not affect basic browser functionality unless it is overridden.
Current behavior: If
useShouldOverrideUrlLoading
istrue
, regardless of the implementation ofshouldOverrideUrlLoading
even if it vacuously returnsNavigationActionPolicy.ALLOW
, the back stack will erroneously contain the webpage which calledwindow.location.replace(nextpage)
.Steps to reproduce
Images
https://github.com/pichillilorenzo/flutter_inappwebview/assets/149631770/90f6fea5-9da8-48df-ab8c-88f7daa6139a
Stacktrace/Logcat