How can we handle deep links in flutter with Get X for go to Custom pages of the application ?
By default, by adding the desired address to the Android Manifest file:
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" android:host="flutterbooksample.com" />
<data android:scheme="https" android:host="flutterbooksample.com"/>
</intent-filter>
when the application opens, the main page of application will be displayed to us.
I am looking to implement this I can direct the user to any page of the application that is needed. A practical example is to pay on the web page and return to the application. When we return, we should show the user a message about the status of the payment, not direct the user to the first page of the application.
Complete solution example using https://pub.dev/packages/app_links.
Let's assume we have three screens, Home, ProductList, and Product which we use to display many different products.
Main method:
void main() async{
var firstScreen = await DeepLinkParser().getFirstScreen();
runApp( MainApp(firstScreen: firstScreen));
}
We got firstScreen
widget using DeepLinkParser
.
class DeepLinkParser {
DeepLinkParser._();
static final _instance = DeepLinkParser._();
factory DeepLinkParser() => _instance;
final _appLinks = AppLinks();
Future<Uri?> getInitialLink() async {
return _appLinks.getInitialAppLink();
}
Future <Widget> getFirstScreen() async {
Uri? uri = await getInitialLink();
if (uri == null){
return const Home();
}
String fragment = uri.fragment;
if (fragment.contains('/product-list')){
return const ProductList();
}
if (fragment.contains('/product/')){
var lastIndexOfSlash = fragment.lastIndexOf('/');
if (lastIndexOfSlash == fragment.length - 1){
return const ProductList();
}
String id = fragment.substring(lastIndexOfSlash + 1);
return ProductScreen.withId(id: id);
}
return const Home();
}
}
MainApp:
class MainApp extends StatelessWidget {
final Widget firstScreen;
const MainApp({super.key, required this.firstScreen});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
home: firstScreen,
getPages: Routes.routes,
navigatorObservers: [NavigationHistoryObserver()],
debugShowCheckedModeBanner: false,
);
}
}
ProductScreen
has two constructors:
class ProductScreen extends StatelessWidget {
String? id;
ProductScreen.withId({super.key, required this.id});
ProductScreen({super.key});
@override
Widget build(BuildContext context) {
id ??= Get.parameters['id'];
Product product = MockProductService().getById(id!)!;
return Scaffold(
appBar: AppBar(
title: Text('Product ${product.id}'),
centerTitle: true,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//skipped Image and Text widgets with product info
],
),
),
);
}
}
When we call ProductScreen
from ProductList
we use the default constructor (without id parameter) and we pass id
like below:
onTap: () {
Get.toNamed('${Routes.PRODUCT}/${products[index].id}');
}
For that to work, we need to create named routes:
class Routes {
static const HOME = '/';
static const PRODUCT_LIST = '/product-list';
static const PRODUCT = '/product';
static final routes = [
GetPage(
name: HOME,
page: () => const Home(),
transition: Transition.circularReveal,
),
GetPage(
name: PRODUCT_LIST,
page: () => const ProductList(),
transition: Transition.circularReveal,
),
GetPage(
name: '$PRODUCT/:id',
page: () => ProductScreen(),
transition: Transition.circularReveal,
preventDuplicates: false,
),
];
}
It works with one problem: when the app is launched from the deep link
https://example.com/#/product/123
Get pushes three routes into the stack:
/
/product
/product/123
despite I expect only the last one. It creates some problems with back button behavior, which I currently resolve with a lot of if
statements.
UPDATE.
I recently upgraded my projects to GetX 5 (release candidate at the time). GetX 5 always uses Navigator 2.0 internally and supports deep links out of the box. Breaking changes are relatively few. So, I advice anybody interested in the web platform upgrade as well.