Flutter web URL redirection routes

Viewed 195

I have app working on Android and iOS and also working good in localhost when I run web app with advanced_url plugin.

http://localhost:95555/web/home?id=xyz

Above URL when I run from Android studio works correctly. But when I build and upload on real server it shows 404 error. It works http://example.com/web/ but it does not work with url redirect.

void main() async {
  setPathUrlStrategy();
  WidgetsFlutterBinding.ensureInitialized();
  await Hive.initFlutter();
  Hive.registerAdapter(OrderAdapter());
  await Hive.openBox(DBProvider.TBL);
  if (!kIsWeb) {
    await Firebase.initializeApp();
  } 

  runApp(ChangeNotifierProvider.value(
    value: AppModel(),
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // if (Provider.of<AppModel>(context).isLoading!) {
    //   return Container();
    // } else {
      return MaterialApp(
        title: Constant.appName,
        debugShowCheckedModeBanner: false,
        theme: Provider.of<AppModel>(context).darkTheme!
            ? buildDarkTheme().copyWith()
            : buildLightTheme().copyWith(),
        supportedLocales: const [
          Locale('en'),
        ],
        locale: const Locale('en'),
        localizationsDelegates: const [
          CountryLocalizations.delegate,
        ],
        builder: (context, _) => AdvancedNavigator(
          tag: 'Main',
          paths: routes,
         // pages: pages,
         //  onGeneratePage: (RouteSettings rs){
         //    print(rs.name);
         //    print(rs.arguments);
         //  },
         //  onGeneratePath: (configuration){
         //    print(configuration.location);
         //  },
        ),
      );
   // }
  }
}


class App extends StatelessWidget {
  const App({ Key? key }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: (context, _) => AdvancedNavigator(
        tag: 'Main',
        paths: {
          '/': (_) => [
            MaterialPage(key: ValueKey('home'), child: ViewHome()),
          ],
          '/items': (_) => [
            MaterialPage(key: ValueKey('home'), child: ViewHome()),
          ],
          'items/{itemId}/...': (args) => [
            MaterialPage(key: ValueKey('home'), child: ViewHome()),
            MaterialPage(key: ValueKey('item${args['itemId']}'), child: AppItem(int.parse(args['itemId']))),
          ],
        },
      ),
    );
  }
}

class ViewHome extends StatelessWidget {
  const ViewHome({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: ListView.builder(
        itemCount: 25,
        itemBuilder: (context, index) => ListTile(
          leading: Icon(Icons.shopping_bag_sharp),
          title: Text('Item $index'),
          subtitle: Text('This is a sample description for item $index'),
          onTap: () {
            AdvancedNavigator.openNamed(context, '/items/$index');
          },
        ),
      ),
    );
  }
}

class AppItem extends StatelessWidget {
  const AppItem(this.itemNumber, {Key? key}) : super(key: key);

  final int itemNumber;

  @override
  Widget build(BuildContext context) {
    return Provider<int>.value(
      value: itemNumber,
      child: AdvancedNavigator(
        tag: 'AppItem',
        parent: AdvancedNavigator.of(context),
        paths: {
          '/': (_) => [
            MaterialPage(child: ViewItem()),
          ],
          '/edit': (_) => [
            MaterialPage(child: ViewItem()),
            MaterialPage(child: ViewEditItem()),
          ],
        },
      ),
    );
  }
}

