fluro_router_generate 1.1.2 copy "fluro_router_generate: ^1.1.2" to clipboard
fluro_router_generate: ^1.1.2 copied to clipboard

A powerful Flutter library for routing based on Fluro, featuring annotations and code generation, with animated transitions, route matching, and support for custom navigation.

中文 | English


pub package License

fluro_router_generate #

Fluro-based routing for Flutter with annotations and code generation.
Register routes automatically via @RouterAnnotation, with path params, query params, and RouteSettings.arguments. Supports animated transitions and custom navigation.

Repositories


1. Dependencies #

dependencies:
  fluro_router_generate: ^1.1.2  # or path: ../ for local

dev_dependencies:
  build_runner: ^2.10.5

2. Create route entry #

In lib/xxxx.dart:

import 'package:fluro_router_generate/fluro_router_generate.dart';
export 'router_config.g.dart';

@EntranceAnnotation()
class RouteConfig extends FluroConfig {
  RouteConfig._();
  static final RouteConfig instance = RouteConfig._();
}

3. Annotate your pages #

import 'package:flutter/material.dart';
import 'package:fluro_router_generate/fluro_router_generate.dart';

@RouterAnnotation(path: '/home/:id', description: 'Home', defaultParams: {'id': '-'})
class HomePage extends StatelessWidget {
  const HomePage({super.key, required this.id});
  final String id;

  @override
  Widget build(BuildContext context) {
    return Scaffold(appBar: AppBar(title: Text('$id')), body: const SizedBox());
  }
}

4. Configure build.yaml (required) #

Your app project must have a root build.yaml, and only the file with @EntranceAnnotation may trigger the builder:

# Only the route entry file triggers generation, e.g. lib/router/router_config.g.dart
targets:
  $default:
    builders:
      fluro_router_generate|router_library:
        generate_for:
          include:
            # Path must match your route entry file
            # - lib/router/router_config.dart
  • If you don’t set this or omit the entry from include: build_runner will run the builder on all .dart files. For any file without @EntranceAnnotation, the builder returns empty output and fails with a message to configure build.yaml. The whole build will fail.
  • So you must list only the route entry file (the one with @EntranceAnnotation) in include.
  • If the entry file has no @EntranceAnnotation or build.yaml is wrong, build_runner will also fail.

5. Generate route table #

dart run build_runner build --delete-conflicting-outputs

This generates router_config.g.dart with generatedHandlers and initAllHandlers().


6. Initialize in main and use #

import 'package:fluro_router_generate/fluro_router_generate.dart';
import 'package:example/router/router_config.dart';

void main() {
  RouteConfig.instance.initAllHandlers();
  runApp(const MyApp());
}

// MaterialApp
onGenerateRoute: FluroConfig.router.generator,

// Navigate
FluroConfig.router.navigateTo(context, '/home/1');

7. Route guards (optional) #

Guards run before each Navigator.push, so you can allow, redirect, or cancel navigation. This is different from NavigatorObserver, which only runs after push/pop.

import 'package:fluro_router_generate/fluro_router.dart';

// e.g. redirect to login when visiting /admin without auth
FluroConfig.addGuard((ctx) async {
  if (ctx.path.startsWith('/admin') && !isLoggedIn()) {
    return GuardResult.redirect('/login');
  }
  return GuardResult.allow;
});

// Remove or clear when needed
FluroConfig.removeGuard(myGuard);
FluroConfig.clearGuards();
API Description
addGuard(guard) Append a guard (runs in order).
insertGuard(index, guard) Insert at index.
removeGuard(guard) Remove first matching guard by reference.
clearGuards() Remove all guards.

Guard returns: GuardResult.allow, GuardResult.redirect(newPath), GuardResult.cancel. Redirect is limited to 5 hops to avoid loops.


Annotation reference #

Field Description
path Route path, e.g. /home/:id, /search?keyword=
description Optional, comment in generated list
defaultParams Optional, default values, e.g. {'id': '-', 'page': 1}
constructorParams Optional: pathParams / queryParams / routeSettingsArguments / none — how params are passed to the constructor
module Optional, module name for grouping/splitting; with build.yaml split_modules can emit a separate .g.dart

See example/ for more.


Examples #

1. Parameter types #

Scenario path example constructorParams Notes
No params /home none No arguments
Single path param /detail/:id pathParams Matches /detail/99, param id
Multiple path params /user/:userId/post/:postId pathParams Matches /user/1/post/2, params userId, postId
Query params /search?keyword=&page=1 queryParams Params from query string
routeSettings with defaultParams /pass-args routeSettingsArguments + defaultParams: {'title': 'Default', 'count': 0} Via RouteSettings.arguments, fallback to defaults
routeSettings without defaultParams /pass-args-no-defaults routeSettingsArguments (no defaultParams) Param names from constructor, for ad-hoc args

No params:

