简体   繁体   English

在 flutter 中处理深度链接通知

[英]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:思路如下:

  1. An invitation comes as deep link of form https://host/join?id=<id>邀请来自表单https://host/join?id=<id>的深层链接
  2. Router handles such deep link by opening invites page and calling 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())));
   ...
}

  1. 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) ,它应该由邀请页面处理。

  1. Invitations page in general contains list of invitations and allows to accept or reject them.邀请页面通常包含邀请列表并允许接受或拒绝它们。 Invitations coming from deep links should trigger acceptance action:来自深层链接的邀请应触发接受操作:
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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM