[英]Handling deep links notifications in flutter
I'm trying to wrap my head around external data handling in Flutter application.我正在努力解决 Flutter 应用程序中的外部数据处理问题。 The idea is following:思路如下:
https://host/join?id=<id>
邀请来自表单https://host/join?id=<id>
的深层链接acceptExternalInvitation()
:路由器通过打开邀请页面并调用acceptExternalInvitation()
来处理这种深度链接:class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
final notificationBloc = NotificationCubit();
final dataSharingBloc = IncomingDataBloc(notificationBloc);
return MultiBlocProvider(
...
child: MaterialApp(
...
home: SafeArea(child: _MyHomePage()),
onGenerateRoute: (settings) => _getRoute(dataSharingBloc, settings)));
}
Route? _getRoute(IncomingDataBloc incomingDataBloc, RouteSettings settings) {
if (settings.name == null) {
return null;
}
final route = settings.name!;
if (route.startsWith('/join')) {
final match = RegExp(r"/join\?id=(.+)$").firstMatch(route);
if (match != null) {
incomingDataBloc.acceptExternalInvitation(match.group(1)!);
return MaterialPageRoute(
builder: (Navcontext) => InvitesPage(), settings: settings);
}
}
return null;
}
}
class _MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) =>
BlocConsumer<NotificationCubit, NotificationState>(
listener: (context, state) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(state.message)));
},
builder: (context, state) => BlocBuilder<IncomingDataBloc, IncomingDataState>(
builder: (context, state) => Scaffold(
appBar: AppBar(),
drawer: _getDrawer(context),
body: OverviewPage())));
...
}
IncomingDataBloc
is responsible for handling all events that come from outside of the application such as deep links here. IncomingDataBloc
负责处理来自应用程序外部的所有事件,例如此处的深度链接。 IncomingDataBloc.acceptExternalInvitation
is defined as following: IncomingDataBloc.acceptExternalInvitation
定义如下: void acceptExternalInvitation(String invitationEncodedString) {
final invitation = MemberInvitation.fromBase64(invitationEncodedString);
emit(NewAcceptedInviteState(invitation));
_notificationCubit.notify("Got invitation from ${invitation.from}");
}
Main point here is emitting the NewAcceptedInviteState(invitation)
, which should be handled by the invitations page.这里的重点是发出NewAcceptedInviteState(invitation)
,它应该由邀请页面处理。
class InvitesPage extends StatelessWidget {
final MemberInvitation? invitation;
InvitesPage({this.invitation});
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: Text("Invitations")),
body: BlocListener<IncomingDataBloc, IncomingDataState>(
listener: (context, state) async {
Logger.root.finest("--------Accepting invitation");
await _acceptInvite(context, (state as NewAcceptedInviteState).invitation);
Navigator.pop(context);
},
listenWhen: (previous, current) => current is NewAcceptedInviteState,
child: ...
)
);
The problem I have is with the listener in InvitesPage
.我遇到的问题是InvitesPage
中的监听器。 When I send a link to the application using adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://host/join?id=MY_ID" my.app
the handling of the link is performed without problems, the notification from p.3 is shown and the InvitesPage
is opened.当我使用adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://host/join?id=MY_ID" my.app
发送指向应用程序的链接时链接处理没有问题,显示来自 p.3 的通知并打开InvitesPage
。 However the code of listener is not executed.然而监听器的代码并没有被执行。
If however I set a break point in listener code it's hit and code is executed.但是,如果我在侦听器代码中设置一个断点,它就会被命中并执行代码。 How can I fix that?我该如何解决? Can it be caused by using BlocListener<IncomingDataBloc, IncomingDataState>
in home page, which is higher in widgets hierarchy?是否可能是由于在主页中使用BlocListener<IncomingDataBloc, IncomingDataState>
导致的,它在小部件层次结构中更高?
And may be more generic question - is such approach of handling external event right one?并且可能是更通用的问题 - 这种处理外部事件的方法是否正确?
Ok, I've figured that out.好吧,我已经想通了。
Indeed the problem was consuming states in two places.事实上,问题是在两个地方消耗状态。 So instead of calling a Bloc method in route, which in my opinion wasn't conceptually correct I just open an invites pages with an invitation provided and let all invitation related logic remain contained in invites page, bloc and state:因此,我没有在路由中调用 Bloc 方法,我认为这在概念上是不正确的,我只是打开一个提供邀请的邀请页面,并让所有与邀请相关的逻辑保留在邀请页面、bloc 和 state 中:
Route? _getRoute(RouteSettings settings) {
if (settings.name == null) {
return null;
}
final route = settings.name!;
if (route == '/settings') {
return MaterialPageRoute(builder: (context) => SettingsPage());
}
if (route.startsWith('/join')) {
final match = RegExp(r"/join\?invitation=(.+)$").firstMatch(route);
if (match != null) {
return MaterialPageRoute(
builder: (Navcontext) =>
InvitesPage(invitation: MemberInvitation.fromBase64(match.group(1)!)),
settings: settings);
}
}
return null;
}
}
only thing I don't really like is handling invitation upon InvitesPage
creation.我唯一不喜欢的是在创建InvitesPage
时处理邀请。 For that I had to make it a stateful widget and implement initState()
:为此,我必须使它成为一个有状态的小部件并实现initState()
:
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (invitation != null) {
context.read<InviteListCubit>().acceptExternalInvitation(invitation!);
}
});
}
But I think it makes sense as state of the page can change with new invitation coming from outside.但我认为这是有道理的,因为页面的 state 可以随着来自外部的新邀请而改变。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.