@RouterAnnotation(path: '/home', constructorParams: HandlerConstructorParams.none)
class HomePage extends StatelessWidget {
  const HomePage({super.key});
  // ...
}

Single path param:

@RouterAnnotation(
  path: '/detail/:id',
  defaultParams: {'id': '0'},
  constructorParams: HandlerConstructorParams.pathParams,
)
class DetailPage extends StatelessWidget {
  const DetailPage({super.key, required this.id});
  final String id;
  // ...
}

Multiple path params:

@RouterAnnotation(
  path: '/user/:userId/post/:postId', 
  defaultParams: {'userId': '0', 'postId': '0'},
  constructorParams: HandlerConstructorParams.pathParams,
)
class PostPage extends StatelessWidget {
  const PostPage({super.key, required this.userId, required this.postId});
  final String userId;
  final String postId;
  // ...
}

Query params:

@RouterAnnotation(
  path: '/search?keyword=&page=1',
  defaultParams: {'keyword': '', 'page': '1'},
  constructorParams: HandlerConstructorParams.queryParams,
)
class SearchPage extends StatelessWidget {
  const SearchPage({super.key, required this.keyword, required this.page});
  final String keyword;
  final String page;
  // ...
}

routeSettings.arguments (with defaultParams):

@RouterAnnotation(
  path: '/pass-args',
  defaultParams: {'title': 'Default title', 'count': 0},
  constructorParams: HandlerConstructorParams.routeSettingsArguments,
)
class PassArgsPage extends StatelessWidget {
  const PassArgsPage({super.key, required this.title, required this.count});
  final String title;
  final int count;
  // ...
}

2. Navigation and passing arguments #

// No params
FluroConfig.push('/home', context: context);

// Path params
FluroConfig.push('/detail/99', context: context);
FluroConfig.push('/user/1/post/2', context: context);

// Query params
FluroConfig.push('/search?keyword=test&page=1', context: context);

// routeSettings.arguments
FluroConfig.push(
  '/pass-args',
  context: context,
  routeSettings: RouteSettings(
    name: '/pass-args',
    arguments: {'title': 'My title', 'count': 42},
  ),
);

3. Modules and split_modules #

Add module to annotations; same module name is grouped (or written to a separate file):

@RouterAnnotation(
  path: '/home',
  module: 'main',
  constructorParams: HandlerConstructorParams.none,
)
class HomePage extends StatelessWidget { ... }

@RouterAnnotation(
  path: '/payment/:orderId',
  module: 'payment',
  defaultParams: {'orderId': ''},
  constructorParams: HandlerConstructorParams.pathParams,
)
class PaymentPage extends StatelessWidget { ... }

To emit a separate file e.g. router_config_payment.g.dart for the payment module, add split_modules in your project root build.yaml:

targets:
  $default:
    builders:
      fluro_router_generate|router_library:
        generate_for:
          include:
            - lib/router/router_config.dart
        options:
          split_modules:
            - payment
            - admin

Modules not in split_modules are inlined into the main generated file. See example/ for a full sample.


FAQ #

defaultParams vs constructor: which decides parameter names? #

  • Parameter set and defaults: defaultParams wins. Only when defaultParams is omitted (or {}) are names inferred from the constructor.
  • Types: After the set is fixed, types always come from the constructor.
  • So defaultParams has priority for which params and defaults; the constructor is used when defaultParams is missing and always for types.

Constructor type is A, defaultParams value looks like type B. Which type is used? #

  • Type follows the constructor type A. The literal in defaultParams (B) only affects the default value, not how the value is parsed.
  • If A is an object type, generated code uses argsMap?['key'] as A, not B for int/double etc.
  • Conclusion: Constructor type A wins; defaultParams’ type B does not override A.

Troubleshooting #

Issue What to check
build_runner fails with a message about build.yaml Ensure the only file in generate_for.include is your route entry file (the one with @EntranceAnnotation). Do not include every .dart file.
Route not found at runtime Call RouteConfig.instance.initAllHandlers() before runApp(), and use onGenerateRoute: FluroConfig.router.generator in MaterialApp.
Wrong or missing params on the page Match constructorParams to how you pass data: pathParams for /path/:id, queryParams for ?key=, routeSettingsArguments for RouteSettings.arguments. Use defaultParams when you need defaults.
Generated file is empty or outdated Run dart run build_runner build --delete-conflicting-outputs again; ensure the entry file is the one listed in build.yaml and has @EntranceAnnotation().
1
likes
0
points
37
downloads

Documentation

Documentation

Publisher

unverified uploader

Weekly Downloads

A powerful Flutter library for routing based on Fluro, featuring annotations and code generation, with animated transitions, route matching, and support for custom navigation.

Repository (GitHub)
View/report issues

Topics

#flutter #routing #code-generation #fluro #annotations

License

unknown (license)

Dependencies

analyzer, build, build_runner, flutter, flutter_lints, glob, source_gen

More

Packages that depend on fluro_router_generate