class ViewItem extends StatelessWidget {
  const ViewItem({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    int itemNumber = Provider.of<int>(context);

    return Scaffold(
      appBar: AppBar(
        leading: BackButton(
          onPressed: () => AdvancedNavigator.of(context, rootNavigator: true).openNamed('/'),
        ),
        title: Text('Item Details'),
      ),
      body: Center(
        child: Text(
          'Viewing item #$itemNumber',
          style: Theme.of(context).textTheme.headline4,
        ),
      ),
      floatingActionButton: FloatingActionButton.extended(
        icon: Icon(Icons.edit),
        label: Text('Edit Item'),
        tooltip: 'Edit',
        onPressed: () => AdvancedNavigator.openNamed(context, '/edit'),
      ),
    );
  }
}

class ViewEditItem extends StatelessWidget {
  const ViewEditItem({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    int itemNumber = Provider.of<int>(context);

    return Scaffold(
      appBar: AppBar(
        leading: BackButton(
          onPressed: () => AdvancedNavigator.openNamed(context, '/'),
        ),
        title: Text('Edit Item'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Container(
              padding: const EdgeInsets.all(20),
              decoration: BoxDecoration(
                color: Colors.grey[200],
                shape: BoxShape.circle,
              ),
              child: Icon(Icons.edit, size: 75.0, color: Colors.white),
            ),
            SizedBox(height: 20.0),
            Text(
              'Editing item #$itemNumber',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
    );
  }
}
1 Answers

I suspect you map your domain wrong, usually it should be mapped to the web-folder and then the web-root would be the content of this web-folder.
The site home has to be found then on http://localhost:95555/home?id=xyz. Therefore the folder web shouldn't be seen in the URLs at all.

Certainly you can use a subdirectory of the url-path too, but then you've to take more care about the paths and URLs.

Concerning your code:

The first thing you can try is to set the base url in the index.html to /web/ without changing anything else.

If that's not working then you've to adjust a few things. In the code below I prepended the path '/web' everywhere where it seemed required like shown here:

enter image description here

void main() async {
  setPathUrlStrategy();
  WidgetsFlutterBinding.ensureInitialized();
  await Hive.initFlutter();
  Hive.registerAdapter(OrderAdapter());
  await Hive.openBox(DBProvider.TBL);
  if (!kIsWeb) {
    await Firebase.initializeApp();
  } 

  runApp(ChangeNotifierProvider.value(
    value: AppModel(),
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // if (Provider.of<AppModel>(context).isLoading!) {
    //   return Container();
    // } else {
      return MaterialApp(
        title: Constant.appName,
        debugShowCheckedModeBanner: false,
        theme: Provider.of<AppModel>(context).darkTheme!
            ? buildDarkTheme().copyWith()
            : buildLightTheme().copyWith(),
        supportedLocales: const [
          Locale('en'),
        ],
        locale: const Locale('en'),
        localizationsDelegates: const [
          CountryLocalizations.delegate,
        ],
        builder: (context, _) => AdvancedNavigator(
          tag: 'Main',
          paths: routes,
         // pages: pages,
         //  onGeneratePage: (RouteSettings rs){
         //    print(rs.name);
         //    print(rs.arguments);
         //  },
         //  onGeneratePath: (configuration){
         //    print(configuration.location);
         //  },
        ),
      );
   // }
  }
}


class App extends StatelessWidget {
  const App({ Key? key }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: (context, _) => AdvancedNavigator(
        tag: 'Main',
        paths: {
          '/web/': (_) => [
            MaterialPage(key: ValueKey('home'), child: ViewHome()),
          ],
          '/web/items': (_) => [
            MaterialPage(key: ValueKey('home'), child: ViewHome()),
          ],
          '/web/items/{itemId}/...': (args) => [
            MaterialPage(key: ValueKey('home'), child: ViewHome()),
            MaterialPage(key: ValueKey('item${args['itemId']}'), child: AppItem(int.parse(args['itemId']))),
          ],
        },
      ),
    );
  }
}

class ViewHome extends StatelessWidget {
  const ViewHome({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: ListView.builder(
        itemCount: 25,
        itemBuilder: (context, index) => ListTile(
          leading: Icon(Icons.shopping_bag_sharp),
          title: Text('Item $index'),
          subtitle: Text('This is a sample description for item $index'),
          onTap: () {
            AdvancedNavigator.openNamed(context, '/web/items/$index');
          },
        ),
      ),
    );
  }
}

class AppItem extends StatelessWidget {
  const AppItem(this.itemNumber, {Key? key}) : super(key: key);

  final int itemNumber;

  @override
  Widget build(BuildContext context) {
    return Provider<int>.value(
      value: itemNumber,
      child: AdvancedNavigator(
        tag: 'AppItem',
        parent: AdvancedNavigator.of(context),
        paths: {
          '/web/': (_) => [
            MaterialPage(child: ViewItem()),
          ],
          '/web/edit': (_) => [
            MaterialPage(child: ViewItem()),
            MaterialPage(child: ViewEditItem()),
          ],
        },
      ),
    );
  }
}

class ViewItem extends StatelessWidget {
  const ViewItem({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    int itemNumber = Provider.of<int>(context);

    return Scaffold(
      appBar: AppBar(
        leading: BackButton(
          onPressed: () => AdvancedNavigator.of(context, rootNavigator: true).openNamed('/web/'),
        ),
        title: Text('Item Details'),
      ),
      body: Center(
        child: Text(
          'Viewing item #$itemNumber',
          style: Theme.of(context).textTheme.headline4,
        ),
      ),
      floatingActionButton: FloatingActionButton.extended(
        icon: Icon(Icons.edit),
        label: Text('Edit Item'),
        tooltip: 'Edit',
        onPressed: () => AdvancedNavigator.openNamed(context, '/web/edit'),
      ),
    );
  }
}

class ViewEditItem extends StatelessWidget {
  const ViewEditItem({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    int itemNumber = Provider.of<int>(context);

    return Scaffold(
      appBar: AppBar(
        leading: BackButton(
          onPressed: () => AdvancedNavigator.openNamed(context, '/web/'),
        ),
        title: Text('Edit Item'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Container(
              padding: const EdgeInsets.all(20),
              decoration: BoxDecoration(
                color: Colors.grey[200],
                shape: BoxShape.circle,
              ),
              child: Icon(Icons.edit, size: 75.0, color: Colors.white),
            ),
            SizedBox(height: 20.0),
            Text(
              'Editing item #$itemNumber',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
    );
  }
}
flutter
flutter-web

I'm not sure if all paths are configured correctly like this, but you get the idea.

Related