Research
Security News
Malicious npm Package Targets Solana Developers and Hijacks Funds
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
github.com/Dennis-Krasnov/Flutter-Deep-Link-Navigation
Provides an elegant abstraction for complete deep linking navigation in Flutter.
This package only provides deep linking for internal navigation. Any external platform-level deep linking solution can optionally be used in conjuction with this package.
The target audience of the documentation is experienced Flutter developers.
There's nothing wrong with not using deep links for internal navigation.
Partially implementing deep links would either have limited benefits or be extremely complicated (not to mention confusing).
Hence why if you decide to use deep links, it makes sense to exclusively use deep links.
If you try to implement complete deep linking yourself here's some of the issues you'll run into:
Artist
--> Song
(artist) => ArtistPage(artist)
and later (song) => SongPage(artist, song)
TL;DR
I separated the navigation system from Diet Driven (shameless plug, please hire me) into its own package and published it.
This package provides a solution for all the aforementioned difficulties.
This example demonstrates:
This example demonstrates:
Authenticated
mixin ensures user is authenticated (LibraryDL, FavoritesDL, UserDL)
DeepLink
is base unit of routes, a deep link is mapped to a Widget
by a Dispatcher
.
Deep links may be reused in different levels of the navigation hierarchy.
A route is the full location of a page, represented by List<DeepLink>
.
path
is the string representation of the route aka route.join("/")
.
Path
class LibraryDL extends DeepLink {
LibraryDL() : super("library");
}
Value
Deep links can also store data, value dispatchers are strongly typed.
class SongDL extends ValueDeepLink<Song> {
SongDL(Song song) : super("song", song);
}
class SongDL extends ValueDeepLink<Song> {
// Override toString
SongDL(Song song) : super("song", song, toString: (song) => song.id);
}
Mixin for sake of inheritence
This could also be achieved by implementing an abstract class.
See use in Child builder section.
mixin FullScreen on DeepLink {}
class LoginDL extends DeepLink with FullScreen {
LoginDL() : super("login");
}
Mixin with logic
mixin Authenticated on DeepLink {
@override
void onDispatch(BuildContext context) {
// Get state from context or global/static variable
final isAuthenticated = Provider.of<AuthenticationService>(context, listen: false).authenticated;
// Throw custom exception
if (!isAuthenticated) {
throw Unauthenticated();
}
}
}
// ...
navigation: (context) => Dispatcher()
// Unauthenticated login page
..exception<Unauthenticated>((exception, route) => [LoginDL()])
..path<LoginDL>((route) => LoginPage()),
Use DeepLinkMaterialApp
instead of using Flutter's MaterialApp
.
This replaces native navigation options with their deep link counterparts.
At most one deep link of a type can exist on a dispatcher.
Deep link material app
DeepLinkMaterialApp(
navigation: (context) => Dispatcher() // see next section ...
defaultRoute: [LibraryDL()], // if ommited, the splash screen is shown until explicit navigation
splashScreen: SplashPage(),
childBuilder: // see child builder section ...
// Non-navigation related fields are still available
themeMode: ThemeMode.light,
// ...
);
Path dispatcher
..path<LoginDL>((route) => LoginPage()),
Value dispatcher
..value<Song, SongDL>((song, route) => SongPage(song: song)),
Sub navigation
..path<LibraryDL>(
(route) => LibraryPage(),
subNavigation: Dispatcher() // ...
),
..value<Song, SongDL>(
(song, route) => SongPage(song: song),
subNavigation: (song) => Dispatcher() // song may be used from this point onward
),
Exception mapping
Exceptions that are thrown while running through the navigation hierarchy are mapped to routes.
..exception<RouteNotFound>
MUST be defined on the base-level dispatcher.
If multiple mappings of the same type are found thoughout the hierarchy, the deep-most mapping is used.
..exception<RouteNotFound>((exception, route) => [ErrorDL<RouteNotFound>(exception)])
The widget specified in childBuilder
is rebuilt when the route in deepLinkNavigator
changes.
/// [DeepLink]s associated with the bottom navigation.
final bottomNavigationDeepLinks = [LibraryDL(), FavoritesDL(), UserDL()];
/// Current index of bottom navigation based on [currentRoute].
int currentIndex(List<DeepLink> currentRoute) {
final index = bottomNavigationDeepLinks.indexOf(currentRoute?.first);
return index != -1 ? index : 0;
}
/// ...
childBuilder: (BuildContext context, DeepLinkNavigator deepLinkNavigator, Widget child) => Scaffold(
body: child,
// Don't show bottom navigation while [currentRoute] is null, or any deep list is [FullScreen]
bottomNavigationBar: deepLinkNavigator.currentRoute?.any((dl) => dl is FullScreen) ?? true ? null : BottomNavigationBar(
currentIndex: currentIndex(deepLinkNavigator.currentRoute),
onTap: (int index) => deepLinkNavigator.navigateTo([bottomNavigationDeepLinks[index]]),
items: [
BottomNavigationBarItem(title: Text("Library"), icon: Icon(Icons.queue_music)),
BottomNavigationBarItem(title: Text("Favorites"), icon: Icon(Icons.favorite)),
BottomNavigationBarItem(title: Text("User"), icon: Icon(Icons.person)),
],
),
)
DeepLinkNavigator
mirrors Navigator
's interface as much as possible (including push and pop futures).
All methods internally orchestrate a native flutter navigator.
Push a deep link
await DeepLinkNavigator.of(context).push(ArtistDL(...));
Pop a value
DeepLinkNavigator.of(context).pop(...);
// or
Navigator.of(context).pop(...);
Navigate to specific route
DeepLinkNavigator.of(context).navigateTo([
LibraryDL(),
ArtistDL(...),
]);
Return to default route (if any)
DeepLinkNavigator.of(context).replaceWithDefault();
TODO: Throw exception to be caught by mapper
// TODO DeepLinkNavigator.of(context).throw(Exception(...));
TODO: Access deep link navigator from anywhere
// TODO DeepLinkNavigator()...
TODO: Page transitions
// await DeepLinkNavigator.of(context).push(
// ArtistDL(...),
// transition: ...,
// duration: ...,
// );
// Possibly:
// await DeepLinkNavigator.of(context).fadeIn(...);
// TODO: serialize List<DeepLink>
RouteNotFound
if the route doesn't existRouteNotFound
maps to a route that doesn't exist[ ] Custom/predefined page transitions
[ ] Access deep link navigator from anywhere using static method and factory pattern
[ ] Assert RouteNotFound
dispatcher exists by running through navigation tree
[ ] Unit test deep link navigator logic
[ ] Cupertino and Widget apps
[ ] Explicit exception throwing
[ ] Platform deep links example + documentation
[ ] Route changed callback for analytics, etc
FAQs
Unknown package
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.