flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
165.22k stars 27.26k forks source link

[Proposal] Disable the browser navigation stack in the Flutter web app #108114

Open kodejack opened 2 years ago

kodejack commented 2 years ago

Disable the browser navigation stack in the Flutter web app to allow a Flutter app to act more like a Single Page Application (SPA) and manage its navigation internally

Use case

We have an application for iOS, Android and Web. The app works perfectly on mobile platforms, but the browser back button causes mayhem for the web application. The application has many dynamically generated pages, which makes the browser history very difficult to manage. If the user uses the navigation in the flutter app, everything is good. If the user starts using the browser's back and forward navigation, The app will regularly fall over due to this being wrong. We have no requirement for deep linking and would use the app as if it was SPA and let Flutter manage the navigation separately from the browser. i.e. if you hit back on the browser, you leave the page.

We have looked at various ways to manage or override this behaviour, including route guards, but have failed to find a reasonable solution. We also tried using w iFrame, which caused cross-site scripting issues with our authentication.

We have written several web apps in Flutter, and all of them have experienced this issue in some way.

Proposal

What we like is the ability to switch a flutter web app from a website with full navigation controlled by the browser and Flutter to a web app that handles its own navigation. Similar to it being contained in an iframe.

If there is already a way to do this, I would love to know. Alas, I have not found a way to this as yet.

maheshj01 commented 2 years ago

Hi @kodejack, Thanks for filing the issue. This looks like a valid feature request. Perhaps you can try using WillPopScope and always return false. Labeling this issue for further insights from the team.

maheshj01 commented 2 years ago

cc: @mdebbar

kodejack commented 2 years ago

We looked at WillPop, but it doesn't seem to work correctly on web and didn't always suit our scenario.

yjbanov commented 2 years ago

Have you tried using a custom UrlStrategy?

https://api.flutter.dev/flutter/package-flutter_web_plugins_url_strategy/UrlStrategy-class.html

kodejack commented 2 years ago

I dont think this will fix the issue as we have a number of pages that are dynamic. All call "FormStack". These are generated on they fly depedning the form branching logic. I will have a closer look at this as it might some of the issue but not the dynamic pages.

blaneyneil commented 2 years ago

I'm running into this same problem with a soon-to-be-released web build of our app. To make matters worse, our web version uses a separate Navigator key so we can target into different views. Which makes a parent "back" inherently confusing.

It would be really helpful to have an option to disable the browser nav stack on the MaterialApp() level.

VIP-Dev-Invisible commented 2 years ago

I am also having the same issue . There should be an option in MaterialApp() where user can disable Nav stack. Is there any ETA to solve this issue ?

mdebbar commented 2 years ago

In order to disable all browser history, you could do something like this:

import 'package:flutter_web_plugins/url_strategy.dart';

void main() {
  // Before running your app:
  setUrlStrategy(null);

  runApp(...);
}

Of course, you'll need to add the flutter_web_plugins package to your pubspec.yaml:

dependencies:
  flutter_web_plugins:
    sdk: flutter

@kodejack is this what you're looking for?

kodejack commented 2 years ago

@mdebbar this seems to be working as desired, The browser nav stack and hence the buttons are being ignored. This looks like we could be onto a winner. I'll try a few other things and let you know if this is pretty solid.

kodejack commented 2 years ago

After trying a few things this seems to fix the web browser nav stack but it makes it incompatible with the iOS and Android apps. So to work around it I created a file for web and mobile.

mobile_url_strategy.dart

void configureUrlStrategy() {
  // No strategy for mobile
}

web_url_strategy.dart

import 'package:flutter_web_plugins/flutter_web_plugins.dart';

void configureUrlStrategy() {
  setUrlStrategy(null);
}

Then optional includes

import 'package:my_app/mobile_url_strategy.dart'
    if (dart.library.html) 'package:my_app/web_url_strategy.dart';

void main() {
  configureUrlStrategy();
}

Is this a recommended approach and should it be part of the framework?

mdebbar commented 2 years ago

@kodejack that's the right way to do it, yes. But we already do this for you in: https://github.com/flutter/flutter/blob/fc444aedab1290b510ca85fc4a906e185cd3eaa6/packages/flutter_web_plugins/lib/url_strategy.dart#L7-L8

If you wanna take advantage of that, and keep your code simple, you can import url_strategy.dart directly instead of importing all of flutter_web_plugins.dart.

import 'package:flutter_web_plugins/url_strategy.dart';

This should work in mobile and web. On mobile, it's implemented as a no-op, similar to what you did in your code sample.

janknips commented 1 year ago

If anyone else comes across this, and needs to have the URL update, but no back button or history.

Just call setUrlStrategy() with the following:

class NoHistoryUrlStrategy extends PathUrlStrategy {
  @override
  void pushState(Object? state, String title, String url) =>
      replaceState(state, title, url);
}
Tameflame commented 1 year ago

@janknips how did you figure this out? This is exactly what I was looking for! Thanks!

PriyaranjanEuphotic commented 1 year ago

@janknips how did you figure this out? This is exactly what I was looking for! Thanks!

If anyone else comes across this, and needs to have the URL update, but no back button or history.

Just call setUrlStrategy() with the following:

class NoHistoryUrlStrategy extends PathUrlStrategy {
  @override
  void pushState(Object? state, String title, String url) =>
      replaceState(state, title, url);
}

its working, but one problem, when I am pressing back button its completely exiting from app, is there any way to display a confirmation dialog

bobosette commented 1 year ago

In order to disable all browser history, you could do something like this:

import 'package:flutter_web_plugins/url_strategy.dart';

void main() {
  // Before running your app:
  setUrlStrategy(null);

  runApp(...);
}

Of course, you'll need to add the flutter_web_plugins package to your pubspec.yaml:

dependencies:
  flutter_web_plugins:
    sdk: flutter

@kodejack is this what you're looking for?

you saved my life!!!

millarboy commented 9 months ago

Yo, I am definitely under qualified to be commenting here, However I did have some issues with hiding the safari bar in my flutter mobile web app so in case I understood the issue i fixed it by wrapping everything on the page with a non scrolling container.... it made my system nav go.... sorry if this is completely out of context

adamcastleman commented 4 months ago

Insert this script into you index.html file in your web folder to disable mobile browser gesture swiping

` `